Compare commits

...

209 Commits
v0.1.1 ... main

Author SHA1 Message Date
Jonny zhang 9cbec06edb
chore: Modify get_image_distribution job parameters (#579)
Signed-off-by: yingxuan <zhanglujia.zlj@digital-engine.com>
Co-authored-by: yingxuan <zhanglujia.zlj@digital-engine.com>
2025-08-29 16:29:18 +08:00
Jonny zhang 8d8130d3bb
chore: Modify the persistent cache task API definition (#577)
Signed-off-by: yingxuan <zhanglujia.zlj@digital-engine.com>
Co-authored-by: yingxuan <zhanglujia.zlj@digital-engine.com>
2025-08-28 16:01:43 +08:00
dependabot[bot] 5022ca0e4e
chore(deps): bump actions/checkout from 4 to 5 (#568)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-12 14:22:35 +08:00
Jonny zhang 8b27240b0c
chore: remove typography in select menu (#567)
Signed-off-by: 瑛玄 <yingxuan@B-74K9LGQN-2326.local>
Co-authored-by: 瑛玄 <yingxuan@B-74K9LGQN-2326.local>
2025-07-30 16:26:06 +08:00
Zhaoxinxin 49a3f9a6f2
feat: modify form validation and E2E (#560)
* feat: modify form validation and E2E

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: modify form validation and E2E

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: modify form validation and E2E

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: modify form validation and E2E

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: modify form validation and E2E

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-22 13:53:15 +08:00
jjzhang332 ff94450c6e
chore: first commit test (#562)
chore: yx first commit test

Signed-off-by: 瑛玄 <zhanglujia.zlj@digital-engine.com>
Co-authored-by: 瑛玄 <zhanglujia.zlj@digital-engine.com>
2025-07-22 09:57:14 +08:00
Zhaoxinxin 849cdb77b7
chore: optimize E2E testing and images (#559)
* chore: optimize E2E testing and images

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: optimize E2E testing and images

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: optimize E2E testing and images

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-16 15:50:27 +08:00
dependabot[bot] ffeb700ac8
chore(deps): bump filesize from 10.1.6 to 11.0.1 (#558)
Bumps [filesize](https://github.com/avoidwork/filesize.js) from 10.1.6 to 11.0.1.
- [Changelog](https://github.com/avoidwork/filesize.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/avoidwork/filesize.js/compare/10.1.6...11.0.1)

---
updated-dependencies:
- dependency-name: filesize
  dependency-version: 11.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-15 14:26:22 +08:00
Zhaoxinxin a527be2547
fix: create preheat parameter ips (#557)
* fix: create preheat parameter ips

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* fix: create preheat parameter ips

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-10 14:39:24 +08:00
Zhaoxinxin 353a8cd778
chore: perfect create preheat and perfect preheat E2E (#556) 2025-07-09 11:52:05 +08:00
Zhaoxinxin d1cc68c3f9
feat: create preheat remove Content For Calculating Task ID (#555)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-08 23:06:40 +08:00
Zhaoxinxin 365b638f64
flx: gc history ttl display error (#554)
* GC history TTL display error

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* GC history TTL display error

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-03 20:18:02 +08:00
Zhaoxinxin 9e08366b9b
chore: change search by url search box (#553)
* chore: change  search by url search box

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change  search by url search box

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-03 17:34:50 +08:00
Zhaoxinxin 36678fbf10
feat: resource task add Image Manifest Url (#551)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-02 23:38:47 +08:00
Zhaoxinxin 5d943d8aea
feat: The minimum value of a numeric input box is 0 (#550)
* feat: The minimum value of number type input is 0

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: The minimum value of number type input is 0

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-07-01 13:49:18 +08:00
Zhaoxinxin 70e822652b
feat: change package (#548) 2025-06-27 14:49:30 +08:00
Zhaoxinxin 499ef7f82d
Feat add gc (#545)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-06-25 22:26:05 +08:00
dependabot[bot] 192567e803
chore(deps): bump @types/node from 22.15.32 to 24.0.3 (#543)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.32 to 24.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 24.0.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-18 14:21:30 +08:00
Zhaoxinxin 4e1e795811
Chore change preheat (#540)
* chore: change preheat

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change preheat

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change preheat

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change preheat

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change preheat

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-06-13 14:48:00 +08:00
dependabot[bot] a6802f8c78
chore(deps-dev): bump eslint-plugin-cypress from 4.3.0 to 5.1.0 (#537)
Bumps [eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress) from 4.3.0 to 5.1.0.
- [Release notes](https://github.com/cypress-io/eslint-plugin-cypress/releases)
- [Commits](https://github.com/cypress-io/eslint-plugin-cypress/compare/v4.3.0...v5.1.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-cypress
  dependency-version: 5.1.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 10:49:46 +08:00
Zhaoxinxin aa4b9ca70f
feat: create preheat scope add percentage and count (#535) 2025-06-05 19:59:24 +08:00
Zhaoxinxin b3769f312f
feat: search task add content for calculating task id (#536)
* feat: search task add content for calculating task id

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: search task add content for calculating task id

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: search task add content for calculating task id

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: search task add content for calculating task id

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: search task add content for calculating task id

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-06-05 17:15:45 +08:00
Zhaoxinxin 9d852018d6
Feat: preheat add batch preheat (#531)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-30 12:01:01 +08:00
Zhaoxinxin b71c1ee7a4
feat: preheat add search (#530)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-27 20:13:14 +08:00
Zhaoxinxin 93e2bff377
feat: add audit page (#527)
* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add audit page

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-26 21:06:13 +08:00
Gaius f160a3ace9
chore(README.md): add maintainer google groups for communication channels and remove discussion group (#526)
* chore(README.md): add maintainer google groups for communication channels and remove discussion group

Signed-off-by: Gaius <gaius.qi@gmail.com>

* Update README.md

---------

Signed-off-by: Gaius <gaius.qi@gmail.com>
2025-05-23 10:36:41 +08:00
Zhaoxinxin d49f8ad080
feat: click on the cluster name to view the cluster details (#525)
* feat: click on the cluster name to view the cluster details

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: click on the cluster name to view the cluster details

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: click on the cluster name to view the cluster details

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-19 17:52:54 +08:00
Zhaoxinxin 1c704b8b98
chore: change preheat error log width (#524)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-19 10:07:32 +08:00
Zhaoxinxin 6a05d43483
feat: add resource persistent cache task (#522)
* chore: resource Persistent Cache Tasks

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change seed peer e2e test

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add resource persistent cache task

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-16 16:27:23 +08:00
Zhaoxinxin e95c7e70e6
feat: Create preheating and add search cluster function (#521)
* feat: Create preheating and add search cluster function

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Create preheating and add search cluster function

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-14 15:24:09 +08:00
dependabot[bot] d5a6609c72
chore(deps): bump web-vitals from 4.2.4 to 5.0.0 (#519)
Bumps [web-vitals](https://github.com/GoogleChrome/web-vitals) from 4.2.4 to 5.0.0.
- [Changelog](https://github.com/GoogleChrome/web-vitals/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GoogleChrome/web-vitals/compare/v4.2.4...v5.0.0)

---
updated-dependencies:
- dependency-name: web-vitals
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-13 21:10:01 +08:00
Zhaoxinxin 6f4393c60a
fix: Cluster scopes title style is not effective (#516)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-05-09 10:20:46 +08:00
Zhaoxinxin 1b301b6999
fix: change CI error (#515)
fix: change ci error

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-30 00:46:33 +08:00
dependabot[bot] fc31a5f649
chore(deps): bump react-router-dom from 6.30.0 to 7.5.3 (#513)
Bumps [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) from 6.30.0 to 7.5.3.
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.5.3/packages/react-router-dom)

---
updated-dependencies:
- dependency-name: react-router-dom
  dependency-version: 7.5.3
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-29 11:30:21 +08:00
Zhaoxinxin 25fb9a53be
feat: add search user E2E test (#514)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-29 11:01:48 +08:00
Zhaoxinxin fd4fbcba41
chore: change users (#512)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-29 09:40:39 +08:00
Zhaoxinxin 6a3f9bf315
Chore change 404 e2e test (#511)
* chore: change 404 e2e test

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change 404 e2e test

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-29 09:40:25 +08:00
Zhaoxinxin f14da7dbcd
chore: optimizing create cluster and create clusters test (#509)
* chore: optimizing create cluster and create clusters test

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: optimizing create cluster and create clusters test

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-28 14:56:15 +08:00
Zhaoxinxin 7f436a839b
chore: optimizing update cluster and update clusters test (#510)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-28 14:55:55 +08:00
Zhaoxinxin 4657ffe359
chore: optimizing clusters and clusters test (#508)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-27 20:28:27 +08:00
Zhaoxinxin 6c856920c3
chore: change seed peer e2e test (#507)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-25 09:51:58 +08:00
Zhaoxinxin 45b6a1673d
chore: change scheduler e2e test (#506)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-24 09:43:00 +08:00
Zhaoxinxin 9fa12d4e0d
chore: bump query-string version to v9.1.1 (#505)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-24 09:42:40 +08:00
Zhaoxinxin 1399d609da
chore: bump jsonwebtoken version to v9.0.9 (#504)
chore: bump jsonwebtoken version to v9.09

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-24 09:42:26 +08:00
Zhaoxinxin a29359fbf8
chore: change tokens (#503)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-22 20:29:04 +08:00
Zhaoxinxin 4c623e56b9
chore: change signup (#501)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-21 19:41:06 +08:00
Zhaoxinxin 05113777c9
chore: change signin (#500)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-21 19:40:54 +08:00
Zhaoxinxin ecb5c28df1
chore: change dark layout (#499)
* chore: change dark layout

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* chore: change dark layout

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-21 19:40:41 +08:00
Zhaoxinxin 4c967d29fc
chore: delete unused image (#498)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-21 16:55:44 +08:00
Zhaoxinxin a48eafaf68
chore: optimizing schedulers (#497)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-18 17:11:42 +08:00
Zhaoxinxin af2733fa49
chore: optimizing cluster information (#496)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-18 15:25:44 +08:00
Zhaoxinxin 57ca2c268e
chore: optimizing cluster CSS (#495)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-18 10:01:25 +08:00
Zhaoxinxin 4f695cee03
chore: bump cypress version to v14.3.0 (#494)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-18 10:01:15 +08:00
Zhaoxinxin 21e69ed180
chore: Change cluster e2e test annotation (#493)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-18 10:01:01 +08:00
Zhaoxinxin 68592d2f8e
feat: Changed to dark mode by default (#492)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-16 16:41:03 +08:00
Zhaoxinxin 6e0a60c753
fix: peer e2e error (#491)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-15 13:37:57 +08:00
dependabot[bot] 22311d8918
chore(deps): bump mui-tel-input from 8.0.1 to 9.0.0 (#489)
Bumps [mui-tel-input](https://github.com/viclafouch/mui-tel-input) from 8.0.1 to 9.0.0.
- [Release notes](https://github.com/viclafouch/mui-tel-input/releases)
- [Commits](https://github.com/viclafouch/mui-tel-input/compare/v8.0.1...v9.0.0)

---
updated-dependencies:
- dependency-name: mui-tel-input
  dependency-version: 9.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-15 12:09:51 +08:00
Gaius 0724e7d0d2
chore: optimize browserslist for production (#487)
Signed-off-by: Gaius <gaius.qi@gmail.com>
2025-04-11 16:43:04 +08:00
Zhaoxinxin f898f98337
feat: mui upgraded to v7 (#484)
* feat: mui upgraded to v7

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: mui upgraded to v7

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-02 18:47:51 +08:00
Zhaoxinxin b22d574e7a
feat: Display based on local time zone (#483)
* feat: Display based on local time zone

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Display based on local time zone

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Display based on local time zone

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-04-02 18:47:00 +08:00
Zhaoxinxin 29df7c96b2
feat: Add Piece Length configuration to preheat and clear tasks (#476)
* feat: Add Piece Length configuration to preheat and clear tasks

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Add Piece Length configuration to preheat and clear tasks

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Add Piece Length configuration to preheat and clear tasks

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Add Piece Length configuration to preheat and clear tasks

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change piece length display

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change piece length display

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change piece length display

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change piece length display

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change piece length display

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-03-26 11:38:22 +08:00
dependabot[bot] 80c5e14b1a
chore(deps): bump mui-tel-input from 6.0.1 to 8.0.1 (#475)
Bumps [mui-tel-input](https://github.com/viclafouch/mui-tel-input) from 6.0.1 to 8.0.1.
- [Release notes](https://github.com/viclafouch/mui-tel-input/releases)
- [Commits](https://github.com/viclafouch/mui-tel-input/compare/v6.0.1...v8.0.1)

---
updated-dependencies:
- dependency-name: mui-tel-input
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-25 21:01:17 +08:00
Zhaoxinxin 90cf6d206a
feat: change personal access token scopes (#477)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-03-25 21:00:56 +08:00
Zhaoxinxin 7dd9df2572
Feat add dark module (#448)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-03-24 15:27:03 +08:00
dependabot[bot] 9c96aaace4
chore(deps): bump babel-loader from 9.2.1 to 10.0.0 (#458) 2025-03-04 10:02:13 +08:00
dependabot[bot] 715adcd26c
chore(deps): bump @mui/icons-material from 5.16.14 to 6.4.3 (#443)
Bumps [@mui/icons-material](https://github.com/mui/material-ui/tree/HEAD/packages/mui-icons-material) from 5.16.14 to 6.4.3.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/v6.4.3/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v6.4.3/packages/mui-icons-material)

---
updated-dependencies:
- dependency-name: "@mui/icons-material"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-11 13:45:36 +08:00
Zhaoxinxin 7818c33dea
feat: change preheat page (#437)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2025-02-10 11:03:21 +08:00
dependabot[bot] 9698119d87
chore(deps-dev): bump eslint-config-prettier from 9.1.0 to 10.0.1 (#436)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 9.1.0 to 10.0.1.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v9.1.0...v10.0.1)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-23 20:49:39 +08:00
Zhaoxinxin 4252f20ef4
fix: page bug (#432)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-30 18:44:59 +08:00
Zhaoxinxin 57803a54c0
feat: change page UI (#431)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-30 10:50:32 +08:00
Zhaoxinxin 0870a8630b
feat: Fix page bugs (#430)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-30 10:34:22 +08:00
Zhaoxinxin dde2699bc4
feat: Fix page bugs (#428) 2024-12-27 19:03:25 +08:00
Zhaoxinxin 21db3353d1
feat: console v2.2.0 (#427)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-27 10:19:18 +08:00
Zhaoxinxin eb41763f30
feat: preheat add scope (#421)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-11 23:31:50 +08:00
dependabot[bot] bd54f92456
chore(deps): bump @types/react-dom from 18.3.3 to 19.0.1 (#418)
Bumps [@types/react-dom](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react-dom) from 18.3.3 to 19.0.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react-dom)

---
updated-dependencies:
- dependency-name: "@types/react-dom"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-10 11:03:42 +08:00
Zhaoxinxin af05f56a47
feat: change e2e ci (#416)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-06 13:48:53 +08:00
Zhaoxinxin b34c2da5ae
fix: Paging bug (#415)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-12-04 11:26:37 +08:00
dependabot[bot] 686b051305
chore(deps): bump codecov/codecov-action from 4 to 5 (#410)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 4 to 5.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v4...v5)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-03 10:29:24 +08:00
Zhaoxinxin dded1e4c11
fix: job rate limit (#409)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-11-11 13:48:18 +08:00
Zhaoxinxin 3b99678fee
feat: add cluster parameter Job Rate Limit (#407)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-11-08 17:06:14 +08:00
Zhaoxinxin 137a2333d7
feat: change menu style (#408)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-11-08 15:20:33 +08:00
Zhaoxinxin 741b3a0476
Feat add clear cache page (#405)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-11-05 11:18:30 +08:00
Zhaoxinxin 1a5d0c88b8
fix: Change delete button text (#403)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-10-23 16:47:08 +08:00
dependabot[bot] e8674a4ef9
chore(deps-dev): bump eslint-plugin-cypress from 3.6.0 to 4.0.0 (#400)
Bumps [eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress) from 3.6.0 to 4.0.0.
- [Release notes](https://github.com/cypress-io/eslint-plugin-cypress/releases)
- [Commits](https://github.com/cypress-io/eslint-plugin-cypress/compare/v3.6.0...v4.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-cypress
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-17 00:01:04 +08:00
Zhaoxinxin e868d5cb2e
fix: number of active schedulers misspell (#398)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-25 22:15:15 +08:00
Zhaoxinxin b8e77ff88b
feat: Change preheat field (#394)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-18 10:52:56 +08:00
Zhaoxinxin feda25f78c
fix: preheat page switching state to initiate multiple requests (#392)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-12 21:29:21 +08:00
Zhaoxinxin 402e683b2b
feat: add changes to scheduler features (#391)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-12 17:15:31 +08:00
Zhaoxinxin 10300ba767
feat: change edit cluster (#388)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-10 17:02:55 +08:00
dependabot[bot] c4fbb7a01d
chore(deps): bump @mui/styled-engine-sc from 5.14.12 to 6.0.1 (#386)
Bumps [@mui/styled-engine-sc](https://github.com/mui/material-ui/tree/HEAD/packages/mui-styled-engine-sc) from 5.14.12 to 6.0.1.
- [Release notes](https://github.com/mui/material-ui/releases)
- [Changelog](https://github.com/mui/material-ui/blob/master/CHANGELOG.md)
- [Commits](https://github.com/mui/material-ui/commits/v6.0.1/packages/mui-styled-engine-sc)

---
updated-dependencies:
- dependency-name: "@mui/styled-engine-sc"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-06 11:13:01 +08:00
Zhaoxinxin dec1ab4ba2
feat: Change all search templates (#384)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-09-03 11:18:51 +08:00
Zhaoxinxin 85ef84998a
Feat change cluster card layout (#382)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-08-27 17:28:01 +08:00
Zhaoxinxin 9b38889169
feat: preheat remove piece length (#381)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-08-16 17:56:28 +08:00
dependabot[bot] 800c37af87
chore(deps): bump @types/node from 20.14.14 to 22.1.0 (#380)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.14.14 to 22.1.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:44:24 +08:00
Zhaoxinxin 78690c93b3
fix: cluster card layout (#378)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-07-10 20:00:45 +08:00
Zhaoxinxin 965dda8c58
feat: Change the default of seedPeerLoadLimit to 2000 and the default of peerLoadLimit to 200 (#377)
* feat: Change the default value of seedPeerLoadLimit to 2000 and the default value of peerLoadLimit to 200

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change the default value of seedPeerLoadLimit to 2000 and the default value of peerLoadLimit to 200

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-06-14 11:03:49 +08:00
Zhaoxinxin d849d65e78
feat: Change the Cluster parameter seed Peer Load Limit to 0-50000 (#376)
* feat: Change the cluster parameter seed Peer Load Limit to 0-50000

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: Change the cluster parameter seed Peer Load Limit to 0-50000

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-06-13 20:08:56 +08:00
Zhaoxinxin c3c0e40861
preheat error log is not displayed (#375)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-06-11 11:47:16 +08:00
dependabot[bot] 5acff463e3
chore(deps): bump @testing-library/react from 15.0.7 to 16.0.0 (#374)
Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 15.0.7 to 16.0.0.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v15.0.7...v16.0.0)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-07 10:25:07 +08:00
dependabot[bot] 58a8d29b00
chore(deps): bump node-polyfill-webpack-plugin from 3.0.0 to 4.0.0 (#373)
Bumps [node-polyfill-webpack-plugin](https://github.com/Richienb/node-polyfill-webpack-plugin) from 3.0.0 to 4.0.0.
- [Release notes](https://github.com/Richienb/node-polyfill-webpack-plugin/releases)
- [Commits](https://github.com/Richienb/node-polyfill-webpack-plugin/compare/v3.0.0...v4.0.0)

---
updated-dependencies:
- dependency-name: node-polyfill-webpack-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-29 10:36:56 +08:00
Zhaoxinxin 7250903163
feat: add delete inactive schedulers and inactive seed peers (#372)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-05-22 21:16:18 +08:00
dependabot[bot] a48549223c
chore(deps): bump web-vitals from 3.5.2 to 4.0.0 (#371)
Bumps [web-vitals](https://github.com/GoogleChrome/web-vitals) from 3.5.2 to 4.0.0.
- [Changelog](https://github.com/GoogleChrome/web-vitals/blob/main/CHANGELOG.md)
- [Commits](https://github.com/GoogleChrome/web-vitals/compare/v3.5.2...v4.0.0)

---
updated-dependencies:
- dependency-name: web-vitals
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-18 13:45:10 +08:00
dependabot[bot] 2fb30700bf
chore(deps-dev): bump eslint-plugin-cypress from 2.15.2 to 3.0.0 (#369)
Bumps [eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress) from 2.15.2 to 3.0.0.
- [Release notes](https://github.com/cypress-io/eslint-plugin-cypress/releases)
- [Commits](https://github.com/cypress-io/eslint-plugin-cypress/compare/v2.15.2...v3.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-cypress
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-23 10:43:47 +08:00
Zhaoxinxin ad998efec1
feat: preheat agrs adds parameter piece length (#368)
* feat: preheat agrs adds parameter piece length

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: preheat agrs adds parameter piece length

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-04-18 15:08:51 +08:00
dependabot[bot] e1420902ea
chore(deps): bump @testing-library/react from 14.3.1 to 15.0.2 (#366)
Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 14.3.1 to 15.0.2.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v14.3.1...v15.0.2)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-18 14:42:08 +08:00
Zhaoxinxin d7c47f1af1
feat: change page loading function (#367)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-04-17 20:27:38 +08:00
dependabot[bot] d00869e71b
chore(deps): bump actionsDesk/lfs-warning from 3.2 to 3.3 (#365)
Bumps [actionsDesk/lfs-warning](https://github.com/actionsdesk/lfs-warning) from 3.2 to 3.3.
- [Release notes](https://github.com/actionsdesk/lfs-warning/releases)
- [Commits](https://github.com/actionsdesk/lfs-warning/compare/v3.2...v3.3)

---
updated-dependencies:
- dependency-name: actionsDesk/lfs-warning
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-12 11:26:55 +08:00
dependabot[bot] fe701dd48b
chore(deps-dev): bump eslint from 8.57.0 to 9.0.0 (#364)
Bumps [eslint](https://github.com/eslint/eslint) from 8.57.0 to 9.0.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.57.0...v9.0.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-12 11:26:35 +08:00
Zhaoxinxin 200b74a7ff
feat: clusters page shows multiple idc CIDR and hostname (#363)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-04-08 10:55:22 +08:00
dependabot[bot] 7f73bda322
chore(deps-dev): bump @commitlint/cli from 18.6.1 to 19.0.3 (#358)
Bumps [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) from 18.6.1 to 19.0.3.
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v19.0.3/@commitlint/cli)

---
updated-dependencies:
- dependency-name: "@commitlint/cli"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-08 17:09:05 +08:00
dependabot[bot] d36771a5e2
chore(deps-dev): bump @commitlint/config-conventional from 18.6.2 to 19.0.3 (#359)
chore(deps-dev): bump @commitlint/config-conventional

Bumps [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) from 18.6.2 to 19.0.3.
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v19.0.3/@commitlint/config-conventional)

---
updated-dependencies:
- dependency-name: "@commitlint/config-conventional"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-08 13:20:43 +08:00
Zhaoxinxin cd6e8d5fe2
fix: edit cluster page problem (#360)
* fix: edit cluster page problem

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* fix: edit cluster page problem

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-03-08 13:20:23 +08:00
dependabot[bot] 7e7d709107
chore(deps): bump query-string from 8.2.0 to 9.0.0 (#357)
Bumps [query-string](https://github.com/sindresorhus/query-string) from 8.2.0 to 9.0.0.
- [Release notes](https://github.com/sindresorhus/query-string/releases)
- [Commits](https://github.com/sindresorhus/query-string/compare/v8.2.0...v9.0.0)

---
updated-dependencies:
- dependency-name: query-string
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 13:51:35 +08:00
Zhaoxinxin 8bee0cf4a2
feat: cluster scope adds hostnames (#356)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-02-21 21:54:32 +08:00
dependabot[bot] ac604324be
chore(deps): bump codecov/codecov-action from 3 to 4 (#355)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-08 11:32:01 +08:00
Zhaoxinxin 5db4e48b71
feat: change pagination (#353)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-02-05 10:34:29 +08:00
dependabot[bot] 01dbb96fe4
chore(deps-dev): bump husky from 8.0.3 to 9.0.7 (#352)
Bumps [husky](https://github.com/typicode/husky) from 8.0.3 to 9.0.7.
- [Release notes](https://github.com/typicode/husky/releases)
- [Commits](https://github.com/typicode/husky/compare/v8.0.3...v9.0.7)

---
updated-dependencies:
- dependency-name: husky
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-30 15:52:21 +08:00
Zhaoxinxin b21bf03e10
feat: Modify the preheat parameter to filteredQueryParams (#351)
feat: Modify preheat parameters

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-01-25 20:05:23 +08:00
dependabot[bot] e72aab0d49
chore(deps): bump actions/cache from 3 to 4 (#349)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-23 13:25:35 +08:00
Zhaoxinxin 44a0e6543a
fix: An error occurs when the show preheat page headers are empty (#348)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2024-01-17 14:41:07 +08:00
Zhaoxinxin bdb7632e28
feat: modify directory structure (#346)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-22 15:58:07 +08:00
Zhaoxinxin da66144ca4
feat: add menu e2e test (#345)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-21 22:04:53 +08:00
dependabot[bot] 8d2ad9a4b4
chore(deps): bump github/codeql-action from 2 to 3 (#343)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-19 17:40:05 +08:00
Zhaoxinxin 4149d948d6
feat: add peers page e2e test (#344)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-19 17:39:40 +08:00
Zhaoxinxin 20a08818ae
feat: add new preheat page e2e test (#342)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-18 17:10:04 +08:00
Zhaoxinxin 9fb9f2c815
feat: add preheat page e2e test (#341)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-15 17:17:58 +08:00
Zhaoxinxin 1c15b6cd20
feat: add preheats page e2e test (#340)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-15 13:25:34 +08:00
Zhaoxinxin 0f4db05321
feat: add users page e2e test (#338)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-13 15:35:15 +08:00
dependabot[bot] 99681b829a
chore(deps): bump node-polyfill-webpack-plugin from 2.0.1 to 3.0.0 (#335)
Bumps [node-polyfill-webpack-plugin](https://github.com/Richienb/node-polyfill-webpack-plugin) from 2.0.1 to 3.0.0.
- [Release notes](https://github.com/Richienb/node-polyfill-webpack-plugin/releases)
- [Commits](https://github.com/Richienb/node-polyfill-webpack-plugin/compare/v2.0.1...v3.0.0)

---
updated-dependencies:
- dependency-name: node-polyfill-webpack-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-12 16:27:47 +08:00
Zhaoxinxin 75d5ed99b7
feat: remove concurrent_piece_count in cluster (#336)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-12 15:58:48 +08:00
Zhaoxinxin 4ad75125e8
feat: add badge (#334)
* feat: add badge

Signed-off-by: zhaoxinxin <1186037180@qq.com>

* feat: add badge

Signed-off-by: zhaoxinxin <1186037180@qq.com>

---------

Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-08 18:35:13 +08:00
Zhaoxinxin 303164f378
feat: add profile page e2e test (#333)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-08 17:15:53 +08:00
Zhaoxinxin bbdfe74809
feat: add edit token page e2e test (#331)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-12-06 16:44:31 +08:00
Zhaoxinxin 1699523c97
feat: add new token page e2e test (#330) 2023-12-06 11:58:02 +08:00
Zhaoxinxin 4d95cfb800
feat: add tokens page e2e test (#329) 2023-12-05 18:10:48 +08:00
Zhaoxinxin 36f588feeb
feat: add edit cluster page e2e test (#326) 2023-12-04 18:46:48 +08:00
Zhaoxinxin e3d68fa03d
feat: add seed peer page e2e test (#327) 2023-12-04 18:46:04 +08:00
Zhaoxinxin 79b761e61d
feat: add show cluster page e2e test (#324)
* feat: add show cluster page e2e test

* feat: add show cluster page e2e test

* feat: add show cluster page e2e test

* feat: add show cluster page e2e test
2023-12-04 14:41:14 +08:00
Zhaoxinxin 8bef0498ca
feat: add scheduler page e2e test (#325) 2023-12-04 14:15:38 +08:00
Zhaoxinxin 4ccfc9a03f
feat: add create cluster e2e test (#323) 2023-11-30 16:13:14 +08:00
Zhaoxinxin 28144ff820
feat: add signup and 404 e2e test (#322) 2023-11-22 18:23:45 +08:00
Zhaoxinxin 480b46bd0c
feat: add clusters e2e test (#321) 2023-11-22 12:29:47 +08:00
Zhaoxinxin 9dac701c8a
feat: cypress text (#317)
Signed-off-by: Gaius <gaius.qi@gmail.com>
Co-authored-by: Gaius <gaius.qi@gmail.com>
2023-11-08 23:35:06 +08:00
Zhaoxinxin cbfd04915a
fix: If there is no cluster console will panic will (#319) 2023-11-03 11:58:06 +08:00
Zhaoxinxin f93ae9add0
fix: Job uses server's pagination (#315) 2023-10-31 16:42:02 +08:00
Zhaoxinxin 9d74dd2e60
fix: multiple input box (#314) 2023-10-31 16:40:20 +08:00
dependabot[bot] 09eaa8c957
chore(deps): bump actions/setup-node from 3 to 4 (#307)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-27 10:37:20 +08:00
dependabot[bot] 157bcf3148
chore(deps-dev): bump @commitlint/cli from 17.8.1 to 18.2.0 (#311)
Bumps [@commitlint/cli](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/cli) from 17.8.1 to 18.2.0.
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/cli/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v18.2.0/@commitlint/cli)

---
updated-dependencies:
- dependency-name: "@commitlint/cli"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-27 10:37:00 +08:00
dependabot[bot] b59171dfd3
chore(deps-dev): bump @commitlint/config-conventional from 17.8.1 to 18.0.0 (#309)
chore(deps-dev): bump @commitlint/config-conventional

Bumps [@commitlint/config-conventional](https://github.com/conventional-changelog/commitlint/tree/HEAD/@commitlint/config-conventional) from 17.8.1 to 18.0.0.
- [Release notes](https://github.com/conventional-changelog/commitlint/releases)
- [Changelog](https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/CHANGELOG.md)
- [Commits](https://github.com/conventional-changelog/commitlint/commits/v18.0.0/@commitlint/config-conventional)

---
updated-dependencies:
- dependency-name: "@commitlint/config-conventional"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-26 23:23:45 +08:00
Zhaoxinxin c934135ff2
fix: guest permissions (#306) 2023-10-20 15:29:24 +08:00
Zhaoxinxin 5315218065
fix: build error (#305) 2023-10-20 12:28:48 +08:00
Zhaoxinxin efb41c1e0a
fix: change cluster page pagination (#304) 2023-10-20 12:03:38 +08:00
Zhaoxinxin 49933f5ba2
fix: change users page pagination (#303)
fix: Change users page pagination
2023-10-20 10:36:54 +08:00
Zhaoxinxin fc41f218d9
fix: change personal access tokens page sorting and pagination (#302)
fix: change tokens table
2023-10-20 10:32:47 +08:00
Zhaoxinxin f7de602dd8
fix: fix schedule and seed peer table (#301) 2023-10-19 18:36:00 +08:00
Gaius 7adb99e601
feat: rename folder Insight to insight (#300)
Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-10-18 12:12:16 +08:00
dependabot[bot] f6aab5a3bd
chore(deps-dev): bump lint-staged from 14.0.1 to 15.0.1 (#297)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 14.0.1 to 15.0.1.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/master/CHANGELOG.md)
- [Commits](https://github.com/okonet/lint-staged/compare/v14.0.1...v15.0.1)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 13:53:54 +08:00
Zhaoxinxin ddd6fe5dee
feat: add peer data visualization (#298) 2023-10-17 12:36:54 +08:00
dependabot[bot] 719d16cee6
chore(deps): bump @testing-library/user-event from 13.5.0 to 14.5.1 (#295)
Bumps [@testing-library/user-event](https://github.com/testing-library/user-event) from 13.5.0 to 14.5.1.
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/user-event/compare/v13.5.0...v14.5.1)

---
updated-dependencies:
- dependency-name: "@testing-library/user-event"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-22 10:30:40 +08:00
Zhaoxinxin 056c14b373
feat: rewrite 404 page (#294) 2023-09-18 20:20:50 +08:00
Zhaoxinxin 4c4a51bd13
fix: change form ui (#292) 2023-09-15 16:33:18 +08:00
Zhaoxinxin d050a563c5
feat: Add preheat newPreheat and showPreheat page (#291) 2023-09-15 16:03:25 +08:00
Zhaoxinxin 35dedfd357
feat: Optimize validate message (#290)
* feat: Optimize validate message

* feat: Optimize validate message
2023-09-11 15:26:15 +08:00
Zhaoxinxin 5e1a13d300
Add multi idc and change the scopes ui of the show cluster page (#289) 2023-09-11 13:42:14 +08:00
Zhaoxinxin b2cdcad177
feat: Add scopes prompt in personal access token (#285) 2023-09-11 11:41:45 +08:00
Zhaoxinxin 3a2f173049
fix: Fix update role error (#284) 2023-09-11 11:33:21 +08:00
Zhaoxinxin 2bc2a4713f
fix: Change error message (#286)
fix: error message
2023-09-11 10:27:35 +08:00
zhaoxinxin b8fa44fcb7
feat: Add cluster checkbox in scopes to personal access token (#282) 2023-09-08 18:24:18 +08:00
zhaoxinxin 600094ad97
fix: SignIn and SignUp Name verification (#281) 2023-09-08 18:23:38 +08:00
dependabot[bot] 614eedcce1
chore(deps): bump actions/checkout from 3 to 4 (#274)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 10:45:56 +08:00
dependabot[bot] fd740daf89
chore(deps-dev): bump typescript from 4.9.5 to 5.2.2 (#271)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.9.5 to 5.2.2.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.9.5...v5.2.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-31 17:14:00 +08:00
zhaoxinxin 7bff359ebe
feat: add copy scheduler cluster ID and copy seed peer cluster ID (#272) 2023-08-31 17:13:21 +08:00
dependabot[bot] 8cbaaeaa80
chore(deps-dev): bump lint-staged from 13.3.0 to 14.0.1 (#269)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 13.3.0 to 14.0.1.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.1)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 15:02:29 +08:00
dependabot[bot] 6a62d24a17
chore(deps): bump @testing-library/jest-dom from 5.17.0 to 6.0.1 (#270)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.17.0 to 6.0.1.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.17.0...v6.0.1)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 15:00:36 +08:00
zhaoxinxin 832f1cda57
fix: Modify pagination and Personal access tokens without token display (#268)
feat: Modify pagination and Personal access tokens without token display
2023-08-21 20:47:47 +08:00
zhaoxinxin 89267ff061
fix: constants file add page size constant (#267)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-21 19:21:06 +08:00
zhaoxinxin 956f35d259
fix: Add pagination function of Personal access tokens page (#264)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-21 16:45:32 +08:00
zhaoxinxin a219abe80c
fix: Add user page pagination function (#265)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-21 16:31:42 +08:00
zhaoxinxin b417c29e4e
fix: fix show cluster pagination function (#266)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-21 15:04:16 +08:00
zhaoxinxin 16829e1377
fix: show cluster name and id in updating cluster (#263)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-18 17:37:38 +08:00
zhaoxinxin 9fc5dc7f1f
fix: show personal access token id and name in updating (#262)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-18 17:31:24 +08:00
zhaoxinxin 0be29ce4c7
fix: change all page names (#261)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-18 17:06:27 +08:00
zhaoxinxin 3d0abf3d45
feat: Added scheduler count and seed peer count to the clusters page and added search and pagination (#259)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-18 13:25:01 +08:00
Gaius 196dd63398
fix: search scheduler and seed peers when delete table row (#254)
fix: search scheduler and seed peers in deleting

Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-08-16 00:08:57 +08:00
Gaius a42ad31544
fix: search schedulers and seed peers with page and per_page (#253)
Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-08-15 23:28:04 +08:00
zhaoxinxin 3d0f2fd1ff
fix: Modify the scheduler API and seed peer API developer menu (#252)
fix: fix bug
2023-08-15 22:57:43 +08:00
zhaoxinxin 4687eab7a8
fix: modify form regular expression (#247)
fix: modify the regular expression
2023-08-15 17:29:12 +08:00
zhaoxinxin 1935b261d4
feat: add developer personal access tokens page (#246) 2023-08-15 17:06:53 +08:00
dependabot[bot] 3dd7cfa50f
chore(deps-dev): bump lint-staged from 13.3.0 to 14.0.0 (#243)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 13.3.0 to 14.0.0.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v13.3.0...v14.0.0)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-15 14:17:38 +08:00
dependabot[bot] c4a9350b9c
chore(deps): bump @testing-library/jest-dom from 5.17.0 to 6.0.0 (#244)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.17.0 to 6.0.0.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.17.0...v6.0.0)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-15 14:17:17 +08:00
赵鑫鑫 31a3975551
fix: console bugs (#242)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
2023-08-11 17:47:14 +08:00
dependabot[bot] d44226959b
chore(deps-dev): bump eslint-config-prettier from 8.10.0 to 9.0.0 (#237)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 8.10.0 to 9.0.0.
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v8.10.0...v9.0.0)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-11 13:38:43 +08:00
dependabot[bot] fa549b518e
chore(deps): bump @types/jest from 27.5.2 to 29.5.3 (#236)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 27.5.2 to 29.5.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-11 13:38:24 +08:00
dependabot[bot] fe3082df06
chore(deps): bump @types/node from 16.18.39 to 20.4.8 (#234)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 16.18.39 to 20.4.8.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-11 13:37:46 +08:00
dependabot[bot] 8913b5a97f
chore(deps): bump @testing-library/react from 13.4.0 to 14.0.0 (#233)
Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 13.4.0 to 14.0.0.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v13.4.0...v14.0.0)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-11 13:37:26 +08:00
赵鑫鑫 38519ec7bb
feat: change shceduler cluster table (#232) 2023-08-04 14:40:40 +08:00
Gaius 2c9e30c9fa
chore: remove Coverage badge
Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-08-03 22:05:16 +08:00
Gaius 5a3fde9e62
chore: remove CI badge
Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-08-03 22:00:56 +08:00
Gaius 60dc7554b9
feat: initialize v1.0.0 (#231)
Signed-off-by: Gaius <gaius.qi@gmail.com>
2023-08-03 21:57:32 +08:00
Xiaolei.Liang 9c4d591a94
Update index.tsx (#156) 2023-04-06 10:52:29 +08:00
jackHU1998 ecbaba6bab
Change proxy address (#67)
* 更换proxy

* 11/2/Change proxy address

Co-authored-by: huzhibiao <huzhibiao@B-N3Q6Q6LT-2325.local>
Co-authored-by: hzb01248865 <hzb01248865@antgroup.com>
2022-11-02 21:28:53 +08:00
dependabot[bot] 50c705a3ab
chore(deps): bump actions/checkout from 2 to 3 (#57)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-18 10:38:08 +08:00
dependabot[bot] 879180e60f
chore(deps): bump actions/setup-node from 1 to 3 (#58)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 1 to 3.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v1...v3)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-18 10:37:45 +08:00
wb-cxj566042 1ad4418d97
delete invalid codes and optimized styles (#56) 2022-10-13 17:23:10 +08:00
wb-cxj566042 1288f31312
fix #54 cluster add pagination (#55) 2022-10-13 10:47:30 +08:00
Gaius 9788a1dc85
chore: add dependabot actions (#43)
Signed-off-by: Gaius <gaius.qi@gmail.com>
2022-09-16 20:03:57 +08:00
embroede 20a145e27d
Fix spelling of 'Permission' in Console Menu (#42) 2022-09-16 19:57:46 +08:00
xumeiji a57d3c567e
fix:change of submit form value seed_peer_cluster_id and security_group_id(#35) (#40)
Co-authored-by: 徐美娇 <xmj01016629@alibaba-inc.com>
2022-06-23 20:52:16 +08:00
Gpia 717e65c674
chore: rename cdn to seed peer, change ui and apis. (#36) 2022-06-01 17:55:38 +08:00
492 changed files with 73655 additions and 7406 deletions

13
.editorconfig Executable file → Normal file
View File

@ -1,16 +1,13 @@
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
# We recommend you to keep these unchanged.
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[Makefile]
indent_style = tab
# Change these settings to your own preference.
indent_style = space
indent_size = 2

3
.eslintignore Normal file
View File

@ -0,0 +1,3 @@
/node_modules/
/.next/
tsconfig.tsbuildinfo

21
.eslintrc.json Normal file
View File

@ -0,0 +1,21 @@
{
"extends": [
"react-app",
"prettier"
],
"overrides": [
{
"files": [
"**/*.ts",
"**/*.tsx"
],
"rules": {
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/comma-dangle": "off"
}
}
]
}

View File

@ -1,7 +1,7 @@
---
name: Bug Report
about: Report a bug for dragonfly console
labels: kind/bug
labels: bug
---
@ -16,9 +16,3 @@ labels: kind/bug
### How to reproduce it:
<!-- How can a maintainer reproduce this issue (please be detailed) -->
### Environment:
- Dragonfly console version:
- OS:
- Kernel (e.g. `uname -a`):
- Others:

View File

@ -1,6 +1,5 @@
---
name: Custom
about: Custom issue template for dragonfly console
labels: kind/custom
---

View File

@ -1,7 +1,7 @@
---
name: Feature Request
about: Request a new feature for dragonfly console
labels: kind/feature
labels: enhancement
---

View File

@ -26,15 +26,12 @@
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation Update (if none of the other choices apply)
## Checklist:
## Checklist
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] Code compiles correctly.
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.
- [ ] I have added tests to cover my changes.

10
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: weekly

23
.github/workflows/check-size.yaml vendored Normal file
View File

@ -0,0 +1,23 @@
name: Check Size
on:
push:
branches: [main, release-*]
pull_request:
branches: [main, release-*]
jobs:
check_size:
name: Check Size
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Check large files
uses: actionsDesk/lfs-warning@v3.3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
filesizelimit: '524288'

33
.github/workflows/ci.yaml vendored Normal file
View File

@ -0,0 +1,33 @@
name: CI
on:
push:
branches: [main, release-*]
pull_request:
branches: [main, release-*]
jobs:
build:
name: Build
timeout-minutes: 10
runs-on: ubuntu-latest
needs: [test]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: '18.x'
- run: yarn
- name: Cache nextjs build
uses: actions/cache@v4
with:
path: .next/cache
key: nextjs-${{ hashFiles('package*.json') }}
- name: Build
run: yarn build

34
.github/workflows/codeql-analysis.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
name: CodeQL Analysis
on:
push:
branches: [main, release-*]
paths-ignore: ['**.md', '**.png', '**.jpg', '**.svg', '**/docs/**']
pull_request:
branches: [main, release-*]
paths-ignore: ['**.md', '**.png', '**.jpg', '**.svg', '**/docs/**']
jobs:
analysis:
name: Analysis
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
language: [javascript]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3

31
.github/workflows/e2e.yaml vendored Normal file
View File

@ -0,0 +1,31 @@
name: E2E Test
on: push
jobs:
cypress-run:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: '18.x'
- name: Install dependencies
run: yarn install --force
- name: Cypress run
uses: cypress-io/github-action@v6
with:
build: yarn build
start: yarn start
wait-on: 'http://localhost:3000'
wait-on-timeout: 120
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

25
.github/workflows/lint.yaml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Lint
on:
push:
branches: [main, release-*]
pull_request:
branches: [main, release-*]
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup node
uses: actions/setup-node@v4
with:
node-version: '18.x'
- run: yarn install
- name: Linter
run: yarn lint

View File

@ -12,12 +12,12 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v5
- name: Set node version
uses: actions/setup-node@v1
uses: actions/setup-node@v4
with:
node-version: '14.x'
node-version: '18.x'
- name: Install
run: yarn install

27
.gitignore vendored
View File

@ -6,12 +6,19 @@
/yarn-error.log
/yarn.lock
/package-lock.json
/.pnp
.pnp.js
# production
/dist
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
# umi
/src/.umi
@ -22,3 +29,23 @@
# vscode
.history/
.vscode/
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
tsconfig.tsbuildinfo
# testing
/coverage
/cypress/videos
# mock
/mock
#nyc
/.nyc_output

4
.husky/commit-msg Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no -- commitlint --edit "$1"

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
yarn lint-staged

View File

@ -2,7 +2,3 @@
**/*.svg
**/*.ejs
**/*.html
package.json
.umi
.umi-production
.umi-test

View File

@ -1,11 +1,13 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"printWidth": 120,
"overrides": [
{
"files": ".prettierrc",
"options": { "parser": "json" }
"options": {
"parser": "json"
}
}
]
}

122
.umirc.ts
View File

@ -1,122 +0,0 @@
import { defineConfig } from 'umi';
export default defineConfig({
title: 'Dragonfly',
nodeModulesTransform: {
type: 'none',
},
favicon: 'logo-dragonfly.png',
routes: [
{
exact: true,
path: '/',
component: '@/pages/index',
},
{ exact: true, path: '/signin', component: '@/pages/index' },
{ exact: true, path: '/installation', component: '@/pages/installation' },
{
exact: false,
path: '/profile',
component: '@/layouts/index',
routes: [
{
exact: true,
path: '/profile/:id',
component: '@/pages/profile',
},
],
},
{
exact: false,
path: '/configuration',
component: '@/layouts/index',
routes: [
{
exact: true,
path: '/configuration/',
component: '@/pages/scheduler',
},
{
exact: true,
path: '/configuration/scheduler-cluster',
component: '@/pages/scheduler',
},
{
exact: true,
path: '/configuration/cdn-cluster',
component: '@/pages/cdn',
},
{
exact: true,
path: '/configuration/application',
component: '@/pages/application',
},
{
exact: true,
path: '/configuration/security',
component: '@/pages/security',
},
],
},
{
exact: false,
path: '/setting',
component: '@/layouts/index',
routes: [
{
exact: true,
path: '/setting/',
component: '@/pages/permission',
},
{
exact: true,
path: '/setting/permission',
component: '@/pages/permission',
},
{
exact: true,
path: '/setting/user',
component: '@/pages/users',
},
{
exact: true,
path: '/setting/oauth',
component: '@/pages/oauth',
},
],
},
{
exact: false,
path: '/service',
component: '@/layouts/index',
routes: [
{
exact: true,
path: '/service/',
component: '@/pages/task',
},
{
exact: true,
path: '/service/task',
component: '@/pages/task',
},
{ component: '@/pages/404' },
],
},
{ component: '@/pages/404' },
],
locale: {
default: 'en-US', // en-US
baseNavigator: true,
antd: true,
},
proxy: {
'/api/v1': {
target: 'http://11.122.75.66:8080', // dep env
},
},
fastRefresh: {},
theme: {
'primary-color': '#23B066',
},
});

328
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,328 @@
# Contributing to Dragonfly Console
It is warmly welcomed if you have the interest to hack on Dragonfly Console.
First, we encourage this kind of willingness very much.
And here is a list of contributing guide for you.
## Topics
- [Contributing to Dragonfly Console](#contributing-to-dragonfly-console)
- [Topics](#topics)
- [Reporting security issues](#reporting-security-issues)
- [Reporting general issues](#reporting-general-issues)
- [Code and doc contribution](#code-and-doc-contribution)
- [Workspace Preparation](#workspace-preparation)
- [Branch Definition](#branch-definition)
- [Commit Rules](#commit-rules)
- [Commit Message](#commit-message)
- [Commit Content](#commit-content)
- [PR Description](#pr-description)
- [Postman mock server overview](#postman-mock-server-overview)
- [Download Postman](#download-postman)
- [Import API](#import-api)
- [Setting up mock server](#setting-up-mock-server)
## Reporting security issues
Security issues are always treated seriously.
As our usual principle, we discourage anyone to spread security issues.
If you find a security issue of Dragonfly Console, please do not discuss it in
public and even do not open a public issue.
Instead, we encourage you to send us a private email to
[dragonfly-developers@googlegroups.com](mailto:dragonfly-developers@googlegroups.com) to report this.
## Reporting general issues
To be honest, we regard every user of Dragonfly Console as a very kind contributor.
After experiencing Dragonfly Console, you may have some feedback for the project.
Then feel free to open an issue via
[NEW ISSUE](https://github.com/dragonflyoss/console/issues/new).
Since we collaborate project Dragonfly Console in a distributed way,
we appreciate **WELL-WRITTEN**, **DETAILED**, **EXPLICIT** issue reports.
To make the communication more efficient, we wish everyone could
search if your issue is an existing one in the searching list.
If you find it existing, please add your details in comments
under the existing issue instead of opening a brand new one.
To make the issue details as standard as possible,
we setup an [ISSUE TEMPLATE](./.github/ISSUE_TEMPLATE) for issue reporters.
You can find three kinds of issue templates there: question,
bug report and feature request. Please **BE SURE** to follow
the instructions to fill fields in template.
There are a lot of cases when you could open an issue:
- bug report
- feature request
- performance issues
- feature proposal
- feature design
- help wanted
- doc incomplete
- test improvement
- any questions on project
- and so on
Also, we must remind that when filing a new issue,
please remember to remove the sensitive data from your post.
Sensitive data could be password, secret key,
network locations, private business data and so on.
## Code and doc contribution
Every action to make project Dragonfly Console better is encouraged.
On GitHub, every improvement for Dragonfly Console could be
via a PR (short for pull request).
- If you find a typo, try to fix it!
- If you find a bug, try to fix it!
- If you find some redundant codes, try to remove them!
- If you find some test cases missing, try to add them!
- If you could enhance a feature, please **DO NOT** hesitate!
- If you find code implicit, try to add comments to make it clear!
- If you find code ugly, try to refactor that!
- If you can help to improve documents, it could not be better!
- If you find document incorrect, just do it and fix that!
- ...
Actually, it is impossible to list them completely.
Just remember one principle:
> WE ARE LOOKING FORWARD TO ANY PR FROM YOU.
Since you are ready to improve Dragonfly Console with a PR,
we suggest you could take a look at the PR rules here.
- [Workspace Preparation](#workspace-preparation)
- [Branch Definition](#branch-definition)
- [Commit Rules](#commit-rules)
- [PR Description](#pr-description)
### Workspace Preparation
To put forward a PR, we assume you have registered
a GitHub ID. Then you could finish
the preparation in the following steps:
1. **FORK** Dragonfly Console to your repository.
To make this work, you just need to click the button Fork
in right-left of [dragonflyoss/console](https://github.com/dragonflyoss/console)
main page. Then you will end up with your repository in
`https://github.com/<your-username>/Console`,
in which `your-username` is your GitHub username.
1. **CLONE** your own repository to develop locally.
Use `git clone https://github.com/dragonflyoss/console.git`
to clone repository to your local machine.
Then you can create new branches to finish the change you wish to make.
1. **Set Remote** upstream to be
`https://github.com/dragonflyoss/console.git`
using the following two commands:
```bash
git remote add upstream https://github.com/dragonflyoss/console.git
git remote set-url --push upstream no-pushing
```
With this remote setting, you can check your git remote configuration like this:
https://github.com/dragonflyoss/console.git
```bash
$ git remote -v
origin https://github.com/<your-username>/console.git (fetch)
origin https://github.com/<your-username>/console.git (push)
upstream https://github.com/dragonflyoss/console.git (fetch)
upstream no-pushing (push)
```
Adding this, we can easily synchronize local branches with upstream branches.
1. **Create a branch** to add a new feature or fix issues
Update local working directory:
```bash
cd console
git fetch upstream
git checkout main
git rebase upstream/main
```
Create a new branch:
```bash
git checkout -b <new-branch>
```
Make any change on the `new-branch` then build and test your codes.
### Branch Definition
Right now we assume every contribution via pull
request is for [branch main](https://github.com/dragonflyoss/console)
in Dragonfly Console. Before contributing,
be aware of branch definition would help a lot.
As a contributor, keep in mind again that every
contribution via pull request is for branch main.
While in project Dragonfly Console, there are several other branches,
we generally call them rc branches, release branches and backport branches.
Before officially releasing a version,
we will checkout a rc(release candidate) branch.
In this branch, we will test more than branch main.
When officially releasing a version,
there will be a release branch before tagging.
After tagging, we will delete the release branch.
When backporting some fixes to existing released version,
we will checkout backport branches. After backporting,
the backporting effects will be in PATCH number in
MAJOR.MINOR.PATCH of [SemVer](http://semver.org/).
### Commit Rules
Actually in Dragonfly Console, we take two rules seriously when committing:
- [Commit Message](#commit-message)
- [Commit Content](#commit-content)
#### Commit Message
Commit message could help reviewers better understand
what the purpose of submitted PR is.
It could help accelerate the code review procedure as well.
We encourage contributors to use **EXPLICIT** commit
message rather than an ambiguous message. In general,
we advocate the following commit message type:
- feat: xxxx.For example, "feat: make result show in sorted order".
- fix: xxxx. For example, "fix: fix panic when input nil parameter".
- docs: xxxx. For example, "docs: add docs about storage installation".
- style: xxxx. For example, "style: format the code style of Constants.java".
- refactor: xxxx. For example, "refactor: simplify to make codes more readable".
- test: xxx. For example, "test: add unit test case for func InsertIntoArray".
- chore: xxx. For example, "chore: integrate travis-ci".
It's the type of maintenance change.
On the other side, we discourage contributors
from committing messages in the following ways:
- ~~fix bug~~
- ~~update~~
- ~~add doc~~
#### Commit Content
Commit content represents all content changes
included in one commit. We had better include things
in one single commit which could support reviewer's complete
review without any other commits' help. In another word,
contents in one single commit can pass the CI to avoid code mess.
In brief, there are two minor rules for us to keep in mind:
- avoid very large change in a commit.
- complete and reviewable for each commit.
No matter what the commit message, or commit content is,
we do take more emphasis on code review.
### PR Description
PR is the only way to make change to Dragonfly Console project files.
To help reviewers better get your purpose,
PR description could not be too detailed.
We encourage contributors to follow the
[PR template](./.github/PULL_REQUEST_TEMPLATE.md) to finish the pull request.
## Postman mock server overview
In this article, we will see how to import Swagger API into Postman and use mock server.
### Download Postman
Download the [app](https://www.postman.com/downloads) to get started with the Postman API platform.
### Import API
If you need to use a mock server, please import the [swagger.yaml](https://raw.githubusercontent.com/dragonflyoss/Dragonfly2/main/api/manager/swagger.yaml) file of Dragonfly Manager, refer to [importing-and-exporting-data](https://learning.postman.com/docs/getting-started/importing-and-exporting-data/).
**Step 1:** Import API.
![](/docs/images/contributing/postman-import.png)
**Step 2:** Copy the swagger.yaml URL.
![](/docs/images/contributing/postman-import-api.png)
**Step 3:** Select OpenAPI 2.0 with Postman collection.
![](/docs/images/contributing/postman-select.png)
### Setting up mock server
To use mock server, please do the following, refer to [mocking-data-setting-up-mock](https://learning.postman.com/docs/designing-and-developing-your-api/mocking-data/setting-up-mock/).
**Step 1:** Choose **Collections** in the sidebar, choose the more actions icon next to the collection you want to mock, then choose **Mock collection**.
![](/docs/images/contributing/postman-mock-collection.png)
**Step 2:** Enter the name of the mock server and click **Create Mock Server** button.
![](/docs/images/contributing/postman-creat-mock.png)
**Step 3:** Copy the mock server URL.
![](/docs/images/contributing/postman-copy-mockUrl.png)
**Step 4:** Add the mock server URL and click the **Save** button.
![](/docs/images/contributing/postman-change-path.png)
**Step 5:** Click the **Send** button to initiate a request.
![](docs/images/contributing/postman-request.png)
**Step 6:** You can verify the success of requests by checking the request logs in the **Mock Servers**.
![](docs/images/contributing/postman-verify.png)
**Step 7:** Export mock server URL through environment variables in project.
Install dependencies.
```shell
npm install
```
First you need `export REACT_APP_API_URL=<your-mock-server-URL>`, where your-mock-server-URL is your own mock server URL, start your server after the import is successful.
```shell
$ export REACT_APP_API_URL=<your-mock-server-URL>
$ npm start
> console@1.0.0 dev
> cross-env NODE_ENV='development'
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
event - compiled client and server successfully in 2.8s (173 modules)
```
**Step 8:** If you want **Mock Server** to return **OK response**, you need to add query params with code, so that the request matches the query params, then **OK response** will be returned.
![](/docs/images/contributing/postman-ok-response.png)
When the query params of the request is `code=200`, **Mock Server** will return `OK Response`.
![](/docs/images/contributing/postman-ok-demo.gif)
**Step 9:** If you want **Mock Server** to return **Bad response**, you need to add query params with code, so that the request matches the query params, then **Bad response** will be returned.
![](/docs/images/contributing/postman-not-fount-response.png)
When the query params of the request is `code=400`, **Mock Server** will return `Bad Response`.
![](/docs/images/contributing/postman-not-found-demo.gif)

View File

@ -1,17 +1,46 @@
# Dragonfly Console
# Develop
[![GitHub release](https://img.shields.io/github/release/dragonflyoss/console.svg)](https://github.com/dragonflyoss/console/releases)
[![LICENSE](https://img.shields.io/github/license/dragonflyoss/console.svg?style=flat-square)](https://github.com/dragonflyoss/console/blob/main/LICENSE)
[![Coverage](https://codecov.io/gh/dragonflyoss/console/branch/main/graph/badge.svg)](https://app.codecov.io/gh/dragonflyoss/console)
## Getting Started
## Introduction
Install dependencies,
Dragonfly console is the front-end console of dragonfly,
through which you can easily configure clusters and view cluster information.
```bash
$ yarn
```
## Functionality Overview
Start the dev server,
- **Scheduler Cluster:** Manage the scheduler cluster and configure the information of the scheduler cluster.
```bash
$ yarn start
```
- **Seed Peer Cluster:** Manage the seed peer cluster and configure the seed peer cluster information.
- **Security:** Manage security groups and security rules,
users can configure the security groups associated with the scheduler cluster.
- **Permissions:** Manage permissions and roles.
- **Task:** Manage asynchronous tasks, including preheat tasks.
- **User:** Manage user information, you can change user roles here.
## Documentation
You can find the full documentation on the [d7y.io][d7y.io].
## Community
Join the conversation and help the community.
- **Slack Channel**: [#dragonfly](https://cloud-native.slack.com/messages/dragonfly/) on [CNCF Slack](https://slack.cncf.io/)
- **Github Discussions**: [Dragonfly Discussion Forum](https://github.com/dragonflyoss/dragonfly/discussions)
- **Developer Group**: <dragonfly-developers@googlegroups.com>
- **Maintainer Group**: <dragonfly-maintainers@googlegroups.com>
- **Twitter**: [@dragonfly_oss](https://twitter.com/dragonfly_oss)
- **DingTalk**: [22880028764](https://qr.dingtalk.com/action/joingroup?code=v1,k1,pkV9IbsSyDusFQdByPSK3HfCG61ZCLeb8b/lpQ3uUqI=&_dt_no_comment=1&origin=11)
[d7y.io]: https://d7y.io/
## Contributing
You should check out our [CONTRIBUTING](./CONTRIBUTING.md) and develop the project together.

19
codecov.yml Normal file
View File

@ -0,0 +1,19 @@
coverage:
precision: 2
round: down
range: '90...100'
status:
project:
default:
enabled: yes
target: 90%
patch:
default:
enabled: yes
target: 90%
comment:
layout: 'reach, diff, flags, files'
behavior: default
require_changes: false
branches:
- main

3
commitlint.config.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
};

18
config-overrides.js Normal file
View File

@ -0,0 +1,18 @@
const webpack = require('webpack');
module.exports = function override(config) {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
crypto: require.resolve('crypto-browserify'),
stream: require.resolve('stream-browserify'),
querystring: require.resolve('query-string'),
vm: false,
});
config.resolve.fallback = fallback;
config.plugins = (config.plugins || []).concat([
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer'],
}),
]);
return config;
};

19
cypress.config.ts Normal file
View File

@ -0,0 +1,19 @@
import { defineConfig } from 'cypress';
export default defineConfig({
// setupNodeEvents can be defined in either
// the e2e or component configuration
e2e: {
setupNodeEvents(on, config) {
require('@cypress/code-coverage/task')(on, config);
// include any other plugin code...
// It's IMPORTANT to return the config object
// with any changed environment variables
return config;
},
baseUrl: 'http://localhost:3000',
},
defaultCommandTimeout: 15000,
responseTimeout: 60000,
});

27
cypress/e2e/404/404.cy.ts Normal file
View File

@ -0,0 +1,27 @@
describe('404', () => {
beforeEach(() => {
cy.signin();
cy.viewport(1440, 1080);
});
it('show 404 page', () => {
cy.visit('/root');
cy.get('#404-help-text').should('have.text', `The page you were looking for doesn't exist.`);
});
it('click the `go back cluster` button', () => {
cy.visit('/root');
// Display 404 help text.
cy.get('#something-went-wrong').should('have.text', 'Something gone wrong!');
cy.get('#404-help-text').should('have.text', `The page you were looking for doesn't exist.`);
// Click go back cluster button.
cy.get('#go-back').click();
// Then I see that the current page is the clusters.
cy.url().should('include', '/clusters');
});
});

View File

@ -0,0 +1,422 @@
import audit from '../../fixtures/audit/audits.json';
import paginationAudit from '../../fixtures/audit/pagination-audits.json';
import users from '../../fixtures/users/users.json';
import userAudit from '../../fixtures/audit/user.audits.json';
import operationGetAudit from '../../fixtures/audit/operation-get-audits.json';
import operationPostAudit from '../../fixtures/audit/operation-post-audits.json';
import operationPutAudit from '../../fixtures/audit/operation-put-audits.json';
import operationDeleteAudit from '../../fixtures/audit/operation-delete-audits.json';
import operationPatchAudit from '../../fixtures/audit/operation-patch-audits.json';
import actorTypeUserAudit from '../../fixtures/audit/actor-type-user-audits.json';
import actorTypeUnknownAudit from '../../fixtures/audit/actor-type-unknown-audits.json';
import actorTypePatAudit from '../../fixtures/audit/actor-type-pat-audits.json';
import failureAudit from '../../fixtures/audit/failure-audits.json';
describe('audit', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?page=1&per_page=10>;rel=prev,</api/v1/audits?page=2&per_page=10>;rel=next,</api/v1/audits?page=1&per_page=10>;rel=first,</api/v1/audits?page=2&per_page=10>;rel=last',
};
res.send(200, audit, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=2&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?page=1&per_page=10>;rel=prev,</api/v1/audits?page=3&per_page=10>;rel=next,</api/v1/audits?page=1&per_page=10>;rel=first,</api/v1/audits?page=2&per_page=10>;rel=last',
};
res.send(200, paginationAudit, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: users,
});
},
);
cy.visit('/audit');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(4)').click();
// Can display user name.
cy.get('#user-11').should('have.text', 'unknown');
// Can display path.
cy.get('#path-11').should('have.text', '/api/v1/users/signin');
// Can display operation.
cy.get('#operation-11').should('have.text', 'POST');
// Can display actor type.
cy.get('#actor-type-11').should('have.text', 'UNKNOWN');
// Can display status code.
cy.get('#status-code-11').should('have.text', '401');
// Can display status.
cy.get('#status-11').should('have.text', 'FAILURE');
cy.get('#user-13').should('have.text', 'jack');
// Can display different operation.
cy.get('#operation-13').should('have.text', 'GET');
cy.get('#operation-14').should('have.text', 'PATCH');
cy.get('#operation-15').should('have.text', 'DELETE');
cy.get('#operation-16').should('have.text', 'PUT');
});
describe('search', () => {
it('should search user name', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?actor_name=jack&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?actor_name=jack&page=1&per_page=10>;rel=prev,</api/v1/audits?actor_name=jack&page=2&per_page=10>;rel=next,</api/v1/audits?actor_name=jack&page=1&per_page=10>;rel=first,</api/v1/audits?actor_name=jack&page=1&per_page=10>;rel=last',
};
res.send(200, userAudit, responseHeaders);
});
},
);
cy.get('#actor-name').type('jack');
cy.get('#audit-table-body').children().and('have.length', 3);
cy.get('#user-5').should('have.text', 'jack');
});
it('should filter by operation', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?operation=GET&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?operation=GET&page=1&per_page=10>;rel=prev,</api/v1/audits?operation=GET&page=2&per_page=10>;rel=next,</api/v1/audits?operation=GET&page=1&per_page=10>;rel=first,</api/v1/audits?operation=GET&page=1&per_page=10>;rel=last',
};
res.send(200, operationGetAudit, responseHeaders);
});
},
);
cy.get('#operation-select').click();
// Select Get.
cy.get('#GET').click();
cy.get('#operation-13').should('have.text', 'GET');
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?operation=POST&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?operation=POST&page=1&per_page=10>;rel=prev,</api/v1/audits?operation=POST&page=2&per_page=10>;rel=next,</api/v1/audits?operation=POST&page=1&per_page=10>;rel=first,</api/v1/audits?operation=POST&page=1&per_page=10>;rel=last',
};
res.send(200, operationPostAudit, responseHeaders);
});
},
);
cy.get('#operation-select').click();
// Select Post.
cy.get('#POST').click();
cy.get('#audit-table-body').children().and('have.length', 3);
cy.get('#operation-10').should('have.text', 'POST');
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?operation=PATCH&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?operation=PATCH&page=1&per_page=10>;rel=prev,</api/v1/audits?operation=PATCH&page=2&per_page=10>;rel=next,</api/v1/audits?operation=PATCH&page=1&per_page=10>;rel=first,</api/v1/audits?operation=PATCH&page=1&per_page=10>;rel=last',
};
res.send(200, operationPatchAudit, responseHeaders);
});
},
);
cy.get('#operation-select').click();
// Select Patch.
cy.get('#PATCH').click();
cy.get('#audit-table-body').children().and('have.length', 1);
cy.get('#operation-14').should('have.text', 'PATCH');
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?operation=DELETE&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?operation=DELETE&page=1&per_page=10>;rel=prev,</api/v1/audits?operation=DELETE&page=2&per_page=10>;rel=next,</api/v1/audits?operation=DELETE&page=1&per_page=10>;rel=first,</api/v1/audits?operation=DELETE&page=1&per_page=10>;rel=last',
};
res.send(200, operationDeleteAudit, responseHeaders);
});
},
);
cy.get('#operation-select').click();
// Select Delete.
cy.get('#DELETE').click();
cy.get('#audit-table-body').children().and('have.length', 1);
cy.get('#operation-15').should('have.text', 'DELETE');
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?operation=PUT&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?operation=PUT&page=1&per_page=10>;rel=prev,</api/v1/audits?operation=PUT&page=2&per_page=10>;rel=next,</api/v1/audits?operation=PUT&page=1&per_page=10>;rel=first,</api/v1/audits?operation=PUT&page=1&per_page=10>;rel=last',
};
res.send(200, operationPutAudit, responseHeaders);
});
},
);
cy.get('#operation-select').click();
// Select Put.
cy.get('#PUT').click();
cy.get('#audit-table-body').children().and('have.length', 1);
cy.get('#operation-16').should('have.text', 'PUT');
});
it('should filter by actor type', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?actor_type=USER&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?actor_type=USER&page=1&per_page=10>;rel=prev,</api/v1/audits?actor_type=USER&page=2&per_page=10>;rel=next,</api/v1/audits?actor_type=USER&page=1&per_page=10>;rel=first,</api/v1/audits?actor_type=USER&page=1&per_page=10>;rel=last',
};
res.send(200, actorTypeUserAudit, responseHeaders);
});
},
);
cy.get('#actor-type-select').click();
// Select User for Actor Type.
cy.get('#USER').click();
cy.get('#audit-table-body').children().and('have.length', 9);
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?actor_type=PAT&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?actor_type=PAT&page=1&per_page=10>;rel=prev,</api/v1/audits?actor_type=PAT&page=2&per_page=10>;rel=next,</api/v1/audits?actor_type=PAT&page=1&per_page=10>;rel=first,</api/v1/audits?actor_type=PAT&page=1&per_page=10>;rel=last',
};
res.send(200, actorTypePatAudit, responseHeaders);
});
},
);
cy.get('#actor-type-select').click();
// Select Pat for Actor Type.
cy.get('#PAT').click();
cy.get('#actor-type-12').should('have.text', 'PAT');
cy.get('#audit-table-body').children().and('have.length', 1);
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?actor_type=UNKNOWN&page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?actor_type=UNKNOWN&page=1&per_page=10>;rel=prev,</api/v1/audits?actor_type=UNKNOWN&page=2&per_page=10>;rel=next,</api/v1/audits?actor_type=UNKNOWN&page=1&per_page=10>;rel=first,</api/v1/audits?actor_type=UNKNOWN&page=1&per_page=10>;rel=last',
};
res.send(200, actorTypeUnknownAudit, responseHeaders);
});
},
);
cy.get('#actor-type-select').click();
// Select Pat for Actor Type.
cy.get('#UNKNOWN').click();
cy.get('#actor-type-7').should('have.text', 'UNKNOWN');
cy.get('#audit-table-body').children().and('have.length', 3);
});
it('should filter by status', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=1&per_page=10&state=FAILURE',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/audits?page=2&per_page=10&state=FAILURE>;rel=next,</api/v1/audits?page=1&per_page=10&state=FAILURE>;rel=first,</api/v1/audits?page=1&per_page=10&state=FAILURE>;rel=last',
};
res.send(200, failureAudit, responseHeaders);
});
},
);
cy.get('#states-select').click();
cy.get('#FAILURE').click();
cy.get('#audit-table-body').children().and('have.length', 2);
});
it('should filter by path', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=1&path=%2Fapi%2Fv1%2Fclusters%2F1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?page=1&path=%2Fapi%2Fv1%2Fclusters%2F1&per_page=10>;rel=prev,</api/v1/audits?page=1&path=%2Fapi%2Fv1%2Fclusters%2F1&per_page=10>;rel=next,</api/v1/audits?page=1&path=%2Fapi%2Fv1%2Fclusters%2F1&per_page=10>;rel=first,</api/v1/audits?page=1&path=%2Fapi%2Fv1%2Fclusters%2F1&per_page=10>;rel=last',
};
res.send(200, operationPatchAudit, responseHeaders);
});
},
);
cy.get('#search').type('/api/v1/clusters/1');
});
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=1&per_page=10',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/audits?page=1&per_page=10>;rel=prev,</api/v1/audits?page=3&per_page=10>;rel=next,</api/v1/audits?page=1&per_page=10>;rel=first,</api/v1/audits?page=2&per_page=10>;rel=last',
};
res.send(200, [], responseHeaders);
});
},
);
cy.get('#no-audit-table').should('have.text', `You don't have audit logs.`);
});
describe('should handle API error response', () => {
it('should handle user API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('should handle audit API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/audits?page=1&per_page=10',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
});
});

View File

@ -0,0 +1,604 @@
import clusters from '../../fixtures/clusters/clusters.json';
import seedPeers from '../../fixtures/seed-peers/seed-peers.json';
import schedulers from '../../fixtures/schedulers/schedulers.json';
import cluster from '../../fixtures/clusters/cluster/cluster.json';
import deleteCluster from '../../fixtures/clusters/cluster/delete-cluster.json';
import deleteClusters from '../../fixtures/clusters/cluster/delete-clusters.json';
describe('Cluster', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: seedPeers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.visit('clusters/1');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
it('can display breadcrumb', () => {
// Display is loading.
cy.get('[data-testid="cluster-loading"]').should('be.exist');
cy.url().should('include', '/clusters/1');
cy.get('.MuiBreadcrumbs-ol > :nth-child(3) > .MuiTypography-root')
.should('be.visible')
.and('contain', 'cluster-1');
cy.get('.MuiBreadcrumbs-ol > :nth-child(1) > .MuiTypography-root').click();
// Load does not exist.
cy.get('[data-testid="cluster-loading"]').should('not.exist');
cy.url().should('include', '/clusters');
});
it('can display information', () => {
// Display the cluster name
cy.get('#name').should('be.visible').and('contain', 'cluster-1');
// Display the cluster description.
cy.get('#description')
.should('be.visible')
.and(
'contain',
'Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.',
);
// Displays whether it is the default cluster.
cy.get('#default').should('be.visible').and('contain', 'Yes');
// Displays the scheduler cluster ID.
cy.get('#scheduler-cluster-id').should('be.visible').and('contain', '1');
// Displays the seed peer cluster ID.
cy.get('#seed-peer-cluster-id').should('be.visible').and('contain', '1');
});
it('can display scopes', () => {
// Displays the location.
cy.get('#location').should('be.visible').and('contain', 'China|Hang|Zhou');
// Displays the idc.
cy.get('#idc-1').should('be.visible').and('contain', 'Hangzhou');
cy.get('#idc-2').should('be.visible').and('contain', 'Shanghai');
// IDC does not exist.
cy.get('#idc-3').should('not.be.visible', 'Beijing');
// The number of IDC is 2 and the More button is no longer displayed.
cy.get('#idc').should('exist').click();
// Click the button to show more idc.
cy.get('.MuiDialogContent-root > :nth-child(1)').should('be.visible').and('have.text', 'Hangzhou');
cy.get('.MuiDialogContent-root > :nth-child(2)').should('be.visible').and('have.text', 'Shanghai');
cy.get('.MuiDialogContent-root > :nth-child(3)').should('be.visible').and('have.text', 'Beijing');
cy.get('.MuiDialogContent-root > :nth-child(4)').should('be.visible').and('have.text', 'Xiamen');
cy.get('.MuiDialogContent-root').should('exist');
cy.get('#idc-total').should('contain', 'Total: 5');
cy.get('body').click('topLeft');
// Displays the CIDRs
cy.get('#cidrs-2').should('be.visible').and('contain', '192.168.0.0/16');
cy.get('#cidrs-total').should('contain', 'Total: 5');
// Click the button to show more cidrs.
cy.get('#cidrs').should('exist').click();
// Show idc dialog module.
cy.get('.MuiDialogContent-root').should('exist');
cy.get('.MuiDialogContent-root').should('be.visible').and('contain', '10.0.0.0/8');
cy.get('body').click('topLeft');
// The CIDR number should be 3.
cy.get('.MuiDialogContent-root > :nth-child(1)').should('have.text', '10.0.0.0/8');
cy.get('.MuiDialogContent-root > :nth-child(2)').should('have.text', '192.168.0.0/16');
// CIDRs is not visible.
cy.get('.MuiDialogContent-root > :nth-child(3)').should('not.be.visible', '172.16.0.0/12');
// The number of hostnames should be 3.
cy.get('#hostname-1').should('have.text', 'cluster-1');
cy.get('#hostname-2').should('have.text', 'cluster-2');
// Hostname is not visible.
cy.get('#hostname-3').should('not.be.visible', 'cluster-3');
cy.get('#hostname-4').and('not.be.visible', 'cluster-4');
cy.get('#hostnames-total').should('contain', 'Total: 5');
// Click the button to show more cidrs.
cy.get('#hostnames').should('exist').click();
// Show hostnames dialog module.
cy.get('.MuiDialogContent-root').children().should('have.length', 4);
cy.get('body').click('topLeft');
cy.get('.MuiDialogContent-root').should('not.be.visible');
});
it('the visible width of the screen is 1920px. Display scopes', () => {
cy.viewport(1920, 1080);
// The number of idc displayed is 3.
cy.get('#idc-1').should('be.visible').and('have.text', 'Hangzhou');
cy.get('#idc-2').should('be.visible').and('have.text', 'Shanghai');
cy.get('#idc-3').should('be.visible').and('have.text', 'Beijing');
cy.get('#idc-4').should('not.be.visible');
// The number of CIDRs displayed is 3.
cy.get('#cidrs-1').should('be.visible').should('have.text', '10.0.0.0/8');
cy.get('#cidrs-2').should('be.visible').should('have.text', '192.168.0.0/16');
cy.get('#cidrs-3').should('be.visible').should('have.text', '172.16.0.0/12');
cy.get('#cidrs-4').should('not.be.visible');
// The number of hostnames displayed is 3.
cy.get('#hostname-1').should('be.visible').should('have.text', 'cluster-1');
cy.get('#hostname-2').should('be.visible').should('have.text', 'cluster-2');
cy.get('#hostname-3').should('be.visible').should('have.text', 'cluster-3');
cy.get('#hostname-4').should('not.be.visible');
});
it('the visible width of the screen is 1920px. Display scopes', () => {
cy.viewport(2560, 1080);
// The number of idc displayed is 3.
cy.get('#idc-1').should('be.visible').and('have.text', 'Hangzhou');
cy.get('#idc-2').should('be.visible').and('have.text', 'Shanghai');
cy.get('#idc-3').should('be.visible').and('have.text', 'Beijing');
cy.get('#idc-4').should('be.visible').and('have.text', 'Xiamen');
// The number of CIDRs displayed is 3.
cy.get('#cidrs-1').should('be.visible').and('have.text', '10.0.0.0/8');
cy.get('#cidrs-2').should('be.visible').and('have.text', '192.168.0.0/16');
cy.get('#cidrs-3').should('be.visible').and('have.text', '172.16.0.0/12');
cy.get('#cidrs-4').should('be.visible').and('have.text', '173.16.0.1/11');
// The number of hostnames displayed is 3.
cy.get('#hostname-1').should('be.visible').and('have.text', 'cluster-1');
cy.get('#hostname-2').should('be.visible').and('have.text', 'cluster-2');
cy.get('#hostname-3').should('be.visible').and('have.text', 'cluster-3');
cy.get('#hostname-4').should('be.visible').and('have.text', 'cluster-4');
});
it('can display config', () => {
cy.get('#seed-peer-load-limit').should('be.visible').and('have.text', '300');
cy.get('#peer-load-limit').should('be.visible').and('have.text', '51');
cy.get('#candidate-parent-limit').should('be.visible').and('have.text', '4');
cy.get('#filter-parent-limit').should('be.visible').and('have.text', '40');
cy.get('#job-rate-limit').should('be.visible').and('have.text', '15');
});
it('copies text to clipboard', () => {
// Click the copy scheduler cluster id icon.
cy.get('#copy-scheduler-cluster-id').click();
cy.get('#schedulerClusterIDCopyIcon').should('exist');
cy.get('#schedulerClusterIDTooltip').should('not.exist');
cy.wait(1000);
// Display successful copy icon.
cy.get('#schedulerClusterIDCopyIcon').should('exist');
cy.get('#schedulerClusterIDTooltip').should('not.exist');
// Let's check the copied text.
cy.window()
.its('navigator.clipboard')
.then((clip) => clip.readText())
.should('equal', '1');
// Click the copy seed peer cluster id icon.
cy.get('#copy-seed-peer-cluster-id').click();
cy.get('#seedPeerClusterIDCopyIcon').should('exist');
cy.get('#seedPeerClusterIDTooltip').should('not.exist');
cy.wait(1000);
// Display successful copy icon.
cy.get('#seedPeerClusterIDCopyIcon').should('exist');
cy.get('#seedPeerClusterIDTooltip').should('not.exist');
// Let's check the copied text.
cy.window()
.its('navigator.clipboard')
.then((clip) => clip.readText())
.should('equal', '1');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: {
id: 1,
name: 'cluster-1',
bio: '',
scopes: {
idc: '',
location: '',
cidrs: null,
hostnames: null,
},
scheduler_cluster_id: 1,
seed_peer_cluster_id: 1,
scheduler_cluster_config: {
candidate_parent_limit: 4,
filter_parent_limit: 15,
job_rate_limit: 100,
},
seed_peer_cluster_config: {
load_limit: 500,
},
peer_cluster_config: {
load_limit: 200,
},
created_at: '2024-04-07T06:30:14Z',
updated_at: '2024-04-07T06:30:14Z',
is_default: true,
},
});
},
);
cy.visit('clusters/1');
});
it('unable to display breadcrumb', () => {
// Display is loading.
cy.get('[data-testid="cluster-loading"]').should('be.exist');
cy.url().should('include', '/clusters/1');
cy.get('.MuiBreadcrumbs-ol > :nth-child(3) > .MuiTypography-root').should('be.visible').and('contain', '-');
cy.get('.MuiBreadcrumbs-ol > :nth-child(1) > .MuiTypography-root').click();
cy.url().should('include', '/clusters');
});
it('unable to display information', () => {
cy.get('#name').should('have.text', 'cluster-1');
cy.get('#description').should('have.text', '-');
cy.get('#default').should('have.text', 'Yes');
cy.get('#scheduler-cluster-id').should('have.text', '1');
cy.get('#seed-peer-cluster-id').should('have.text', '1');
});
it('unable to display scopes', () => {
// location should be empty.
cy.get('#no-location').should('have.text', '-');
// idc should be empty.
cy.get('#idc').should('not.exist');
cy.get('#no-idc').should('have.text', '-');
cy.get('#idc-total').should('have.text', 'Total: 0');
// cidrs should be empty..
cy.get('#cidrs').should('not.exist');
cy.get('#no-cidrs').should('have.text', '-');
cy.get('#cidrs-total').should('have.text', 'Total: 0');
// hostnames should be empty..
cy.get('#hostnames').should('not.exist');
cy.get('#no-hostnames').should('have.text', '-');
cy.get('#hostnames-total').should('have.text', 'Total: 0');
});
it('unable to display config', () => {
cy.get('#seed-peer-load-limit').should('have.text', 500);
cy.get('#peer-load-limit').should('have.text', 200);
cy.get('#candidate-parent-limit').should('have.text', 4);
cy.get('#filter-parent-limit').should('be.visible').and('have.text', 15);
cy.get('#job-rate-limit').should('have.text', 100);
});
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('clusters/1');
// Display is loading.
cy.get('[data-testid="cluster-loading"]').should('be.exist');
// An error message should be displayed.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close the error message prompt.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
describe('delete', () => {
beforeEach(() => {
cy.visit('/clusters');
});
it('can delete the cluster', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
statusCode: 200,
body: deleteCluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000&seed_peer_cluster_id=10',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000&scheduler_cluster_id=10',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
// Display the total number of clusters and the default number.
cy.get('#total-clusters').should('be.visible').and('contain', 37);
cy.get('#default-clusters').should('be.visible').and('contain', 13);
// Choose a cluster without scheduler and seed peer.
cy.get('#cluster-name-10').should('be.visible').and('contain', 'cluster-10');
cy.get('#cluster-name-10').click();
cy.get('#name').scrollIntoView();
cy.get('#name').should('be.visible').and('contain', 'cluster-10');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: deleteClusters,
});
},
);
cy.get('#delete-cluster').click();
cy.get('#cancelDeleteCluster').click();
cy.get('#delete-cluster').click();
// Confirm delete.
cy.get('#deleteCluster').click();
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
cy.get('#cluster-name-10').should('not.exist');
// Display the total number of clusters after deletion.
cy.get('#total-clusters').should('be.visible').and('contain', 36);
// Display the default number after deletion.
cy.get('#default-clusters').should('be.visible').and('contain', 12);
});
it('cluster cannot be deleted if scheduler and seed nodes exist in the cluster', () => {
cy.get('#cluster-id-1').should('be.visible').and('contain', '1');
cy.get('#cluster-name-1').click();
cy.get('#name').scrollIntoView().should('be.visible').and('contain', 'cluster-1');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 500,
body: { message: 'scheduler cluster exists scheduler' },
});
},
);
// Click the delete button.
cy.get('#delete-cluster').click();
cy.get('#deleteCluster').click();
// An error message should be displayed.
cy.get('.MuiAlert-message').should('have.text', 'scheduler cluster exists scheduler');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
statusCode: 200,
body: deleteCluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000&seed_peer_cluster_id=10',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000&scheduler_cluster_id=10',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
// Choose a cluster without scheduler and seed peer.
cy.get('#cluster-name-10').should('be.visible').and('contain', 'cluster-10');
cy.get('#cluster-name-10').click();
cy.get('#name').scrollIntoView().should('be.visible').and('contain', 'cluster-10');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Click the delete button.
cy.get('#delete-cluster').click();
cy.get('#deleteCluster').click();
// An error message should be displayed.
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
});
it('try to delete cluster with guest user', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
statusCode: 200,
body: deleteCluster,
});
},
);
cy.guestSignin();
// The cluster name should be cluster-10.
cy.get('#cluster-name-10').should('be.visible').and('contain', 'cluster-10');
cy.get('#cluster-name-10').click();
cy.get('#name').scrollIntoView().should('be.visible').and('contain', 'cluster-10');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/clusters/10',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
},
);
cy.get('#delete-cluster').click();
// Click the Confirm Deletion button.
cy.get('#deleteCluster').click();
// An error message should be displayed.
cy.get('.MuiAlert-message').should('have.text', 'permission deny');
});
});
});

View File

@ -0,0 +1,479 @@
import clusters from '../../fixtures/clusters/clusters.json';
import seedPeers from '../../fixtures/seed-peers/seed-peers.json';
import schedulers from '../../fixtures/schedulers/schedulers.json';
describe('Clusters', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: seedPeers,
});
},
);
cy.visit('/clusters');
cy.viewport(1440, 1480);
});
describe('when data is loaded', () => {
it('display the total number of clusters and the default number', () => {
// Click the create cluster button.
cy.get('#create-cluster').click();
// Then I see that the current page is the create cluster!
cy.url().should('include', '/clusters/new');
cy.get('#cancel').click();
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
cy.get('[data-testid="isloading"]').should('be.exist');
// Check total clusters.
cy.get('#total-clusters').should('be.visible').and('contain', '37');
// Check total default clusters.
cy.get('#default-clusters').should('be.visible').and('contain', '13');
cy.get('[data-testid="isloading"]').should('not.exist');
});
it('display the total number of schedulers and the active number', () => {
cy.get('#total-schedulers').should('be.visible').and('contain', '12');
cy.get('#active-schedulers').should('be.visible').and('contain', '4');
});
it('display the total number of seed peers and the active number', () => {
cy.get('#total-seed-peer').should('be.visible').and('contain', '12');
cy.get('#active-seed-peer').should('be.visible').and('contain', '8');
});
it('can display clusters card', () => {
// Display the card component.
cy.get('#clusters').should('exist');
// Show Default background color.
cy.get('#default-cluster-1')
.should('be.visible')
.and('contain', 'Default')
.and('have.css', 'background-color', 'rgb(0, 129, 112)');
// Show cluster name.
cy.get('#cluster-name-1').should('be.visible').and('contain', 'cluster-1');
// Show cluster description.
cy.get('#cluster-description-1')
.should('be.visible')
.and(
'contain',
'Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.',
);
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Show Non-Default cluster.
cy.get('#cluster-name-2').should('be.visible').and('contain', 'cluster-2');
// Show Non-Default background color.
cy.get('#default-cluster-2')
.should('be.visible')
.and('contain', 'Non-Default')
.and('have.css', 'background-color', 'rgb(93, 95, 97)');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: null,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.visit('/clusters');
});
it('display the total number of clusters and the default number', () => {
cy.get('#total-clusters').should('be.visible').and('contain', '0');
cy.get('#default-clusters').should('be.visible').and('contain', '0');
});
it('display the total number of schedulers and the active number', () => {
cy.get('#total-schedulers').should('be.visible').and('contain', '0');
cy.get('#default-clusters').should('be.visible').and('contain', '0');
});
it('display the total number of seed peers and the active number', () => {
cy.get('#total-seed-peer').should('be.visible').and('contain', '0');
cy.get('#active-seed-peer').should('be.visible').and('contain', '0');
});
it('cluster card should present an empty status', () => {
cy.get('#clusters').should('not.exist');
// Shouldn't render pagination buttons.
cy.get('#clusterPagination > .MuiPagination-ul').should('not.exist');
});
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
// Check number of pagination.
cy.get('#clusterPagination > .MuiPagination-ul').children().should('have.length', 7);
// Show cluster name.
cy.get('#cluster-name-1').should('be.visible').and('contain', 'cluster-1');
});
it('when pagination changes, different page results are rendered', () => {
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Display last page cluster information.
cy.get('#cluster-id-8').should('be.visible').and('contain', '8');
// Display cluster information.
cy.get('#default-cluster-8')
.should('be.visible')
.and('contain', 'Non-Default')
.and('have.css', 'background-color', 'rgb(93, 95, 97)');
cy.get('#cluster-name-8').should('be.visible').and('contain', 'cluster-8');
cy.get('#cluster-description-8')
.should('be.visible')
.and(
'contain',
'Cluster-8 is a high-performance computing cluster located in China, specifically in Jiangsu data centers.',
);
// Check the current page number.
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#cluster-name-8').should('be.visible').and('contain', 'cluster-8');
// Check the current page number.
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Refresh page.
cy.reload().then(() => {
cy.wait(2000);
});
// Check if the page number has been reset.
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#cluster-name-8').should('be.visible').and('contain', 'cluster-8');
});
it('when returning to the previous page, pagination and results remain unchanged', () => {
// Go to the next page.
cy.get(':nth-child(7) > .MuiButtonBase-root').click();
// Check if the page number has been reset.
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#cluster-name-23').should('have.text', 'cluster-23');
// Go to the next page.
cy.get(':nth-child(7) > .MuiButtonBase-root').click();
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '3');
cy.get('#cluster-name-13').should('have.text', 'cluster-13');
cy.get('#cluster-name-23').should('not.exist');
// Go to the next page.
cy.get(':nth-child(7) > .MuiButtonBase-root').click();
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '4');
cy.get('#cluster-name-25').should('have.text', 'cluster-25');
cy.get('#cluster-name-13').should('not.exist');
// Go to the last page.
cy.get(':nth-child(7) > .MuiButtonBase-root').click();
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '5');
cy.get('#clustersCard').children().should('have.length', 1);
cy.get('#cluster-name-37').should('have.text', 'cluster-37');
// Go to 2 page.
cy.get('.MuiPagination-ul > :nth-child(3)').click();
cy.get('#cluster-name-8').should('be.visible').and('contain', 'cluster-8');
// Go to show cluster page.
cy.get('#cluster-name-8').click();
// Then I see that the current page is the show cluster.
cy.url().should('include', '/clusters/8');
// Go back to the last page。
cy.go('back');
// Check the current page number.
cy.get('#clusterPagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#cluster-name-8').should('be.visible').and('contain', 'cluster-8');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.intercept({ method: 'GET', url: '/api/v1/seed-peers?page=1&per_page=10000000' }, (req) => {
req.reply({
forceNetworkError: true,
});
});
cy.intercept({ method: 'GET', url: '/api/v1/schedulers?page=1&per_page=10000000' }, (req) => {
req.reply({
forceNetworkError: true,
});
});
cy.visit('/clusters');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('display the total number of clusters and the default number', () => {
cy.get('#total-clusters').should('be.visible').and('contain', '0');
cy.get('#clusterPagination > .MuiPagination-ul').should('not.exist');
cy.get('#default-clusters').should('be.visible').and('contain', '0');
});
it('display the total number of schedulers and the active number', () => {
cy.get('#total-schedulers').should('be.visible').and('contain', '0');
cy.get('#default-clusters').should('be.visible').and('contain', '0');
});
it('display the total number of seed peers and the active number', () => {
cy.get('#total-seed-peer').should('be.visible').and('contain', '0');
cy.get('#active-seed-peer').should('be.visible').and('contain', '0');
});
it('cluster card should present an empty status', () => {
// No clusters.
cy.get('#clusters').should('not.exist');
// No pagination.
cy.get('#clusterPagination > .MuiPagination-ul').should('not.exist');
});
});
describe('search', () => {
it('should search cluster name', () => {
cy.get('#search-wrapper').type('cluster-10');
// Then I see that the current page is the /clusters/1?search=cluster-10!
cy.url().should('include', '/clusters?search=cluster-10');
cy.get('#clusterPagination > .MuiPagination-ul').should('not.exist');
cy.get('#clustersCard').should('exist').children().should('have.length', 1);
cy.get('#cluster-name-10').should('have.text', 'cluster-10');
// Clear search box.
cy.get('#search-wrapper').clear();
// If the search is empty, all clusters will be displayed.
cy.get('#search-wrapper').type('{enter}');
cy.get('#clusterPagination > .MuiPagination-ul').should('exist');
// Check number of pagination.
cy.get('#clusterPagination > .MuiPagination-ul').children().should('have.length', 7);
cy.get('#cluster-name-1').should('be.visible').and('contain', 'cluster-1');
cy.get('#cluster-name-22').should('be.visible').and('contain', 'cluster-22');
});
it('should search cluster name and show no results', () => {
cy.get('#search-wrapper').type('cluster-47');
// No clusters card.
cy.get('#clustersCard').should('not.exist');
// Pagination has been hidden.
cy.get('#clusterPagination > .MuiPagination-ul').should('not.exist');
cy.get('#no-clusters').should('be.visible');
cy.get('#no-results').should('contain', '"cluster-47"');
});
it('should be queried based on the query string', () => {
cy.visit('/clusters/?search=cluster-2');
// The content of the input box is displayed as cluster-2.
cy.get('#search-wrapper').should('have.value', 'cluster-2');
cy.get('#clustersCard').should('exist').children().should('have.length', 9);
});
it('should search for cluster name and switch paging', () => {
cy.get('#search-wrapper').type('cluster');
// Go to 2 page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#clustersCard').should('exist').children().should('have.length', 9);
// Check the URL.
cy.url().should('include', '/clusters?search=cluster&page=2');
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(6) > .MuiButtonBase-root').click();
cy.get('#clustersCard').should('exist').children().should('have.length', 1);
// Check the URL.
cy.url().should('include', '/clusters?search=cluster&page=5');
// Go to the first page.
cy.get('.MuiPagination-ul > :nth-child(2) > .MuiButtonBase-root').click();
// Check the URL.
cy.url().should('include', '/clusters?search=cluster');
// Go to 2 page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#search-wrapper').type('-2');
// Check number of pagination.
cy.get('#clusterPagination > .MuiPagination-ul').children().should('have.length', 4);
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the URL.
cy.url().should('include', '/clusters?search=cluster-2&page=2');
});
});
it('call onChange when changing page size', () => {
// The viewport will now be changed to 1440px x 1080px
cy.viewport(1440, 1080);
// Check if the number of page size is 9.
cy.get('#clustersCard').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1600px x 1080px
cy.viewport(1600, 1080);
cy.wait(1000);
// Check if the number of page size is 9.
cy.get('#clustersCard').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1920px x 1080px
cy.viewport(1920, 1080);
cy.wait(1000);
// Check if the number of page size is 12.
cy.get('#clustersCard').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2048px x 1080px
cy.viewport(2048, 1080);
cy.wait(1000);
// Check if the number of page size is 12.
cy.get('#clustersCard').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2560px x 1080px
cy.viewport(2560, 1080);
cy.wait(1000);
// Check if the number of page size is 15.
cy.get('#clustersCard').should('exist').children().should('have.length', 15);
});
});

View File

@ -0,0 +1,450 @@
import clusters from '../../fixtures/clusters/clusters.json';
import seedPeers from '../../fixtures/seed-peers/seed-peers.json';
import schedulers from '../../fixtures/schedulers/schedulers.json';
import createClusters from '../../fixtures/clusters/create-clusters.json';
import createCluster from '../../fixtures/clusters/create-cluster.json';
import _ from 'lodash';
describe('Create cluster', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: seedPeers,
});
},
);
cy.signin();
cy.visit('/clusters/new');
cy.viewport(1440, 1080);
});
it('can create cluster', () => {
cy.visit('/clusters');
// Show number of cluster.
cy.get('#total-clusters').should('be.visible').and('contain', '37');
// Show number of cluster default.
cy.get('#default-clusters').should('be.visible').and('contain', '13');
// Click the `ADD CLUSTER` button.
cy.get('.clusters_clusterTitle__5Lhnw > .MuiButtonBase-root').click();
cy.url().should('include', '/clusters/new');
// Add Information.
cy.get('.PrivateSwitchBase-input').click();
cy.get('#name').type('cluster-17');
cy.get('#description').type('Add new cluster case');
cy.get('#location').type('China|Hang|Zhou');
// Add idc.
cy.get('#idc').type('hz{enter}');
cy.get('#idc').type('sh{enter}');
// Add cidrs.
cy.get('#cidrs').click();
cy.contains('li', '10.0.0.0/8').click();
cy.get('#cidrs').click();
cy.contains('li', '172.16.0.0/12').click();
cy.get('#cidrs').click();
cy.contains('li', '192.168.0.0/16').click();
// Add config.
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('10');
cy.intercept(
{
method: 'POST',
url: '/api/v1/clusters',
},
(req) => {
req.body = '';
req.reply({
statusCode: 200,
body: createCluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: createClusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/38',
},
(req) => {
req.reply({
statusCode: 200,
body: createCluster,
});
},
);
// Click the `save` button.
cy.get('#save').click();
// Then I see that the current page is the clusters.
cy.url().should('include', '/clusters/38');
cy.get('#name').should('have.text', 'cluster-38');
cy.get('#description').should('have.text', 'Add new cluster case');
// Show Scopes.
cy.get('#location').should('have.text', 'China|Hang|Zhou');
cy.get('#idc-1').should('have.text', 'hz');
cy.get('#idc-2').should('have.text', 'sh');
cy.get('#cidrs-1').should('have.text', '10.0.0.0/8');
cy.get('#cidrs-2').should('have.text', '172.16.0.0/12');
cy.get('#cidrs-3').should('have.text', '192.168.0.0/16');
cy.get('.MuiBreadcrumbs-ol > :nth-child(1) > .MuiTypography-root').click();
// The number of clusters has been increased.
cy.get('#total-clusters').should('be.visible').and('contain', '38');
// The default number of clusters has been increased.
cy.get('#default-clusters').should('be.visible').and('contain', '14');
});
it('cannot create cluster with existing cluster', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/clusters',
},
(req) => {
req.body = {
name: 'cluster-1',
bio: '',
scopes: {
idc: '',
location: '',
cidrs: [],
},
scheduler_cluster_config: {
filter_parent_limit: 4,
filter_parent_range_limit: 40,
},
seed_peer_cluster_config: {
load_limit: 300,
},
peer_cluster_config: {
load_limit: 50,
},
is_default: true,
};
req.reply({
statusCode: 409,
body: { message: 'Conflict' },
});
},
);
cy.get('#name').type('cluster-1{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the clusters.
cy.url().should('include', '/clusters');
});
it('cannot create cluster without required attributes', () => {
cy.get('#save').click();
cy.get('#name-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 1-40.');
});
it('try to create cluster with guest user', () => {
cy.guestSignin();
cy.intercept({ method: 'POST', url: '/api/v1/clusters' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
});
cy.get('#name').type('cluster-17{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
cy.get('#cancel').click();
cy.wait(1000);
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
});
it('should handle API error response', () => {
cy.intercept({ method: 'POST', url: '/api/v1/clusters' }, (req) => {
(req.body = ''),
req.reply({
forceNetworkError: true,
});
});
cy.get('#name').type('cluster-17');
cy.get('#save').click();
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
describe('cannot create cluster with invalid attributes', () => {
it('try to verify information', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const name = _.times(41, () => _.sample(characters)).join('');
const description = _.times(401, () => _.sample(characters)).join('');
// Should display message name the validation error.
cy.get('#save').click();
// Name is a required attribute.
cy.get('#name-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 1-40.');
cy.get('#name').type(name);
// Show verification error message.
cy.get('#name-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 1-40.');
// Submit form when validation fails.
cy.get('#save').click();
// Cluster creation failed, the page is still in cluster/new.
cy.url().should('include', '/clusters/new');
cy.get('#name').clear();
// Enter the correct name.
cy.get('#name').type('cluster-12');
cy.get('#name-helper-text').should('not.exist');
// Should display message describing the validation error.
cy.get('#description').type(description);
// Show verification error message.
cy.get('#description-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-400.');
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#description').clear();
cy.get('#description').type('cluster description');
cy.get('#name-helper-text').should('not.exist');
});
it('try to verify scopes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const location = _.times(101, () => _.sample(characters)).join('');
const hostnames = _.times(31, () => _.sample(characters)).join('');
// Name is a required attribute.
cy.get('#name').type('cluster-12');
// Should display location the validation error message.
cy.get('#location').type(location);
// Show verification error message.
cy.get('#location-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-100.');
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#location').clear();
// Verification passed.
cy.get('#location').type('Beijing');
cy.get('#location-helper-text').should('not.exist');
// Should display idc the validation error message.
cy.get('#idc').type('hz');
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#idc-helper-text').should('be.visible').and('contain', `Please press ENTER to end the IDC creation.`);
cy.get('#idc').type('hz{enter}');
// Verification passed.
cy.get('#idc-helper-text').should('not.exist');
// Should display cidrs the validation error message.
cy.get('#cidrs').type('192.168.40.0/24');
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#cidrs-helper-text').should('be.visible').and('contain', `Please press ENTER to end the CIDRs creation.`);
cy.get('#cidrs').type('192.168.40.0/24{enter}');
// Verification passed.
cy.get('#cidrs-helper-text').should('not.exist');
// Should display cidrs the validation error message.
cy.get('#hostnames').type('sigma');
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#hostnames-helper-text')
.should('be.visible')
.and('contain', `Please press ENTER to end the Hostnames creation.`);
cy.get('#hostnames').type('hostname{enter}');
cy.get('#hostnames').type(hostnames);
cy.get('#hostnames-helper-text')
.should('be.visible')
.and('contain', `Fill in the characters, the length is 1-30.`);
});
it('try to verify config', () => {
// Name is a required attribute.
cy.get('#name').type('cluster-12');
// Should display seed peer load limit the validation error message.
cy.get('#seedPeerLoadLimit').invoke('val').should('eq', '2000');
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('50001');
cy.get('#seedPeerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-50000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('400');
// Verification passed.
cy.get('#seedPeerLoadLimit-helper-text').should('not.exist');
// Should display peer load limit the validation error message.
cy.get('#peerLoadLimit').invoke('val').should('eq', '200');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('2001');
cy.get('#peerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-2000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('50');
// Verification passed.
cy.get('#peerLoadLimit-helper-text').should('not.exist');
// Should display candidate parent limit the validation error message.
cy.get('#candidateParentLimit').invoke('val').should('eq', '4');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('21');
cy.get('#candidateParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-20.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('5');
cy.get('#candidateParentLimit-helper-text').should('not.exist');
// Should display filter parent limit the validation error message.
cy.get('#filterParentLimit').invoke('val').should('eq', '40');
cy.get('#filterParentLimit').clear();
// Minimum validation range not reached.
cy.get('#filterParentLimit').type('9');
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#filterParentLimit').clear();
// Maximum verification range exceeded.
cy.get('#filterParentLimit').type('1001');
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#filterParentLimit').clear();
cy.get('#filterParentLimit').type('100');
// Verification passed.
cy.get('#filterParentLimit-helper-text').should('not.exist');
// Should display filter parent limit the validation error message.
cy.get('#jobRateLimit').invoke('val').should('eq', '10');
cy.get('#jobRateLimit').clear();
// Minimum validation range not reached.
cy.get('#jobRateLimit').type('0');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#jobRateLimit').clear();
// Maximum verification range exceeded.
cy.get('#jobRateLimit').type('1000001');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/new');
cy.get('#jobRateLimit').clear();
cy.get('#jobRateLimit').type('100');
// Verification passed.
cy.get('#jobRateLimit-helper-text').should('not.exist');
});
});
});

View File

@ -0,0 +1,466 @@
import cluster from '../../fixtures/clusters/cluster/cluster.json';
import updateCluster from '../../fixtures/clusters/cluster/update-cluster.json';
import _ from 'lodash';
describe('Update cluster', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.visit('/clusters/1/edit');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
// Show cluster information.
cy.get('#name').should('contain', 'cluster-1');
cy.get('#default').should('be.checked').check({ force: true });
// Should display location.
cy.get('#location').should('have.value', 'China|Hang|Zhou');
// Should display idc.
cy.get('#idc-0').should('contain', 'Hangzhou');
cy.get('#idc-1').should('contain', 'Shanghai');
// Should display cidrs.
cy.get('#cidrs-0').should('contain', '10.0.0.0/8');
cy.get('#cidrs-1').should('contain', '192.168.0.0/16');
cy.get('#cidrs-2').should('contain', '172.16.0.0/12');
// Should display hostnames.
cy.get('#hostnames-0').should('contain', 'cluster-1');
cy.get('#hostnames-1').should('contain', 'cluster-2');
cy.get('#hostnames-2').should('contain', 'cluster-3');
// Show config.
cy.get('#seedPeerLoadLimit').should('have.value', 300);
cy.get('#peerLoadLimit').should('have.value', 51);
cy.get('#candidateParentLimit').should('have.value', 4);
cy.get('#filterParentLimit').should('have.value', 40);
cy.get('#jobRateLimit').should('have.value', 15);
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/2',
},
(req) => {
req.reply({
statusCode: 200,
body: {
id: 0,
name: '',
bio: '',
scopes: {
idc: '',
location: '',
cidrs: null,
hostnames: null,
},
scheduler_cluster_id: 1,
seed_peer_cluster_id: 1,
scheduler_cluster_config: {
candidate_parent_limit: 0,
filter_parent_limit: 0,
},
seed_peer_cluster_config: {
load_limit: 0,
},
peer_cluster_config: {
load_limit: 0,
},
created_at: '2023-03-08T02:39:03Z',
updated_at: '2023-03-08T02:39:03Z',
is_default: false,
},
});
},
);
cy.visit('/clusters/2/edit');
// Show cluster information.
cy.get('#id').should('contain', '0');
cy.get('#name').should('contain', '');
cy.get('#default').should('not.be.checked').check({ force: false });
// Location should be empty.
cy.get('#location').should('have.value', '');
// IDC should be empty.
cy.get('#idc').should('have.value', '');
// CIDRs should be empty.
cy.get('#cidrs').should('have.value', '');
// Hostname should be empty.
cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').should(
'have.value',
'',
);
// cluster config should be empty.
cy.get('#seedPeerLoadLimit').should('have.value', 0);
cy.get('#peerLoadLimit').should('have.value', 0);
cy.get('#candidateParentLimit').should('have.value', 0);
cy.get('#filterParentLimit').should('have.value', 0);
cy.get('#jobRateLimit').should('have.value', 0);
});
it('can update cluster', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
body: {},
});
});
cy.visit('/clusters/1');
// Click update cluster button.
cy.get('#update').click();
// Show cluster name.
cy.get('#name').should('be.visible').and('contain', 'cluster-1');
cy.get('#default').click();
// Update cluster description.
cy.get('#description').clear();
cy.get('#description').type('update cluster-1');
// Update cluster Scopes.
cy.get('#location').clear();
cy.get('#location').type('China|Shang|Hai');
cy.get('#idc').type('{selectall}').type('{backspace}');
cy.get('#cidrs').type('192.168.20.2{enter}');
// Update cluster Config.
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('400');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('50');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('5');
cy.get('#filterParentLimit').clear();
cy.get('#filterParentLimit').type('50');
cy.get('#jobRateLimit').clear();
cy.get('#jobRateLimit').type('20');
// Click save button.
cy.get('#save').click();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: updateCluster,
});
},
);
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
// Check whether the cluster information is updated successfully.
cy.get('#description').should('be.visible').and('contain', 'update cluster-1');
cy.get('#default').should('be.visible').and('contain', 'No');
cy.get('#cidrs').click();
cy.get('.MuiDialogContent-root > :nth-child(4)').should('be.visible').and('contain', '192.168.20.2');
cy.get('body').click('topLeft');
cy.get('#seed-peer-load-limit').scrollIntoView().should('be.visible').and('contain', '400');
cy.get('#job-rate-limit').should('be.visible').and('contain', '20');
});
it('click the `CANCEL button', () => {
cy.url().should('include', '/clusters/1/edit');
cy.get('[data-testid="isloading"]').should('be.exist');
cy.wait(1000);
cy.get('#cancel').click();
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
});
it('try to update cluster with guest user', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
});
cy.guestSignin();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
describe('should handle API error response', () => {
it('get cluster API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('error-message').should('not.exist');
});
it('update cluster API error response', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/clusters/1' }, (req) => {
(req.body = ''),
req.reply({
forceNetworkError: true,
});
});
cy.get('#description').clear();
cy.get('#description').type('update cluster-1');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
describe('cannot update cluster with invalid attributes', () => {
it('try to verify information', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const description = _.times(401, () => _.sample(characters)).join('');
cy.get('#description').clear();
cy.get('#description').type(description);
// Show verification error message.
cy.get('#description-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-400.');
// Submit form when validation fails.
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#description').clear();
// Verification passed.
cy.get('#description').type('cluster description');
});
it('try to verify scopes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const location = _.times(101, () => _.sample(characters)).join('');
// Should display location the validation error message.
cy.get('#location').type(location);
// Show verification error message.
cy.get('#location-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the length is 0-100.');
// Submit form when validation fails.
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#location').clear();
// Verification passed.
cy.get('#location').type('Beijing');
cy.get('#location-helper-text').should('not.exist');
// Should display idc the validation error message.
cy.get('#idc').type('hz');
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#idc-helper-text').should('be.visible').and('contain', `Please press ENTER to end the IDC creation.`);
// Verification passed.
cy.get('#idc').type('hz{enter}');
cy.get('#idc-helper-text').should('not.exist');
// Should display cidrs the validation error message.
cy.get('#cidrs').type('192.168.40.0/24');
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
// Show verification error message.
cy.get('#cidrs-helper-text').should('be.visible').and('contain', `Please press ENTER to end the CIDRs creation.`);
cy.get('#cidrs').type('192.168.40.0/24{enter}');
cy.get('#cidrs-helper-text').should('not.exist');
// Should display hostnames the validation error message.
cy.get('#hostnames').type('cluster-2');
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
// Show verification error message.
cy.get('#hostnames-helper-text')
.should('be.visible')
.and('contain', `Please press ENTER to end the Hostnames creation.`);
cy.get('#hostnames').type('cluster-1{enter}');
cy.get('#hostnames-helper-text').should('not.exist');
});
it('try to verify config', () => {
// Should display seed peer load limit the validation error message.
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('50001');
// Show verification error message.
cy.get('#seedPeerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-50000.`);
// Submit form when validation fails.
cy.get('#save').click();
// cluster creation failed, the page is still in cluster/new!
cy.url().should('include', '/clusters/1/edit');
cy.get('#seedPeerLoadLimit').clear();
cy.get('#seedPeerLoadLimit').type('400');
// Verification passed.
cy.get('#seedPeerLoadLimit-helper-text').should('not.exist');
// Should display peer load limit the validation error message.
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('2001');
// Show verification error message.
cy.get('#peerLoadLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 0-2000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#peerLoadLimit').clear();
cy.get('#peerLoadLimit').type('50');
// Verification passed.
cy.get('#peerLoadLimit-helper-text').should('not.exist');
// Should display candidate parent limit the validation error message.
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('21');
// Show verification error message.
cy.get('#candidateParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-20.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#candidateParentLimit').clear();
cy.get('#candidateParentLimit').type('5');
cy.get('#candidateParentLimit-helper-text').should('not.exist');
// Should display filter parent limit the validation error message.
cy.get('#filterParentLimit').clear();
// Minimum validation range not reached.
cy.get('#filterParentLimit').type('9');
// Show verification error message.
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#filterParentLimit').clear();
// Maximum verification range exceeded.
cy.get('#filterParentLimit').type('1001');
// Show verification error message.
cy.get('#filterParentLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 10-1000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#filterParentLimit').clear();
cy.get('#filterParentLimit').type('100');
// Verification passed.
cy.get('#filterParentLimit-helper-text').should('not.exist');
// Should display Job Rate Limit(requests per seconds) the validation error message.
cy.get('#jobRateLimit').invoke('val').should('eq', '15');
cy.get('#jobRateLimit').clear();
// Minimum validation range not reached.
cy.get('#jobRateLimit').type('0');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#jobRateLimit').clear();
// Maximum verification range exceeded.
cy.get('#jobRateLimit').type('1000001');
cy.get('#jobRateLimit-helper-text')
.should('be.visible')
.and('contain', `Fill in the number, the length is 1-1000000.`);
cy.get('#save').click();
cy.url().should('include', '/clusters/1/edit');
cy.get('#jobRateLimit').clear();
cy.get('#jobRateLimit').type('100');
// Verification passed.
cy.get('#jobRateLimit-helper-text').should('not.exist');
});
});
});

View File

@ -0,0 +1,247 @@
import tokens from '../../../fixtures/developer/tokens/tokens.json';
import createToken from '../../../fixtures/developer/tokens/create-token.json';
import _ from 'lodash';
describe('Create token', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: tokens,
});
},
);
cy.visit('/developer/personal-access-tokens/new');
cy.viewport(1440, 1080);
});
it('can create token', () => {
cy.visit('/developer/personal-access-tokens');
// Click the `ADD PERSONAL ACCESS TOKENS` button.
cy.get('#new-tokens-button').click();
// Then I see that the current page is the developer/personal-access-tokens/new!
cy.url().should('include', '/developer/personal-access-tokens/new');
cy.get('#name').type('root-12');
// Choose an expiration time of 60 days.
cy.get('#demo-simple-select').click();
cy.get('[data-value="60"]').click();
cy.intercept(
{
method: 'POST',
url: '/api/v1/personal-access-tokens',
},
(req) => {
req.body = {};
req.reply({
statusCode: 200,
body: {
id: 12,
created_at: '2023-12-05T11:26:32Z',
updated_at: '2023-12-05T11:26:32Z',
is_del: 0,
name: 'root-12',
bio: '',
token: 'ZjM1NzM1NGItYjYwYi00OTEyLTlmN2QtNjc5M2JhNzhiOTI3',
scopes: [],
state: 'active',
expired_at: '2033-12-02T11:26:17Z',
user_id: 2,
},
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: createToken,
});
},
);
cy.get('#save').click();
// Then I see that the current page is the developer/personal-access-tokens!
cy.url().should('include', '/developer/personal-access-tokens');
// After creation is completed, the copyable token will be displayed.
cy.get('#copy-column').should('exist');
// Click the Copy icon button.
cy.get('#copy-button').click();
// The copy icon is no longer displayed.
cy.get('#copy').should('not.exist');
// Shwo done icon.
cy.get('#done').should('exist');
// Show `copied!` text.
cy.get('.MuiTooltip-tooltip').should('exist').and('have.text', 'copied!');
// Let's check the copied text.
cy.window()
.its('navigator.clipboard')
.then((clip) => clip.readText())
.should('equal', 'ZjM1NzM1NGItYjYwYi00OTEyLTlmN2QtNjc5M2JhNzhiOTI3');
cy.wait(1000);
cy.get('#copy').should('exist');
cy.get('#done').should('not.exist');
cy.get('.MuiTooltip-tooltip').should('not.exist');
// Display successfully created token information.
cy.get('#root-12').should('be.visible').and('have.text', 'root-12');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
// When you click refresh, the replication token will not be displayed again for your security.
cy.get('#copy-column').should('not.exist');
});
it('cannot create token with existing token', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/personal-access-tokens',
},
(req) => {
req.body = {};
req.reply({
statusCode: 409,
body: { message: 'Conflict' },
});
},
);
cy.get('#name').type('root-12{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the developer/personal-access-tokens!
cy.url().should('include', '/developer/personal-access-tokens');
});
it('token cannot be created without required attributes', () => {
cy.get('#save').click();
cy.get('#name-helper-text').should('exist').and('have.text', 'Fill in the characters, the length is 1-100.');
});
it('try to create token with guest user', () => {
cy.visit('/signin');
cy.guestSignin();
cy.intercept(
{
method: 'POST',
url: '/api/v1/personal-access-tokens',
},
(req) => {
req.body = {};
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
},
);
cy.visit('/developer/personal-access-tokens/new');
// Users menu does not exist.
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
cy.get('#name').type('root-12{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/personal-access-tokens',
},
(req) => {
req.body = {};
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#name').type('root-12{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
it('cannot create token with invalid attributes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const name = _.times(101, () => _.sample(characters)).join('');
const description = _.times(401, () => _.sample(characters)).join('');
// Should name message describing the validation error.
cy.get('#name').type(name);
// Show verification error message.
cy.get('#name-helper-text').should('exist').and('have.text', 'Fill in the characters, the length is 1-100.');
// Submit form when validation fails.
cy.get('#save').click();
// Then I see that the current page is the developer/personal-access-tokens/new!
cy.url().should('include', '/developer/personal-access-tokens/new');
cy.get('#name').clear();
// Enter the correct name.
cy.get('#name').type('root-12');
// Should display message describing the validation error.
cy.get('#bio').type(description);
// Show verification error message.
cy.get('#bio-helper-text').should('exist').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#save').click();
// Then I see that the current page is the developer/personal-access-tokens/new!
cy.url().should('include', '/developer/personal-access-tokens/new');
// Check if the job checkbox is checked.
cy.get('#job').should('be.checked').check({ force: true });
// Check if the cluster checkbox is checked.
cy.get('#cluster').should('be.checked').check({ force: true });
});
});

View File

@ -0,0 +1,317 @@
import tokens from '../../../fixtures/developer/tokens/tokens.json';
import deleteToken from '../../../fixtures/developer/tokens/delete-tokens.json';
import tokenDeleteAfter from '../../../fixtures/developer/tokens/token-delete-after.json';
describe('Tokens', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: tokens,
});
},
);
cy.visit('/developer/personal-access-tokens');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#token-title').should('have.text', 'Personal access tokens');
// Show token name.
cy.get('#root-11').should('be.visible').and('have.text', 'root-11');
// Show user name.
cy.get('#user-name-11').should('contain', 'root');
// Show Expiration.
cy.get('#expired-at-11').should('be.visible').and('have.text', 'Mon, Dec 11 2023.');
// Show token information.
cy.get('#root-9').should('be.visible').and('have.text', 'root-9');
cy.get('#user-name-9').should('contain', 'jack');
cy.get('#expired-at-9').should('be.visible').and('have.text', 'Thu, Dec 1 2033.');
cy.get('#root-4').should('be.visible').and('have.text', 'root-4');
cy.get('#user-name-3').should('contain', 'lucy');
cy.get('#expired-at-4').should('be.visible').and('have.text', 'Sun, Feb 11 2024.');
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.get('#no-tokens').should('be.visible').and('have.text', `You don't have any tokens.`);
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
// No tokens list exists.
cy.get('#tokens-list').should('not.exist');
// Show You don't have any preheat tokens.
cy.get('#no-tokens').should('be.visible').and('have.text', `You don't have any tokens.`);
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
// Check number of pagination.
cy.get('#tokens-pagination > .MuiPagination-ul').children().should('have.length', 4);
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
});
it('when pagination changes, different page results are rendered', () => {
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3)').click();
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Show token name.
cy.get('#root-1').should('be.visible').and('have.text', 'root-1');
cy.get('#expired-at-1').should('be.visible').and('have.text', 'Thu, Dec 1 2033.');
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3)').click();
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Refresh page.
cy.reload().then(() => {
cy.wait(2000);
});
// Check if the page number is the last page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
});
it('when returning to the previous page, pagination and results remain unchanged', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3)').click();
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#root-1').should('have.text', 'root-1');
cy.get('#root-1').click();
// Then I see that the current page is the show update personal-access-tokens.
cy.url().should('include', '/developer/personal-access-tokens/1');
// Go back to the last page。
cy.go('back');
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#root-1').should('have.text', 'root-1');
});
});
describe('delete', () => {
it('when a token is removed, this token is the only token on the last page', () => {
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3)').click();
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Displays the name of the token that needs to be deleted.
cy.get('#root-1').should('be.visible').and('have.text', 'root-1');
// Click DELETE button.
cy.get('#delete-token-1').click();
// Click cancel button.
cy.get('#cancel').click();
cy.get('#delete-token-1').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/personal-access-tokens/1',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply((res) => {
res.setDelay(1000);
res.send({
statusCode: 200,
body: deleteToken,
});
});
},
);
// Confirm delete.
cy.get('#delete').click();
// Show isloading.
cy.get('[data-testid="isloading"]').should('be.exist');
// Delete success message.
cy.get('.MuiAlert-message').should('have.text', 'Submission successful!');
cy.get('[data-testid="isloading"]').should('not.exist');
// Check if the token exists.
cy.get('#root-1').should('not.exist');
// Pagination does not exist.
cy.get('#tokens-pagination > .MuiPagination-ul').should('not.exist');
});
it('When removing a token, there is only one token for the next page', () => {
// Check the current page number.
cy.get('#tokens-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
// Displays the name of the token that needs to be deleted.
cy.get('#root-11').should('be.visible').and('have.text', 'root-11');
cy.get('#delete-token-11').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: tokenDeleteAfter,
});
},
).as('delete');
cy.get('#delete').click();
cy.wait('@delete');
// Delete success message.
cy.get('.MuiAlert-message').should('have.text', 'Submission successful!');
// Check if the token exists.
cy.get('#root-11').should('not.exist');
// Pagination does not exist.
cy.get('#tokens-pagination > .MuiPagination-ul').should('not.exist');
});
it('try to delete token using guest user', () => {
cy.guestSignin();
cy.get('#delete-token-11').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
},
);
cy.get('#delete').click();
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'permission deny');
});
it('try to delete token using guest user', () => {
cy.guestSignin();
cy.get('#delete-token-11').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#delete').click();
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
});
});
});

View File

@ -0,0 +1,299 @@
import tokens from '../../../fixtures/developer/tokens/tokens.json';
import token from '../../../fixtures/developer/tokens/token.json';
import updateToken from '../../../fixtures/developer/tokens/update-token.json';
import _ from 'lodash';
describe('Update token', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: tokens,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.reply({
statusCode: 200,
body: token,
});
},
);
cy.visit('/developer/personal-access-tokens/11');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
// Check the token ID.
cy.get('#id').should('be.visible').and('contain', '11');
// Check the token name.
cy.get('#name').should('be.visible').and('contain', 'root-11');
// Check the token description.
cy.get('#bio').should('have.value', 'root-11 token, used to control of cluster');
// Check that the job checkbox.
cy.get('#job').should('not.be.checked');
// Check that the cluster checkbox.
cy.get('#cluster').should('be.checked').check({ force: true });
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
// Check the token ID.
cy.get('#id').should('have.text', '-');
// Check the token name.
cy.get('#name').should('have.text', '-');
// Check the token description.
cy.get('#bio').should('have.value', '');
// Check that the job checkbox.
cy.get('#job').should('not.be.checked');
// Check that the cluster checkbox.
cy.get('#cluster').should('not.be.checked');
});
it('can update token', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/personal-access-tokens/11' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
body: {
id: 2,
created_at: '2023-12-06T03:39:55Z',
updated_at: '2023-12-06T06:33:29.066Z',
is_del: 0,
name: 'root-11',
bio: 'update root-11',
token: 'ODhlMjFkY2UtM2Y1ZS00ZTVmLThkMzYtMzE2MzhiNmQxODlj',
scopes: ['preheat'],
state: 'active',
expired_at: '2033-12-03T06:33:27.032Z',
user_id: 1,
},
});
});
cy.visit('/developer/personal-access-tokens');
// Show token name.
cy.get('#root-11').should('be.visible').and('have.text', 'root-11');
// Click token name.
cy.get('#root-11').click();
// Then I see that the current page is the developer/personal-access-tokens/11!
cy.url().should('include', '/developer/personal-access-tokens/11');
cy.get('#name').should('be.visible').and('contain', 'root-11');
// Update token description.
cy.get('#bio').clear();
cy.get('#bio').type('update root-11');
// Choose an expiration time of 10 years.
cy.get('#demo-simple-select').click();
cy.get('[data-value="3650"]').click();
// Check if the job checkbox is checked.
cy.get('#job').click();
cy.get('#job').should('be.checked').check({ force: true });
// Check if the cluster checkbox is checked.
cy.get('#cluster').click();
cy.get('#cluster').should('not.be.checked');
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: updateToken,
});
},
);
cy.get('#save').click();
// Check for updated expiration date.
cy.get('#expired-at-11').should('be.visible').and('have.text', 'Sat, Dec 3 2033.');
// Then I see that the current page is the developer/personal-access-tokens!
cy.url().should('include', '/developer/personal-access-tokens');
// After update is completed, the copyable token will be displayed.
cy.get('#copy-column').should('exist');
// Click the Copy icon button.
cy.get('#copy-button').click();
// Let's check the copied text.
cy.window()
.its('navigator.clipboard')
.then((clip) => clip.readText())
.should('equal', 'ODhlMjFkY2UtM2Y1ZS00ZTVmLThkMzYtMzE2MzhiNmQxODlj');
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the personal-access-tokens!
cy.url().should('include', '/developer/personal-access-tokens');
});
it('unable to update token without required attributes', () => {
cy.get('#save').click();
cy.get('.MuiFormHelperText-root').should('exist').and('have.text', 'Please select an option.');
});
it('try to update token with guest user', () => {
cy.visit('/signin');
cy.guestSignin();
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.body = {};
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
},
);
cy.visit('/developer/personal-access-tokens/11');
// Choose an expiration time of 60 days.
cy.get('#demo-simple-select').click();
cy.get('[data-value="60"]').click();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
describe('should handle API error response', () => {
it('get token API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/personal-access-tokens/10',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/developer/personal-access-tokens/10');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('#id').should('be.visible').and('contain', '-');
});
it('update token API error response', () => {
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/personal-access-tokens/11',
},
(req) => {
req.body = {};
req.reply({
forceNetworkError: true,
});
},
);
// Choose an expiration time of 60 days.
cy.get('#demo-simple-select').click();
cy.get('[data-value="60"]').click();
cy.get('#save').click();
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
it('cannot create token with invalid attributes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const description = _.times(401, () => _.sample(characters)).join('');
// Submit form when validation fails.
cy.get('#save').click();
// Then I see that the current page is the developer/personal-access-tokens/new!
cy.url().should('include', '/developer/personal-access-tokens/11');
// Choose an expiration time of 60 days.
cy.get('#demo-simple-select').click();
cy.get('[data-value="60"]').click();
// Should display message describing the validation error.
cy.get('#bio').type(description);
// Show verification error message.
cy.get('#bio-helper-text').should('exist').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#save').click();
// Then I see that the current page is the developer/personal-access-tokens/new!
cy.url().should('include', '/developer/personal-access-tokens/11');
cy.get('#bio').clear();
cy.get('#bio').type('update token');
// Verification passed.
cy.get('#bio-helper-text').should('not.exist');
// Check that the job checkbox.
cy.get('#job').should('not.be.checked').check({ force: true });
// Check that the cluster checkbox.
cy.get('#cluster').should('be.checked').check({ force: true });
});
});

262
cypress/e2e/gc/audit.cy.ts Normal file
View File

@ -0,0 +1,262 @@
import config from '../../fixtures/gc/config.json';
import history from '../../fixtures/gc/history.json';
import executeGC from '../../fixtures/gc/execute-gc.json';
import updateConfig from '../../fixtures/gc/update-config.json';
describe('audit', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply((res: any) => {
res.send(200, config);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply((res: any) => {
res.send(200, history);
});
},
);
cy.viewport(1440, 1080);
cy.visit('/gc/audit');
});
it('when data is loaded', () => {
// Show audit ttl.
cy.get('#audit-ttl').should('have.text', '3 days');
// Show gc history.
cy.get('#history').should('have.text', '11');
cy.get('#pagination').should('exist');
// Display gc history information.
cy.get('#trigger-119').should('have.text', 'Manual');
cy.get('#ttl-119').should('have.text', '2 days');
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#id-97').should('have.text', 97);
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply({ statusCode: 200, body: [] });
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply({ statusCode: 200, body: [] });
},
);
cy.get('#audit-ttl').should('have.text', '-');
cy.get('#history').should('have.text', '0');
cy.get('#last-completed').should('have.text', '-');
cy.get('#pagination').should('not.exist');
// no history.
cy.get('#no-history').should('have.text', `You don't have GC history.`);
});
it('can execute GC', () => {
cy.get('#execute-gc').click();
cy.get('#execute').should('exist');
// Click cancel button.
cy.get('#cancel-execute').click();
cy.get('#execute').should('not.exist');
cy.get('#execute-gc').click();
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
async (req) => {
await new Promise((resolve) => setTimeout(resolve, 2000));
req.reply({
statusCode: 200,
body: executeGC,
});
},
);
// Click execute button.
cy.get('#save-execute').click();
cy.get('#execute-loading').should('exist');
cy.wait(1000);
cy.get('#success-execute-gc').should('exist');
// Show number of recycled audit log.
cy.get('.MuiAlert-message').should('have.text', 'You have successfully recycled 10 audit logs!');
cy.get('#close-execut-icon').click();
cy.get('#execute').should('not.exist');
});
it('can not execute GC', () => {
cy.get('#execute-gc').click();
cy.get('#execute').should('exist');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
async (req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Click execute button.
cy.get('#save-execute').click();
cy.get('#execute-error').should('exist');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply({ forceNetworkError: true });
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply({ forceNetworkError: true });
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('can update ttl', () => {
cy.get('#audit-ttl').should('have.text', '3 days');
cy.get('#update').click();
cy.get('#audit-ttl-input').clear();
cy.get('#audit-ttl-input').type('100');
cy.get('#ttl-error').should(
'have.text',
'Fill in the number, and the time value must be greater than 0 and less than 30 days.',
);
cy.get('#audit-unit').click();
cy.get('[data-value="hours"]').click();
cy.get('#audit-ttl-input').clear();
cy.get('#audit-ttl-input').type('2000');
// Shou error.
cy.get('#ttl-error').should('have.text', 'Fill in the number, the length is 1-1000.');
cy.get('#audit-ttl-input').clear();
cy.get('#audit-ttl-input').type('1');
cy.get('#audit-ttl-input').clear();
cy.get('#audit-ttl-input').type('1');
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/configs/1',
},
async (req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply((res: any) => {
res.send(200, updateConfig);
});
},
);
cy.get('#save-ttl').click();
cy.get('.MuiAlert-message').should('have.text', 'Submission successful!');
cy.get('#audit-ttl').should('have.text', '21 days');
});
it('can no update ttl', () => {
cy.get('#audit-ttl').should('have.text', '3 days');
cy.get('#update').click();
cy.get('#audit-ttl-input').clear();
cy.get('#audit-ttl-input').type('1');
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/configs/1',
},
async (req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#save-ttl').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});

259
cypress/e2e/gc/job.cy.ts Normal file
View File

@ -0,0 +1,259 @@
import config from '../../fixtures/gc/config.json';
import history from '../../fixtures/gc/history.json';
import executeGC from '../../fixtures/gc/execute-gc.json';
import updateConfig from '../../fixtures/gc/update-config.json';
describe('audit', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply((res: any) => {
res.send(200, config);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply((res: any) => {
res.send(200, history);
});
},
);
cy.viewport(1440, 1080);
cy.visit('/gc/job');
});
it('when data is loaded', () => {
// Displays the Job ttl.
cy.get('#job-ttl').should('have.text', '13 days');
// Displays the GC history.
cy.get('#history').should('have.text', '13');
cy.get('#pagination').should('exist');
// Display gc history information.
cy.get('#trigger-117').should('have.text', 'Manual');
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Display gc history information.
cy.get('#id-101').should('have.text', 101);
cy.get('#ttl-101').should('have.text', '13 days');
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply({ statusCode: 200, body: [] });
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply({ statusCode: 200, body: [] });
},
);
cy.get('#job-ttl').should('have.text', '-');
cy.get('#history').should('have.text', '0');
cy.get('#last-completed').should('have.text', '-');
cy.get('#pagination').should('not.exist');
// no history.
cy.get('#no-history').should('have.text', `You don't have GC history.`);
});
it('can execute GC', () => {
cy.get('#execute-gc').click();
cy.get('#execute').should('exist');
// Click cancel button.
cy.get('#cancel-execute').click();
cy.get('#execute').should('not.exist');
cy.get('#execute-gc').click();
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
async (req) => {
await new Promise((resolve) => setTimeout(resolve, 2000));
req.reply({
statusCode: 200,
body: executeGC,
});
},
);
// Click execute button.
cy.get('#save-execute').click();
cy.get('#execute-loading').should('exist');
cy.wait(1000);
cy.get('#success-execute-gc').should('exist');
// Show number of recycled audit log.
cy.get('.MuiAlert-message').should('have.text', 'You have successfully recycled 10 job!');
cy.get('#close-execut-icon').click();
cy.get('#execute').should('not.exist');
});
it('can not execute GC', () => {
cy.get('#execute-gc').click();
cy.get('#execute').should('exist');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
async (req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Click execute button.
cy.get('#save-execute').click();
cy.get('#execute-error').should('exist');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply({ forceNetworkError: true });
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10000000&type=gc',
},
(req) => {
req.reply({ forceNetworkError: true });
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('can update ttl', () => {
cy.get('#job-ttl').should('have.text', '13 days');
cy.get('#update').click();
cy.get('#job-ttl-input').clear();
cy.get('#job-ttl-input').type('100');
cy.get('#ttl-error').should(
'have.text',
'Fill in the number, and the time value must be greater than 0 and less than 30 days.',
);
cy.get('#job-unit').click();
cy.get('[data-value="hours"]').click();
cy.get('#job-ttl-input').clear();
cy.get('#job-ttl-input').type('2000');
// Shou error.
cy.get('#ttl-error').should('have.text', 'Fill in the number, the length is 1-1000.');
cy.get('#job-ttl-input').clear();
cy.get('#job-ttl-input').type('1');
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/configs/1',
},
async (req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/configs?page=1&per_page=10000000',
},
(req) => {
req.reply((res: any) => {
res.send(200, updateConfig);
});
},
);
cy.get('#save-ttl').click();
cy.get('.MuiAlert-message').should('have.text', 'Submission successful!');
cy.get('#job-ttl').should('have.text', '21 days');
});
it('can no update ttl', () => {
cy.get('#job-ttl').should('have.text', '13 days');
cy.get('#update').click();
cy.get('#job-ttl-input').clear();
cy.get('#job-ttl-input').type('1');
cy.intercept(
{
method: 'PATCH',
url: '/api/v1/configs/1',
},
async (req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#save-ttl').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});

View File

@ -0,0 +1,858 @@
import clusters from '../../../fixtures/clusters/clusters.json';
import preheats from '../../../fixtures/job/preheats/preheats.json';
import createPreheatFile from '../../../fixtures/job/preheats/create-preheat-file.json';
import createPreheatImage from '../../../fixtures/job/preheats/create-preheat-image.json';
import _ from 'lodash';
describe('Create preheat', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=next,</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=first,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=last',
};
res.send(200, preheats, responseHeaders);
});
},
);
cy.visit('/jobs/preheats/new');
cy.viewport(1440, 1080);
});
it('can create an All Peers task with a preheat scope of 30%', () => {
// By default, there is no percentage and count.
cy.get('#count-or-percentage').should('not.exist');
// Scope select all peers.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
cy.get('#all').should('have.text', `Preheat to each peer in the P2P cluster.`);
cy.get('#count-or-percentage').should('exist');
cy.get('#radio-percentage').click();
cy.get('#percentage').click(100, 10);
// Select count.
cy.get('#radio-count').click();
cy.get('#count').click();
cy.get('#count').type('50');
// Scope select all seed peers.
cy.get('#select-scope').click();
cy.get('#all_seed_peers').click();
cy.get('#all').should('have.text', `Preheat to each seed peer in the P2P cluster.`);
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the preheats page!
cy.url().should('include', '/jobs/preheats');
});
it('can create preheat file', () => {
cy.visit('/jobs/preheats');
cy.get('#new-preheat').click();
cy.url().should('include', '/jobs/preheats/new');
cy.get('.MuiTypography-h5').should('have.text', 'Create Preheat');
cy.get('#description').type('create preheat');
// Select a cluster.
cy.get('#cluster').type('cluster-1{enter}');
cy.get('body').click('topLeft');
cy.get('#pieceLength').type('5');
// Select a scope.
cy.get('#select-scope').click();
cy.get('#all_seed_peers').click();
// Select a ips.
cy.get('#radio-ips').click();
cy.get('#ips').type('10.0.0.8{enter}');
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#add-url').click();
cy.get('#url-0').type('https://example.com/path/to/file/url-1');
// Add tag.
cy.get('#tag').type('tag-1');
// Add application.
cy.get('#application').type('application-1');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatFile,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/12',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatFile,
});
},
);
cy.get('#save').click();
// Then I see that the current page is the preheats page!
cy.url().should('include', '/jobs/preheats/12');
// Displays successfully added preheat task.
cy.get('#description').should('have.text', 'create preheat');
cy.get('#status').should('have.text', 'PENDING');
cy.get('#url-0').should('have.text', 'https://example.com/path/to/file/url-1');
cy.get('#url-1').should('have.text', 'https://example.com/path/to/file');
cy.get('#id').should('have.text', 12);
cy.get('#piece-length').should('have.text', '5 MiB');
cy.get('#scope').should('have.text', 'All Seed Peers');
cy.get('#tag').should('have.text', 'tag-1');
cy.get('#application').should('have.text', 'application-1');
});
it('can create preheat image', () => {
cy.get('#preheat-image').click();
cy.get('#description').type('create preheat');
// Select a cluster.
cy.get('#cluster').type('cluster-1{enter}');
cy.get('body').click('topLeft');
cy.get('#pieceLength').type('5');
// Select a scope.
cy.get('#select-scope').click();
cy.get('#all_seed_peers').click();
cy.get('#radio-ips').click();
cy.get('#ips').type('10.0.0.8{enter}');
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#username').type('root');
cy.get('#password').type('password');
// Add tag.
cy.get('#tag').type('tag-1');
// Add application.
cy.get('#application').type('application-1');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatImage,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/13',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatImage,
});
},
);
cy.get('#save').click();
// Should show preheat details.
cy.get('#description').should('have.text', 'create preheat');
cy.get('#status').should('have.text', 'PENDING');
cy.get('#type').should('have.text', 'Image');
cy.get('#url').should('have.text', 'https://example.com/manifests/v2.1.0');
cy.get('#id').should('have.text', 13);
cy.get('#platform').should('have.text', 'Linux AMD64');
cy.get('#piece-length').should('have.text', '-');
cy.get('#scope').should('have.text', 'Single Seed Peer');
cy.get('#tag').should('have.text', 'tag-1');
cy.get('#application').should('have.text', 'application-1');
cy.get('#ips-0').should('have.text', '10.244.4.5');
cy.get('#ips-1').should('have.text', '10.244.4.3');
});
it('cannot to use cluster without scheduler for preheat', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 500,
body: { message: 'candidate schedulers not found' },
});
},
);
cy.get('#cluster').click();
cy.contains('li', 'cluster-2').click();
cy.get('body').click('topLeft');
// Select a scope.
cy.get('#select-scope').click();
cy.get('body').click('topLeft');
cy.get('#select-scope').click();
cy.get('#all_seed_peers').click();
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'candidate schedulers not found');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('cannot create preheat task without required attributes', () => {
cy.get('#save').click();
cy.get('#cluster-helper-text').should('be.visible').and('have.text', 'Select at least one option.');
cy.get('#url-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 1-1000.');
});
it('try to create preheat with guest user', () => {
cy.guestSignin();
cy.visit('/jobs/preheats/new');
// Check if the guest user is signin in.
cy.get('[href="/users"]').should('not.exist');
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
// Select a scope.
cy.get('#select-scope').click();
cy.get('#single_seed_peer').click();
// Add ure.
cy.get('#url').type('https://example.com/path/to/file');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatFile,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/12',
},
(req) => {
req.reply({
statusCode: 200,
body: createPreheatFile,
});
},
);
cy.get('#save').click();
// Then I see that the current page is the preheats page!
cy.url().should('include', '/jobs/preheats/12');
// Displays successfully added preheat task.
cy.get('#description').should('have.text', 'create preheat');
cy.get('#status').should('have.text', 'PENDING');
cy.get('#id').should('have.text', 12);
cy.get('#piece-length').should('have.text', '5 MiB');
});
describe('should handle API error response', () => {
it('creating a preheat file API error response', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#cluster').click();
cy.contains('li', 'cluster-2').click();
cy.get('body').click('topLeft');
// Select a scope.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
it('creating a preheat image API error response', () => {
cy.get('#preheat-image');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 500,
body: {
message:
'Get "https://index.docker.io/v2/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)',
},
});
},
);
cy.get('#cluster').click();
cy.contains('li', 'cluster-2').click();
cy.get('body').click('topLeft');
// Select a scope.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message')
.should('be.visible')
.and(
'contain',
'Get "https://index.docker.io/v2/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)',
);
});
});
describe('cannot create preheat with invalid attributes', () => {
it('try to verify information', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const description = _.times(401, () => _.sample(characters)).join('');
cy.get('#cluster').type('cluster-99{enter}');
cy.get('#cluster-helper-text').should('have.text', 'cluster not found');
cy.get('#cluster').type('cluster-9{enter}');
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
// Add ure.
cy.get('#url').type('https://example.com/path/to/file');
// Should display message describing the validation error.
cy.get('#description').type(description);
// Show verification error message.
cy.get('#description-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#save').click();
});
it('try to verify URL', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const url = _.times(1001, () => _.sample(characters)).join('');
// Should display message URL the validation error.
cy.get('#url').type(`https://docs${url}`);
cy.get('#url-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 1-1000.');
// Click add URL button.
cy.get('#add-url').click();
cy.get('#save').click();
// The added URL validation error prompt should be displayed.
cy.get('#url-0-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-1000.');
cy.get('#url-0').type('https://example.com/path/to/file');
// Click add URL button.
cy.get('#add-url').click();
// Check whether to add URL input box.
cy.get('#url-1').should('exist');
// Click the clear URL button.
cy.get('#clear-url-1').click();
cy.get('#url-1').should('not.exist');
cy.get('#url').clear();
});
it('try to verify the preheat image args', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const url = _.times(401, () => _.sample(characters)).join('');
const filter = _.times(101, () => _.sample(characters)).join('');
cy.get('#preheat-image').click();
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
cy.get('#url').type('https://docs');
// Should display message name the validation error.
cy.get('#username').type(filter);
// Show verification error message.
cy.get('#username-helper-text').should('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#username').clear();
cy.get('#username').type('root');
cy.get('#username-helper-text').should('not.exist');
// Should display message password the validation error.
cy.get('#password').type(filter);
// Show verification error message.
cy.get('#password-helper-text').should('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#password').clear();
cy.get('#password').type('root');
cy.get('#password-helper-text').should('not.exist');
// Should display message Piece Length the validation error.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
cy.get('#radio-count').click();
cy.get('#count').should('have.value', '1');
cy.get('#count').clear();
cy.get('#count').type('0');
// Show verification error message.
cy.get('#count-helper-text').should('have.text', 'Fill in the characters, the length is 1-200.');
cy.get('#count').clear();
cy.get('#count').type('201');
cy.get('#count-helper-text').should('have.text', 'Fill in the characters, the length is 1-200.');
// Should display message Piece Length the validation error.
cy.get('#pieceLength').type('0');
// Show verification error message.
cy.get('#pieceLength-helper-text').should('have.text', 'Please enter a value between 4 and 1024 MiB.');
cy.get('#pieceLength').clear();
cy.get('#pieceLength-helper-text').should('not.eq');
cy.get('#pieceLength').type('1025');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
cy.get('#pieceLength-helper-text').should('exist');
// Should display message tag the validation error.
cy.get('#tag').type(url);
cy.get('#tag-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#tag').clear();
// Should display message filter the validation error.
cy.get('#filteredQueryParams').type('filter');
cy.get('#save').click();
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Please press ENTER to end the filter creation');
cy.get('#filteredQueryParams').clear();
cy.get('#filteredQueryParams').type('filter{enter}');
cy.get('#filteredQueryParams').type(filter);
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
// Should display message filter the validation error.
cy.get('#filteredQueryParams').type('filter');
cy.get('#save').click();
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Please press ENTER to end the filter creation');
cy.get('#filteredQueryParams').clear();
cy.get('#filteredQueryParams').type('filter{enter}');
cy.get('#filteredQueryParams').type(filter);
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
// Should display message ips the validation error.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
// Select ips.
cy.get('#radio-ips').click();
cy.get('#ips').type('10.0.0.8');
cy.get('#save').click();
// Show verification error message.
cy.get('#ips-helper-text').should('be.visible').and('have.text', 'Please press ENTER to end the ips creation');
cy.get('#ips').clear();
cy.get('#ips').type('10.0.0.8{enter}');
cy.get('#ips').type(filter);
// Show verification error message.
cy.get('#ips-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
});
it('try to verify the preheat image header', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const key = _.times(101, () => _.sample(characters)).join('');
cy.get('#preheat-image').click();
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
// Add ure.
cy.get('#url').type('https://example.com/path/to/file');
// Click add header button.
cy.get('#add-headers').click();
cy.get('#header').children().should('have.length', 3);
// Verification passed.
cy.get('#key-0').type('key');
cy.get('#key-0-helper-text').should('not.exist');
// Incorrect header key entered.
cy.get('#key-0').clear();
cy.get('#key-0').type(key);
// Show header key verification error message.
cy.get('#key-0-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-100.');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
cy.get('#save').click();
cy.get('#value-0-helper-text').should('have.text', 'Fill in the characters, the length is 1-1000.');
cy.get('#value-0').type('key');
cy.get('#value-0-helper-text').should('not.exist');
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
// Add haeder.
cy.get('#header > .MuiButton-root').click();
// Check the number of headers.
cy.get('#header').children().should('have.length', 4);
// Delete header input box.
cy.get('#clear-header-1').click();
cy.get('#header').children().should('have.length', 3);
});
it('try to verify the preheat file args', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const url = _.times(1001, () => _.sample(characters)).join('');
const filter = _.times(101, () => _.sample(characters)).join('');
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
cy.get('#url').type('https://docs');
// Should display message Piece Length the validation error.
cy.get('#select-scope').click();
cy.get('#all_peers').click();
cy.get('#radio-count').click();
cy.get('#count').should('have.value', '1');
cy.get('#count').clear();
cy.get('#count').type('0');
// Show verification error message.
cy.get('#count-helper-text').should('have.text', 'Fill in the characters, the length is 1-200.');
cy.get('#count').clear();
cy.get('#count').type('201');
cy.get('#count-helper-text').should('have.text', 'Fill in the characters, the length is 1-200.');
// Should display message Piece Length the validation error.
cy.get('#pieceLength').type('0');
// Show verification error message.
cy.get('#pieceLength-helper-text').should('have.text', 'Please enter a value between 4 and 1024 MiB.');
cy.get('#pieceLength').clear();
cy.get('#pieceLength-helper-text').should('not.eq');
cy.get('#pieceLength').type('1025');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
cy.get('#pieceLength-helper-text').should('exist');
// Should display message tag the validation error.
cy.get('#tag').type(url);
cy.get('#tag-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#tag').clear();
// Should display message filter the validation error.
cy.get('#filteredQueryParams').type('filter');
cy.get('#save').click();
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Please press ENTER to end the filter creation');
cy.get('#filteredQueryParams').clear();
cy.get('#filteredQueryParams').type('filter{enter}');
cy.get('#filteredQueryParams').type(filter);
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
// Should display message filter the validation error.
cy.get('#filteredQueryParams').type('filter');
cy.get('#save').click();
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Please press ENTER to end the filter creation');
cy.get('#filteredQueryParams').clear();
cy.get('#filteredQueryParams').type('filter{enter}');
cy.get('#filteredQueryParams').type(filter);
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
// Should display message ips the validation error.
cy.get('#select-scope').click();
cy.get('#all_seed_peers').click();
// Select ips.
cy.get('#radio-ips').click();
cy.get('#ips').type('10.0.0.8');
cy.get('#save').click();
// Show verification error message.
cy.get('#ips-helper-text').should('be.visible').and('have.text', 'Please press ENTER to end the ips creation');
cy.get('#ips').clear();
cy.get('#ips').type('10.0.0.8{enter}');
cy.get('#ips').type(filter);
// Show verification error message.
cy.get('#ips-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
});
it('try to verify the preheat file header', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const key = _.times(101, () => _.sample(characters)).join('');
// Select a cluster.
cy.get('#cluster').click();
cy.contains('li', 'cluster-1').click();
cy.get('body').click('topLeft');
// Add ure.
cy.get('#url').type('https://example.com/path/to/file');
// Click add header button.
cy.get('#add-headers').click();
cy.get('#header').children().should('have.length', 3);
// Verification passed.
cy.get('#key-0').type('key');
cy.get('#key-0-helper-text').should('not.exist');
// Incorrect header key entered.
cy.get('#key-0').clear();
cy.get('#key-0').type(key);
// Show header key verification error message.
cy.get('#key-0-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-100.');
cy.get('#save').click();
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
cy.get('#save').click();
cy.get('#value-0-helper-text').should('have.text', 'Fill in the characters, the length is 1-1000.');
cy.get('#value-0').type('key');
cy.get('#value-0-helper-text').should('not.exist');
// Preheat creation failed, the page is still in preheat/new!
cy.url().should('include', '/jobs/preheats/new');
// Add haeder.
cy.get('#header > .MuiButton-root').click();
// Check the number of headers.
cy.get('#header').children().should('have.length', 4);
// Delete header input box.
cy.get('#clear-header-1').click();
cy.get('#header').children().should('have.length', 3);
});
});
});

View File

@ -0,0 +1,453 @@
import preheats from '../../../fixtures/job/preheats/preheats.json';
import failurePreheat from '../../../fixtures/job/preheats/failure-preheat.json';
import successPreheat from '../../../fixtures/job/preheats/success-preheat.json';
import pendingPreheat from '../../../fixtures/job/preheats/pending-preheat.json';
declare const expect: Chai.ExpectStatic;
describe('Preheat', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=next,</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=first,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=last',
};
res.send(200, preheats, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/8',
},
(req) => {
req.reply({
statusCode: 200,
body: successPreheat,
});
},
);
cy.viewport(1440, 1080);
});
it('click the breadcrumb', () => {
cy.visit('/jobs/preheats');
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#preheat-6').click();
cy.url().should('include', '/jobs/preheats/6');
// Check for breadcrumb.
cy.get(':nth-child(3) > .MuiTypography-root').should('exist').and('contain', 'Preheat');
cy.get(':nth-child(3) > .MuiTypography-root').click();
cy.get('[data-testid="isloading"]').should('not.exist');
// Then I see that the current page is the preheats page!
cy.url().should('include', '/jobs/preheats');
});
describe('when data is loaded', () => {
beforeEach(() => {
cy.visit('/jobs/preheats');
});
it('should display detailed preheat failure information', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/10',
},
(req) => {
req.reply((res) => {
res.setDelay(1000);
res.send({
statusCode: 200,
body: failurePreheat,
});
});
},
);
// Click the preheat details button.
cy.get('#preheat-10').click();
cy.get('[data-testid="preheat-isloading"]').should('be.exist');
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', 10);
// Show preheat id.
cy.get('#id').should('have.text', 10);
// Show preheat description.
cy.get('#description').should('have.text', 'This is a preheat task with status failure');
cy.get('[data-testid="preheat-isloading"]').should('not.exist');
// Show preheat scope.
cy.get('#scope').should('contain', 'All Peers');
// Show preheat scope count.
cy.get('#count').should('contain', '100');
// Show preheat status.
cy.get('#status')
.should('have.text', 'FAILURE')
.and('have.css', 'background-color', 'rgb(212, 37, 54)')
.find('#error-log-icon')
.and('exist');
cy.get('#url-0').should('have.text', 'https://example.com/path/to/file');
cy.get('#url-1').should('have.text', 'https://example.com/path/to/file/url-1');
cy.get('#url-2').should('have.text', 'https://example.com/path/to/file/url-2');
cy.get('#piece-length').should('have.text', '4 MiB');
// Show preheat tag.
cy.get('#tag').should('have.text', 'prheat tag');
cy.get('#application').should('have.text', 'application-1');
// Show preheat headers.
cy.get('#header-key-0').should('have.text', 'Connection');
cy.get('#header-value-0').should('have.text', 'keep-alive');
// Show preheat scheduler clusters ID.
cy.get('#scheduler-lusters-id').should('have.text', 1);
// Show preheat Created At.
// cy.get('#created-at').should('have.text', '2023-12-13 11:58:53');
// Click the show error log button.
cy.get('#view-error-log').click();
cy.get('.css-avhns > .MuiTypography-h6').should('have.text', 'Error log');
cy.get('#panel1d-header').click();
// Check error log.
cy.get('.MuiAccordionDetails-root')
.should('be.visible')
.and('have.text', 'rpc error: code = Aborted desc = source response 401/401 Unauthorized is not valid');
});
it('should display detailed preheat success information', () => {
cy.get('#preheat-8').click();
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', 8);
// Show preheat id.
cy.get('#id').should('have.text', 8);
// Show preheat scope.
cy.get('#scope').should('have.text', 'Single Seed Peer');
// Show preheat type.
cy.get('#type').should('have.text', 'Image');
// Show preheat status.
cy.get('#status')
.should('have.text', 'SUCCESS')
.and('have.css', 'background-color', 'rgb(34, 139, 34)')
.find('#error-log-icon')
.and('not.exist');
// Show preheat URL.
cy.get('#url').should('have.text', 'https://example.com/manifests/v2.1.0');
// Show preheat headers.
cy.get('#header-key-0').should('have.text', 'Authorization');
cy.get('#header-key-1').should('have.text', 'Connection');
// Show preheat piece length.
cy.get('#piece-length').should('have.text', '4 MiB');
});
it('should display detailed preheat pending information', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingPreheat,
});
interceptCount++;
},
).as('preheat');
cy.get('#preheat-11').click();
cy.wait(100);
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', 11);
// Show preheat id.
cy.get('#id').should('have.text', 11);
// Show preheat status.
cy.get('#status')
.should('have.text', 'PENDING')
.and('have.css', 'background-color', 'rgb(219, 171, 10)')
.find('#pending-icon')
.and('exist')
.find('#error-log-icon')
.and('not.exist');
// Show preheat scope.
cy.get('#scope').should('contain', 'All Seed Peers');
// Show preheat scope.
cy.get('#percentage').should('contain', '100%');
// Show preheat piece length.
cy.get('#piece-length').should('have.text', '-');
// Show preheat headers.
cy.get('#header-value-0').should('have.text', 'Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT');
cy.wait(59000);
// Check how many times the API should be executed after six seconds.
cy.get('@preheat').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(2, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: failurePreheat,
});
},
);
// Show preheat status.
cy.get('#status')
.should('have.text', 'FAILURE')
.and('have.css', 'background-color', 'rgb(212, 37, 54)')
.find('#error-log-icon')
.and('exist');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/6',
},
(req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
cy.visit('/jobs/preheats/6');
});
it('unable to display breadcrumb', () => {
cy.get('.MuiBreadcrumbs-ol').should('be.visible').and('contain', 'Preheat');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', '-');
});
it('preheat information should appear empty', () => {
// Show preheat id.
cy.get('#id').should('have.text', 0);
// Show preheat description.
cy.get('#description').should('have.text', '-');
// Show preheat status.
cy.get('#status').should('contain', 'PENDING');
// Show preheat url.
cy.get('#url').should('have.text', '-');
// Show preheat piece length.
cy.get('#piece-length').should('have.text', '-');
// Show preheat scope.
cy.get('#scope').should('have.text', '-');
// Show preheat tag.
cy.get('#tag').should('have.text', '-');
// Show preheat application.
cy.get('#application').should('have.text', '-');
// Show preheat ips.
cy.get('#ips').should('not.exist');
// Show preheat headers.
cy.get('#headers').should('have.text', '-');
// Show preheat scheduler clusters ID.
cy.get('#scheduler-lusters-id').should('have.text', '-');
// Show preheat Created At.
cy.get('#created-at').should('have.text', '-');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/6',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/jobs/preheats/6');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('unable to display breadcrumb', () => {
cy.get('.MuiBreadcrumbs-ol').should('be.visible').and('contain', 'Preheat');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', '-');
});
it('preheat information should appear empty', () => {
// Show preheat id.
cy.get('#id').should('have.text', 0);
// Show preheat description.
cy.get('#description').should('have.text', '-');
// Show preheat status.
cy.get('#status').should('contain', 'PENDING');
// Show preheat url.
cy.get('#url').should('have.text', '-');
// Show preheat piece length.
cy.get('#piece-length').should('have.text', '-');
// Show preheat tag.
cy.get('#tag').should('have.text', '-').should('have.text', '-');
// Show preheat ips.
cy.get('#ips').should('not.exist');
// Show preheat headers.
cy.get('#headers').should('have.text', '-');
// Show preheat scheduler clusters ID.
cy.get('#scheduler-lusters-id').should('have.text', '-');
// Show preheat Created At.
cy.get('#created-at').should('have.text', '-');
});
it('when the status is pending, preheat API error response', () => {
cy.visit('/jobs/preheats/11');
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingPreheat,
});
interceptCount++;
},
).as('preheat');
cy.wait(100);
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').should('have.text', 11);
// Show preheat id.
cy.get('#id').should('have.text', 11);
// Show preheat status.
cy.get('#status')
.should('have.text', 'PENDING')
.and('have.css', 'background-color', 'rgb(219, 171, 10)')
.find('#pending-icon')
.and('exist')
.find('#error-log-icon')
.and('not.exist');
// Show preheat headers.
cy.get('#header-key-0').should('have.text', 'Authorization');
// Show preheat piece length.
cy.get('#piece-length').should('have.text', '-');
cy.wait(59000);
// Check how many times the API should be executed after six seconds.
cy.get('@preheat').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(2, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
});
});

View File

@ -0,0 +1,438 @@
import preheats from '../../../fixtures/job/preheats/preheats.json';
import paginationPreheats from '../../../fixtures/job/preheats/pagination-preheats.json';
import successPreheats from '../../../fixtures/job/preheats/success-preheats.json';
import failurePreheats from '../../../fixtures/job/preheats/failure-preheats.json';
import pendingPreheats from '../../../fixtures/job/preheats/pending-preheats.json';
import failurePreheat from '../../../fixtures/job/preheats/failure-preheat.json';
import successPreheat from '../../../fixtures/job/preheats/success-preheat.json';
import pendingPreheat from '../../../fixtures/job/preheats/pending-preheat.json';
declare const expect: Chai.ExpectStatic;
describe('Preheats', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=2&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=2&per_page=10>;rel=last',
};
res.send(200, preheats, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=2&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=2&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=2&per_page=10>;rel=last',
};
res.send(200, paginationPreheats, responseHeaders);
});
},
);
cy.visit('/jobs/preheats');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
it('should display preheat all list', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
res.setDelay(2000);
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=2&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=2&per_page=10>;rel=last',
};
res.send(200, preheats, responseHeaders);
});
interceptCount++;
},
).as('preheats');
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('[data-testid="isloading"]').should('not.exist');
cy.get('.MuiList-root > :nth-child(3) > .MuiButtonBase-root').click();
// The preheating status is displayed as PENDING.
cy.get('#PENDING-11').should('exist');
cy.get('#id-11').should('have.text', 11);
// cy.get('#created_at-11').should('have.text', '2023-03-23 16:29:18');
cy.get('#description-11').should('have.text', 'This is a preheat task with status pending');
// The preheating status is displayed as FAILURE.
cy.get('#FAILURE-10').should('exist');
cy.get('#description-10').should('have.text', 'This is a preheat task with status failure');
// The preheating status is displayed as SUCCESS.
cy.get('#list-8 > .css-1mlhis1').should('exist').find('#SUCCESS-8').should('exist');
cy.get('#description-8').should('have.text', 'This is a preheat task with status success');
});
it('should display preheat success list', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=SUCCESS&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=prev,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=next,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=first,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=last',
};
res.send(200, successPreheats, responseHeaders);
});
},
);
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="SUCCESS"]').click();
// Check how many preheat tasks are in success status.
cy.get('#preheats-list').children().should('have.length', 6);
cy.get('#preheat-pagination').should('not.exist');
});
it('should display preheat failure list', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=FAILURE&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=next,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=first,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=last',
};
res.send(200, failurePreheats, responseHeaders);
});
},
);
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="FAILURE"]').click();
// Check how many preheat tasks are in success failure.
cy.get('#preheats-list').children().should('have.length', 4);
});
it('should display preheat pending list', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=PENDING&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=PENDING>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=PENDING>;rel=next,</api/v1/jobs?page=1&per_page=10&state=PENDING>;rel=first,</api/v1/jobs?page=0&per_page=10&state=PENDING>;rel=last',
};
res.send(200, pendingPreheats, responseHeaders);
}),
interceptCount++;
},
).as('preheats');
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="PENDING"]').click();
// Check how many preheat tasks are in pending failure.
cy.get('#preheats-list').children().should('have.length', 1);
cy.wait(59000);
// The API should poll.
cy.get('@preheats').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(1, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=PENDING&type=preheat',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: `
</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=1&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=1&per_page=10>;rel=last`,
};
res.send(200, [], responseHeaders);
});
},
);
// No preheats list exists.
cy.get('#preheats-list').should('not.exist');
// Show You don't have any preheat tasks.
cy.get('#no-preheat').should('be.visible').and('contain', `You don't have any preheat tasks.`);
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=preheat',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
// No preheats list exists.
cy.get('#preheats-list').should('not.exist');
// Show You don't have any preheat tasks.
cy.get('#no-preheat').should('be.visible').and('contain', `You don't have any preheat tasks.`);
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
// Check number of pagination.
cy.get('#preheat-pagination > .MuiPagination-ul').children().should('have.length', 4);
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
// The preheating status is displayed as PENDING.
cy.get('#PENDING-11').should('exist');
cy.get('#id-11').should('have.text', 11);
});
it('when pagination changes, different page results are rendered', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#preheats-list').children().should('have.length', 1);
cy.get('#SUCCESS-1').should('exist');
cy.get('#id-1').should('have.text', 1);
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
// Check the current page number.
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Show page 1 preheat task.
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
});
it('when returning to the previous page, pagination and results remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
// Go to show preheat page.
cy.get('#preheat-1').click();
// Then I see that the current page is the show update personal-access-tokens.
cy.url().should('include', '/jobs/preheats/1');
// Go back to the last page。
cy.go('back');
// Check the current page number.
cy.get('#preheat-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
});
});
describe('search', () => {
it('should search for successful preheat', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/8',
},
(req) => {
req.reply({
statusCode: 200,
body: successPreheat,
});
},
);
// Check the list.
cy.get('#preheats-list').children().should('have.length', 10);
// should search for preheat ID.
cy.get('#search').type('8');
// Check the number of preheat lists is 1.
cy.get('#preheats-list').children().should('have.length', 1);
cy.get('#id-8').should('have.text', 8);
cy.get('#search').clear();
cy.get('#preheats-list').children().should('have.length', 10);
});
it('should search for failure preheat', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/10',
},
(req) => {
req.reply((res) => {
res.setDelay(1000);
res.send({
statusCode: 200,
body: failurePreheat,
});
});
},
);
// Check the list.
cy.get('#preheats-list').children().should('have.length', 10);
// should search for preheat ID.
cy.get('#search').type('10');
// Check the number of preheat lists is 1.
cy.get('#preheats-list').children().should('have.length', 1);
cy.get('#id-10').should('have.text', 10);
});
it('should search for pending preheat', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingPreheat,
});
interceptCount++;
},
).as('preheats');
// should search for preheat ID.
cy.get('#search').type('11');
cy.wait(59000);
// Check how many times the API should be executed after six seconds.
cy.get('@preheats').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(1, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: failurePreheat,
});
},
);
cy.get('#FAILURE-10').should('exist');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/6',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// should search for preheat ID.
cy.get('#search').type('6');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
});

303
cypress/e2e/menu/menu.cy.ts Normal file
View File

@ -0,0 +1,303 @@
import clusters from '../../fixtures/clusters/clusters.json';
import seedPeers from '../../fixtures/seed-peers/seed-peers.json';
import schedulers from '../../fixtures/schedulers/schedulers.json';
describe('Menu', () => {
beforeEach(() => {
cy.viewport(1440, 1080);
});
it('user not signin', () => {
// redirect when not signin.
cy.visit('/');
// Then I see that the current page is the signin!
cy.url().should('include', '/signin');
});
it('should switch to dark mode', () => {
cy.guestSignin();
cy.visit('/');
// Click the Light button.
cy.get('#light').click();
cy.get('#light').should('have.class', 'Mui-selected');
// Check if it is switched to light mode.
cy.get('#main').should('have.css', 'background-color', 'rgb(244, 246, 248)');
// Click the Dark button.
cy.get('#dark').click();
cy.get('#dark').should('have.class', 'Mui-selected');
// Check if it is switched to dark mode.
cy.get('#main').should('have.css', 'background-color', 'rgb(31, 36, 48)');
});
describe('try to signin as guest user', () => {
beforeEach(() => {
cy.guestSignin();
cy.visit('/');
});
it('should be redirect when signin', () => {
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
// The selected menu is clusters.
cy.get('[href="/clusters"]').should('have.class', 'Mui-selected');
// User menu does not exist.
cy.get('[href="/users"]').should('not.exist');
});
it('should navigate to the tokens page', () => {
cy.get('#developer').click();
cy.get('#personal-access-tokens').click();
// Then I see that the current page is the tokens!
cy.url().should('include', '/developer/personal-access-tokens');
// The selected menu is tokens.
cy.get('#personal-access-tokens').should('have.class', 'Mui-selected');
cy.get('#dragonfly').click();
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
});
it('should navigate to the preheats page and task page', () => {
cy.get('#jobs').click();
cy.get('#preheats').click();
// Then I see that the current page is the preheats!
cy.url().should('include', '/jobs/preheats');
// The selected menu is preheats.
cy.get('#preheats').should('have.class', 'Mui-selected');
});
it('should navigate to the task page and task persistent cache page', () => {
cy.get('#resource').click();
cy.get('#task').click();
// Then I see that the current page is the task!
cy.url().should('include', '/resource/task/clear');
cy.get('#task').should('have.class', 'Mui-selected');
cy.get('#persistent-cache-task').click();
// Then I see that the current page is the task persistent cache!
cy.url().should('include', '/resource/persistent-cache-task');
cy.get('#persistent-cache-task').should('have.class', 'Mui-selected');
});
});
describe('try to signin as root user', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: seedPeers,
});
},
);
cy.visit('/');
});
it('should be redirect when signin', () => {
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
// The selected menu is clusters.
cy.get('[href="/clusters"]').should('have.class', 'Mui-selected');
});
it('should navigate to the tokens page', () => {
cy.get('#developer').click();
cy.get('#personal-access-tokens').click();
// Then I see that the current page is the tokens!
cy.url().should('include', '/developer/personal-access-tokens');
// The selected menu is tokens.
cy.get('#personal-access-tokens').should('have.class', 'Mui-selected');
});
it('should navigate to the preheats page and task page', () => {
cy.get('#jobs').click();
cy.get('#preheats').click();
// Then I see that the current page is the preheats!
cy.url().should('include', '/jobs/preheats');
// The selected menu is preheats.
cy.get('#preheats').should('have.class', 'Mui-selected');
});
it('should navigate to the task page and task persistent cache page', () => {
cy.get('#resource').click();
cy.get('#task').click();
// Then I see that the current page is the task!
cy.url().should('include', '/resource/task/clear');
cy.get('#task').should('have.class', 'Mui-selected');
cy.get('#persistent-cache-task').click();
// Then I see that the current page is the task persistent cache!
cy.url().should('include', '/resource/persistent-cache-task');
cy.get('#persistent-cache-task').should('have.class', 'Mui-selected');
});
it('should navigate to the users page', () => {
cy.get('#users').click();
// Then I see that the current page is the users!
cy.url().should('include', '/users');
// The selected menu is users.
cy.get('#users').should('have.class', 'Mui-selected');
});
it('should navigate to the profile page', () => {
// Click unfold button.
cy.get('#unfold-more').click();
// Go to profil page.
cy.get('#profile-menu').click();
// Then I see that the current page is the profile!
cy.url().should('include', '/profile');
});
it('The menu should be smaller', () => {
// The menu should be smaller.
cy.get('#closure').should('exist').click();
cy.get('#expand').should('exist');
cy.get('#closure').should('not.exist');
// Go to tokens page.
cy.get('#developer').click();
cy.get('#personal-access-tokens').click();
// Then I see that the current page is the tokens!
cy.url().should('include', '/developer/personal-access-tokens');
// Go to jobs page.
cy.get('#jobs').click();
cy.get('#preheats').click();
// Then I see that the current page is the preheats!
cy.url().should('include', '/jobs/preheats');
// Go to task page.
cy.get('#resource').click();
cy.get('#task').click();
// Then I see that the current page is the task!
cy.url().should('include', '/resource/task/clear');
cy.get('#resource').click();
cy.get('#persistent-cache-task').click();
// Then I see that the current page is the task persistent cache!
cy.url().should('include', '/resource/persistent-cache-task');
// Go to user page.
cy.get('#users').click();
// Then I see that the current page is the users!
cy.url().should('include', '/users');
});
it('can logout', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/users/signout',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.get('#unfold-more').click();
cy.get('body').click('topLeft');
cy.get('#unfold-more').click();
// Click Logout button.
cy.get('#logout-menu').click();
// Then I see that the current page is the signin!
cy.url().should('include', '/signin');
});
it('logout API error response', () => {
cy.intercept(
{
method: 'POST',
url: '/api/v1/users/signout',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#unfold-more').click();
cy.get('#logout-menu').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
});
});

View File

@ -0,0 +1,404 @@
import peers from '../../fixtures/peers/peers.json';
import refreshPeers from '../../fixtures/peers/refresh-peers.json';
import cluster from '../../fixtures/clusters/cluster/cluster.json';
const path = require('path');
declare const expect: Chai.ExpectStatic;
describe('Peers', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/peers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: peers,
});
},
);
cy.visit('/clusters/1/peers');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
it('displays the total number of peers and git version number, as well as the number of git commit', () => {
// should display the total number of peers.
cy.get('#total').should('have.text', 10);
// should display the git version number of peers.
cy.get('#git-version').should('have.text', 4);
// should display the git commit number of peers.
cy.get('#git-commit').should('have.text', 5);
});
it('should display the active ratio', () => {
// Show active ratio by git version.
cy.get('#git-version-active').should('contain', '80%');
// Show active ratio by git commit.
cy.get('#git-commit-active').should('contain', '80%');
cy.get('.MuiInputBase-root > #git-version-select').click();
cy.get('[data-value="git-version-1"]').click();
// Show active ratio by git version 1.
cy.get('#git-commit-active').should('contain', '50%');
cy.get('.MuiInputBase-root > #git-version-select').click();
cy.get('[data-value="git-version-2"]').click();
// Show active ratio by git version 2.
cy.get('#git-commit-active').should('contain', '100%');
});
it('can export csv file', () => {
// Click export csv.
cy.get('#export').click();
cy.get('#export-git-version').click();
cy.get('[data-value="git-version-1"]').click();
cy.get('#export-git-commit').click();
cy.get('[data-value="git-commit-4"]').click();
cy.get('#close-export').click();
const downloadsFolder = Cypress.config('downloadsFolder');
// Click export csv.
cy.get('#export').click();
// Click save button.
cy.get('#save').click();
// Wait two seconds to ensure the download is successful.
cy.wait(2000);
// Get download file.
const all = path.join(downloadsFolder, 'Peer Data.csv');
// Check all quantity.
cy.readFile(all).then((fileContent) => {
const lines = fileContent.split('\n');
const numEntries = lines.length - 2;
expect(numEntries).to.be.closeTo(10, 0);
});
// Click export csv.
cy.get('#export').click();
cy.get('#export-git-version').click();
cy.get('[data-value="git-version-1"]').click();
cy.get('#save').click();
cy.wait(2000);
const gitVersion = path.join(downloadsFolder, 'Peer Data.csv');
// Check whether the number of data exported based on git-version-1 is correct.
cy.readFile(gitVersion)
.should('exist')
.then((fileContent) => {
const numEntries = fileContent.split('\n').length - 2;
expect(numEntries).to.be.closeTo(2, 0);
});
// Click export csv.
cy.get('#export').click();
cy.get('#export-git-version').click();
cy.get('[data-value="git-version-1"]').click();
cy.get('#export-git-commit').click();
cy.get('[data-value="git-commit-4"]').click();
cy.get('#save').click();
cy.wait(2000);
const gitCommit = path.join(downloadsFolder, 'Peer Data.csv');
// Check whether the number of data exported based on git-commit-4 is correct.
cy.readFile(gitCommit)
.should('exist')
.then((fileContent) => {
const numEntries = fileContent.split('\n').length - 2;
expect(numEntries).to.be.closeTo(1, 0);
});
});
it('click cancel button', () => {
// Click export csv.
cy.get('#export').click();
cy.get('.css-18v9rtl').should('be.visible').and('have.text', 'Export');
// Select git-version-1 in the git version selection box.
cy.get('#export-git-version').click();
cy.get('[data-value="git-version-1"]').click();
// Select git-commit-4 in the git commit selection box.
cy.get('#export-git-commit').click();
cy.get('[data-value="git-commit-4"]').click();
// Click cancel button.
cy.get('#cancel').click();
cy.get('#export').click();
// Check whether the selected one is all.
cy.get('#export-git-version').should('have.text', 'All');
cy.get('#export-git-commit').should('have.text', 'All');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/peers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
});
it('displays the total number of peers and git version number, as well as the number of git commit', () => {
// should display the total number of peers.
cy.get('#total').should('have.text', 0);
// should display the git version number of peers.
cy.get('#git-version').should('have.text', 0);
// should display the git commit number of peers.
cy.get('#git-commit').should('have.text', 0);
});
it('cannot display the active ratio', () => {
cy.get('#git-version-active').should('contain', '0');
cy.get('#git-commit-active').should('contain', '0');
});
it('cannot export csv file', () => {
cy.get('#export').click();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Export failed');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/peers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/clusters/1/peers');
});
it('displays the total number of peers and git version number, as well as the number of git commit', () => {
// should display the total number of peers.
cy.get('#total').should('have.text', 0);
// should display the git version number of peers.
cy.get('#git-version').should('have.text', 0);
// should display the git commit number of peers.
cy.get('#git-commit').should('have.text', 0);
});
it('cannot display the active ratio', () => {
cy.get('#git-version-active').should('contain', '0');
cy.get('#git-version-active').should('contain', '0');
cy.get('#git-commit-active').should('contain', '0');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('cannot export csv file', () => {
cy.get('#export').click();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Export failed');
});
});
describe('refresh', () => {
it('can refresh peers and return new data', () => {
cy.get('#total').should('have.text', 10);
cy.get('#git-version').should('have.text', 4);
cy.get('#git-commit').should('have.text', 5);
cy.get('#refresh').should('not.be.disabled');
// Click refresh button.
cy.get('#refresh').click();
cy.get('#refresh-title').should('be.visible').and('have.text', 'Refresh');
cy.get('#cancel').click();
cy.get('#refresh').click();
cy.get('#close-delete-icon').click();
cy.get('#refresh').click();
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.on('response', (res) => {
res.setDelay(2000);
});
req.reply({
statusCode: 200,
body: JSON.stringify('OK'),
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/peers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: refreshPeers,
});
},
);
cy.get('#save').click();
cy.get('#refresh').should('be.disabled');
cy.wait(2000);
cy.get('#total').should('have.text', 14);
cy.get('#git-version').should('have.text', 6);
cy.get('#git-commit').should('have.text', 7);
});
it('not can refresh peers and return new data', () => {
cy.get('#total').should('have.text', 10);
cy.get('#git-version').should('have.text', 4);
cy.get('#git-commit').should('have.text', 5);
cy.get('#refresh').should('not.be.disabled');
// Click refresh button.
cy.get('#refresh').click();
cy.get('#refresh-title').should('be.visible').and('have.text', 'Refresh');
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.on('response', (res) => {
res.setDelay(2000);
});
req.reply({
statusCode: 404,
body: { message: 'scheduler cluster id 7: record not found' },
});
},
);
cy.get('#save').click();
cy.get('#refresh').should('be.disabled');
cy.wait(2000);
cy.get('.MuiAlert-message').should('have.text', 'scheduler cluster id 7: record not found');
cy.get('#total').should('have.text', 10);
cy.get('#git-version').should('have.text', 4);
cy.get('#git-commit').should('have.text', 5);
});
it('can refresh peer fetch data error', () => {
cy.get('#total').should('have.text', 10);
cy.get('#git-version').should('have.text', 4);
cy.get('#git-commit').should('have.text', 5);
cy.get('#refresh').should('not.be.disabled');
// Click refresh button.
cy.get('#refresh').click();
cy.get('#refresh-title').should('be.visible').and('have.text', 'Refresh');
cy.get('#cancel').click();
cy.get('#refresh').click();
cy.get('#close-delete-icon').click();
cy.get('#refresh').click();
cy.intercept(
{
method: 'POST',
url: '/api/v1/jobs',
},
(req) => {
req.on('response', (res) => {
res.setDelay(2000);
});
req.reply({
statusCode: 200,
body: JSON.stringify('OK'),
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/peers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#save').click();
cy.get('#refresh').should('be.disabled');
cy.wait(2000);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('#total').should('have.text', 10);
cy.get('#git-version').should('have.text', 4);
cy.get('#git-commit').should('have.text', 5);
});
});
});

View File

@ -0,0 +1,557 @@
import updateUser from '../../fixtures/users/update-user.json';
import _ from 'lodash';
describe('Profile', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.visit('/profile');
cy.viewport(1440, 1080);
});
it('when data is loaded', () => {
// Show user name.
cy.get('#name-title').should('be.visible').and('have.text', 'root');
// Show user description.
cy.get('#description').should('be.visible').and('have.text', 'I am root');
cy.get('#id').should('be.visible').and('have.text', 1);
cy.get('#name').should('be.visible').and('have.text', 'root');
cy.get('#email').should('be.visible').and('have.text', 'root@example.com');
cy.get('#location').should('be.visible').and('have.text', 'Hangzhou');
cy.get('#phone').should('be.visible').and('have.text', '+86 153 1234 5678');
cy.get('#created_at').should('be.visible').and('have.text', '2023-11-06 06:09:04');
// Check Update Personal Information form.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
cy.get('#bio').should('have.value', 'I am root');
cy.get('#phone').should('have.value', '+86 153 1234 5678');
cy.get('#location').should('have.value', 'Hangzhou');
cy.get('#email').should('have.value', 'root@example.com');
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/1',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
// Show user name.
cy.get('#name-title').should('be.visible').and('have.text', '-');
// Show user description.
cy.get('#description').should('be.visible').and('have.text', '-');
cy.get('#id').should('be.visible').and('have.text', '-');
cy.get('#name').should('be.visible').and('have.text', '-');
cy.get('#email').should('be.visible').and('have.text', '-');
cy.get('#location').should('be.visible').and('have.text', '-');
cy.get('#phone').should('be.visible').and('have.text', '-');
cy.get('#created_at').should('be.visible').and('have.text', '-');
// Check Update Personal Information form.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
cy.get('#bio').should('have.value', '');
cy.get('#phone').should('have.value', '+86');
cy.get('#location').should('have.value', '');
cy.get('#email').should('have.value', '');
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Check Update Personal Information form.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
cy.get('#bio').should('have.value', '');
cy.get('#phone').should('have.value', '+86');
cy.get('#location').should('have.value', '');
cy.get('#email').should('have.value', '');
});
describe('update personal information', () => {
it('can update user', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/users/1' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
body: [],
});
});
// Click EDIT button.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
// Update user name.
cy.get('#bio').clear();
cy.get('#bio').type('I am root, I will change the description');
// Update user phone.
cy.get('#phone').clear();
cy.get('#phone').type('15123456789');
// Update user location.
cy.get('#location').clear();
cy.get('#location').type('Shanghai');
// Update user email.
cy.get('#email').clear();
cy.get('#email').type('root@gmail.com');
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/1',
},
(req) => {
req.reply({
statusCode: 200,
body: updateUser,
});
},
);
cy.get('#save').click();
// Check if profile description is updated.
cy.get('#description').should('be.visible').and('have.text', 'I am root, I will change the description');
// Check if profile email is updated.
cy.get('#email').should('be.visible').and('have.text', 'root@gmail.com');
// Check if profile location is updated.
cy.get('#location').should('be.visible').and('have.text', 'Shanghai');
// Check if profile phone is updated.
cy.get('#phone').should('be.visible').and('have.text', '+86 153 1234 5678');
});
it('click the `CANCEL button', () => {
// Click EDIT button.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
cy.get('#bio').clear();
cy.get('#bio').type('I am root, I will change the description');
// Update user email.
cy.get('#email').clear();
cy.get('#email').type('root@gmail.com');
cy.get('#cancel').click();
cy.get('#description').should('be.visible').and('have.text', 'I am root');
// Check whether the navigation bar email has changed.
cy.get('#email').should('be.visible').and('have.text', 'root@example.com');
// Click EDIT button.
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
cy.get('#bio').should('have.value', 'I am root');
cy.get('#email').should('have.value', 'root@example.com');
});
it('try to update user with guest user', () => {
cy.visit('/signin');
cy.guestSignin();
cy.intercept({ method: 'PATCH', url: '/api/v1/users/2' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
});
cy.visit('/profile');
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
// Update user phone.
cy.get('#phone').clear();
cy.get('#phone').type('18123456789');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'permission deny');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('should handle API error response', () => {
cy.intercept({ method: 'PATCH', url: '/api/v1/users/1' }, (req) => {
(req.body = ''),
req.reply({
forceNetworkError: true,
});
});
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
// Update user phone.
cy.get('#phone').clear();
cy.get('#phone').type('18123456789');
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
it('cannot create user with invalid attributes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const description = _.times(401, () => _.sample(characters)).join('');
const location = _.times(101, () => _.sample(characters)).join('');
cy.get('.MuiGrid-root > .MuiButtonBase-root').click();
// Should display message description the validation error.
cy.get('#bio').clear();
cy.get('#bio').type(description);
// Show verification error message.
cy.get('#bio-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#save').click();
cy.get('.css-1033rfx > .MuiTypography-root').should('exist').and('have.text', 'Update Personal Information');
cy.get('#bio').clear();
cy.get('#bio').type('I am root');
// Verification passed.
cy.get('#bio-helper-text').should('not.exist');
// Should display message phone the validation error.
cy.get('#phone').clear();
cy.get('#phone').type('+86 153 1234 123123');
// Show verification error message.
cy.get('#phone-helper-text').should('be.visible').and('have.text', 'Invalid phone number.');
cy.get('#save').click();
cy.get('.css-1033rfx > .MuiTypography-root').should('exist').and('have.text', 'Update Personal Information');
cy.get('#phone').clear();
cy.get('#phone').type('+86 151 2345 6789');
// Verification passed.
cy.get('#phone-helper-text').should('not.exist');
// Should display message location the validation error.
cy.get('#location').clear();
cy.get('#location').type(location);
// Show verification error message.
cy.get('#location-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#location').clear();
cy.get('#location').type('Shanghai');
cy.get('#location-helper-text').should('not.exist');
// Should display message email the validation error.
cy.get('#email').clear();
cy.get('#email').type('root');
// Show verification error message.
cy.get('#email-helper-text').should('be.visible').and('have.text', 'Email is invalid or already taken.');
cy.get('#email').clear();
cy.get('#email').type('root@example.com');
cy.get('#email-helper-text').should('not.exist');
});
});
describe('change password', () => {
it('can update password', () => {
cy.intercept({ method: 'POST', url: '/api/v1/users/1/reset_password' }, (req) => {
(req.body = { new_password: 'dragonfly2', old_password: 'dragonfly2' }),
req.reply({
statusCode: 200,
});
});
cy.intercept({ method: 'POST', url: '/api/v1/users/signout' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
});
});
// Click change password tab.
cy.get('#tab-password').click();
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
// Click cancel password button.
cy.get('#cancel-change-password').click();
// Input should be cleared.
cy.get('#oldPassword').should('have.value', '');
cy.get('#newPassword').should('have.value', '');
cy.get('#confirmNewPassword').should('have.value', '');
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
// Click save button.
cy.get('#change-password').click();
// Then I see that the current page is the signin!
cy.url().should('include', 'signin');
});
it('click the Profile tab', () => {
// Click change password button.
cy.get('#tab-password').click();
cy.get('#change-password-title').should('be.visible').and('have.text', 'Change Password');
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
// Click cancel button.
cy.get('#tab-profile').click();
cy.get('#change-password-title').should('not.exist');
cy.get('#tab-password').click();
cy.get('#change-password-title').should('be.visible').and('have.text', 'Change Password');
// Check if old password is empty.
cy.get('#oldPassword').should('have.text', '');
// Check if new password is empty.
cy.get('#newPassword').should('have.text', '');
// Check if confirm new password is empty.
cy.get('#confirmNewPassword').should('have.text', '');
});
it('try to update user with guest user', () => {
cy.visit('/signin');
cy.guestSignin();
cy.intercept({ method: 'POST', url: '/api/v1/users/2/reset_password' }, (req) => {
(req.body = { new_password: 'dragonfly2', old_password: 'dragonfly2' }),
req.reply({
statusCode: 200,
});
});
cy.intercept({ method: 'POST', url: '/api/v1/users/signout' }, (req) => {
(req.body = ''),
req.reply({
statusCode: 200,
});
});
cy.visit('/profile');
// Click change password button.
cy.get('#tab-password').click();
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
cy.get('#change-password').click();
// Then I see that the current page is the signin!
cy.url().should('include', 'signin');
});
it('should handle API error response', () => {
cy.intercept({ method: 'POST', url: '/api/v1/users/1/reset_password' }, (req) => {
(req.body = { new_password: 'dragonfly2', old_password: 'dragonfly2' }),
req.reply({
forceNetworkError: true,
});
});
// Click change password button.
cy.get('#tab-password').click();
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
cy.get('#change-password').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
it('try to change password with invalid password', () => {
cy.intercept({ method: 'POST', url: '/api/v1/users/1/reset_password' }, (req) => {
(req.body = { new_password: 'dragonfly2', old_password: 'dragonfly2' }),
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
});
// Click change password button.
cy.get('#tab-password').click();
cy.get('#oldPassword').type('dragonfly1');
cy.get('#newPassword').type('dragonfly2');
cy.get('#confirmNewPassword').type('dragonfly2');
cy.get('#change-password').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
it('cannot change password without required attributes', () => {
// Click change password button.
cy.get('#tab-password').click();
cy.get('#change-password').click();
// Show error message.
cy.get('#oldPassword-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the maximum length is 16.');
cy.get('#newPassword-helper-text')
.should('be.visible')
.and('have.text', 'At least 8-16 characters, with at least 1 lowercase letter and 1 number.');
cy.get('#confirmNewPassword-helper-text')
.should('be.visible')
.and('have.text', 'Please enter the same password.');
});
it('cannot change password with invalid attributes', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const oldPassword = _.times(17, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const newPasswordLengthExceeds = _.times(17, () => _.sample(characters)).join('');
const newPasswordLengthIsInsufficient = _.times(7, () => _.sample(characters)).join('');
// Click change password button.
cy.get('#tab-password').click();
// Should display message old password the validation error.
cy.get('#oldPassword').type(oldPassword);
// Show verification error message.
cy.get('#oldPassword-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the maximum length is 16.');
cy.get('#oldPassword').clear();
cy.get('#oldPassword').type('dragonfly');
cy.get('#oldPassword-helper-text').should('not.exist');
// Should display message new password the validation error.
cy.get('#newPassword').type(newPasswordLengthExceeds);
// Show verification error message.
cy.get('#newPassword-helper-text')
.should('be.visible')
.and('have.text', 'At least 8-16 characters, with at least 1 lowercase letter and 1 number.');
cy.get('#newPassword').clear();
cy.get('#newPassword').type('dragonfly1');
// Verification passed.
cy.get('#newPassword-helper-text').should('not.exist');
cy.get('#newPassword').clear();
cy.get('#newPassword').type(newPasswordLengthIsInsufficient);
// Show verification error message.
cy.get('#newPassword-helper-text')
.should('be.visible')
.and('have.text', 'At least 8-16 characters, with at least 1 lowercase letter and 1 number.');
cy.get('#newPassword').clear();
cy.get('#newPassword').type('dragonfly1');
// Verification passed.
cy.get('#newPassword-helper-text').should('not.exist');
// Should display message confirm new password the validation error.
cy.get('#confirmNewPassword').type(newPasswordLengthIsInsufficient);
// Show verification error message.
cy.get('#confirmNewPassword-helper-text')
.should('be.visible')
.and('have.text', 'Please enter the same password.');
cy.get('#confirmNewPassword').clear();
cy.get('#confirmNewPassword').type('dragonfly1');
// Verification passed.
cy.get('#confirmNewPassword-helper-text').should('not.exist');
});
it('click the password hide butto', () => {
cy.get('#tab-password').click();
// Verify the display status of the content of the old password input box.
cy.get('#oldPassword').type('dragonfly1');
// Find the old password input box and verify that its type attribute is 'password'.
cy.get('#oldPassword').should('have.attr', 'type', 'password');
// Change the type attribute of the old password input box to 'text' so that the content is visible.
cy.get(':nth-child(2) > .MuiFormControl-root > .MuiInputBase-root > .MuiButtonBase-root').click();
// Verify the contents of the old password input box.
cy.get('#oldPassword').should('have.attr', 'type', 'text').and('have.value', 'dragonfly1');
// Verify the display status of the content of the new password input box.
cy.get('#newPassword').type('dragonfly2');
cy.get('#newPassword').should('have.attr', 'type', 'password');
cy.get(':nth-child(3) > .MuiFormControl-root > .MuiInputBase-root > .MuiButtonBase-root').click();
cy.get('#newPassword').should('have.attr', 'type', 'text').and('have.value', 'dragonfly2');
// Verify the display status of the content of the confirm new password input box.
cy.get('#confirmNewPassword').type('dragonfly2');
cy.get('#confirmNewPassword').should('have.attr', 'type', 'password');
cy.get(':nth-child(4) > .MuiFormControl-root > .MuiInputBase-root > .MuiButtonBase-root').click();
cy.get('#confirmNewPassword').should('have.attr', 'type', 'text').and('have.value', 'dragonfly2');
});
});
});

View File

@ -0,0 +1,274 @@
import persistentCacheTasks from '../../../fixtures/resource/persistent-cache-task/persistent-cache-tasks.json';
import persistentCacheTask from '../../../fixtures/resource/persistent-cache-task/persistent-cache-task.json';
import failedPersistentCacheTask from '../../../fixtures/resource/persistent-cache-task/failed-persistent-cache-task.json';
describe('Persistent Cache Tasks', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: persistentCacheTasks,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: persistentCacheTask,
});
},
);
cy.visit('/resource/persistent-cache-task/clusters/1/2865345332');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
it('click the breadcrumb', () => {
// Display is loading.
cy.get('[data-testid="isloading"]').should('be.exist');
// Check for breadcrumb.
cy.get('#scheduler-cluster-1').should('be.visible').and('contain', 'scheduler-cluster-1');
cy.get('#task-id-2865345332').should('have.text', 2865345332);
cy.get('#scheduler-cluster-1').click();
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/resource/persistent-cache-task/clusters/1');
});
it('can display success persistent cache task', () => {
cy.get('#id').should('have.text', '2865345332');
cy.get('#success-task').should('exist');
cy.get('#persistent-replica-count').should('have.text', '2');
cy.get('#ttl').should('have.text', '7 days');
cy.get('#content-length').should('have.text', '1.59 KB');
cy.get('#piece-length').should('have.text', '4 MiB');
cy.get('#application').should('have.text', 'application-1');
cy.get('#tag').should('have.text', 'tag-1');
// Display peers.
cy.get('#peers').should('exist');
cy.get('#id-0').should('have.text', '2');
cy.get('#hostname-0').should('have.text', 'hostname-2');
cy.get('#os-0').should('have.text', 'ios');
cy.get('#persistent-0').should('contain', 'Yes');
cy.get('#type-0').should('have.text', 'Super');
cy.get('#ip-0').should('have.text', '112.3325.44');
cy.get('#port-0').should('have.text', '8001');
cy.get('#download-port-0').should('have.text', '4001');
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#hostname-0').should('have.text', 'hostname-5');
});
it('can display failed persistent cache task', () => {
cy.visit('/resource/persistent-cache-task/clusters/1');
cy.get('.MuiPagination-ul > :nth-child(3)').click();
cy.get('#failed-task-1').should('exist');
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks/3870122508?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: failedPersistentCacheTask,
});
},
);
// Click the persistent cache task details button.
cy.get('#card-id-1').click();
cy.get('#peers').should('not.exist');
cy.get('#failure-task').should('exist');
cy.get('#scheduler-cluster-1').click();
cy.get('#operation-0').click();
cy.get(':nth-child(11) > .MuiPaper-root > .MuiList-root > .information_menu__CXV1V > #view-3810320977').click();
// Then I see that the current page is the persistent cache task details!
cy.url().should('include', '/resource/persistent-cache-task/clusters/1/3810320977');
// Then I see that the current page is the persistent cache tasks!
cy.get('#scheduler-cluster-1').click();
// Display a list of persistent cache tasks.
cy.get('#table').click();
cy.get('#operation-3810320977').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .information_menu__CXV1V > #view-3810320977').click();
// Then I see that the current page is the persistent cache task details!
cy.url().should('include', '/resource/persistent-cache-task/clusters/1/3810320977');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
});
it('unable to display breadcrumb', () => {
cy.get('#task-id-2865345332').should('have.text', '2865345332');
});
it('persistent cache task render empty status', () => {
cy.get('#id').should('have.text', '0');
cy.get('#failure-task').should('exist');
cy.get('#create-at').should('have.text', '-');
cy.get('#persistent-replica-count').should('have.text', '-');
cy.get('#ttl').should('have.text', '-');
cy.get('#content-length').should('have.text', '-');
cy.get('#piece-length').should('have.text', '-');
cy.get('#application').should('have.text', '-');
cy.get('#tag').should('have.text', '-');
cy.get('#peers').should('not.exist');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks/3810320977?scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/resource/persistent-cache-task/clusters/1/3810320977');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('persistent cache task render empty status', () => {
cy.get('#id').should('have.text', '0');
cy.get('#failure-task').should('exist');
cy.get('#create-at').should('have.text', '-');
cy.get('#persistent-replica-count').should('have.text', '-');
cy.get('#ttl').should('have.text', '-');
cy.get('#content-length').should('have.text', '-');
cy.get('#piece-length').should('have.text', '-');
cy.get('#application').should('have.text', '-');
cy.get('#tag').should('have.text', '-');
cy.get('#peers').should('not.exist');
});
});
describe('delete', () => {
it('persistent cache tasks can be deleted', () => {
cy.get('#open-dialog').should('not.exist');
cy.get('#delete-task').click();
cy.get('#open-dialog').should('exist');
// Cancel delete task.
cy.get('#cancel-delete-task').click();
cy.get('#open-dialog').should('not.exist');
cy.get('#delete-task').click();
cy.get('#delete-task-input').type('delete');
cy.get('#save-delete-task').click();
// Shoe help text.
cy.get('#delete-task-input-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#delete-task-input').clear();
cy.get('#delete-task-input').type('DELETE');
cy.get('#delete-task-input-helper-text').should('not.exist');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.get('#save-delete-task').click();
cy.url().should('include', '/resource/persistent-cache-task/clusters/1');
});
it('should handle API error response', () => {
cy.get('#delete-task').click();
cy.get('#delete-task-input').type('DELETE');
cy.get('#delete-task-input-helper-text').should('not.exist');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#save-delete-task').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
});

View File

@ -0,0 +1,526 @@
import clusters from '../../../fixtures/clusters/clusters.json';
import persistentCacheTasks from '../../../fixtures/resource/persistent-cache-task/persistent-cache-tasks.json';
import deletePersistentCacheTasks from '../../../fixtures/resource/persistent-cache-task/delete-persistent-cache-tasks.json';
import deletePersistentCacheTasksAfter from '../../../fixtures/resource/persistent-cache-task/delete-persistent-cache-tasks-after.json';
describe('Persistent Cache Tasks', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: clusters,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: persistentCacheTasks,
});
},
);
cy.visit('/resource/persistent-cache-task');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
it('it should show cluster', () => {
// Display is loading.
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#clusters-card').should('exist');
cy.get('#cluster-name-1').should('have.text', 'cluster-1');
cy.get('#cluster-name-1').click();
});
it('should show persistent cache tasks', () => {
cy.visit('/resource/persistent-cache-task/clusters/1');
// Display is loading.
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#total').should('have.text', 19);
cy.get('#application').should('have.text', 6);
cy.get('#tag').should('have.text', 17);
cy.get('#card-id-0').should('have.text', '3810320977');
cy.get('#tag-0').should('have.text', 'tag-4');
cy.get('#application-0').should('have.text', 'application-3');
cy.get('#table').click();
cy.get(':nth-child(1) > #id-3810320977').should('have.text', '3810320977');
});
it('should show visualization of persistent cache tasks', () => {
cy.visit('/resource/persistent-cache-task/clusters/1');
cy.get('#tab-analytics').click();
cy.get('#total').should('have.text', 19);
cy.get('#application').should('have.text', 6);
cy.get('#tag').should('have.text', 17);
cy.get('#application-ratio').should('have.text', '31.58%');
cy.get('#tag-ratio').should('have.text', '89.47%');
});
it('call onChange when changing page size', () => {
// The viewport will now be changed to 1440px x 1080px
cy.viewport(1440, 1080);
// Check if the number of page size is 9.
cy.get('#clusters-card').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1600px x 1080px
cy.viewport(1600, 1080);
cy.wait(1000);
// Check if the number of page size is 12.
cy.get('#clusters-card').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1920px x 1080px
cy.viewport(1920, 1080);
cy.wait(1000);
// Check if the number of page size is 20.
cy.get('#clusters-card').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2048px x 1080px
cy.viewport(2048, 1080);
cy.wait(1000);
// Check if the number of page size is 20.
cy.get('#clusters-card').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2560px x 1080px
cy.viewport(2560, 1080);
cy.wait(1000);
// Check if the number of page size is 24.
cy.get('#clusters-card').should('exist').children().should('have.length', 15);
cy.visit('/resource/persistent-cache-task/clusters/1');
// The viewport will now be changed to 1440px x 1080px
cy.viewport(1440, 1080);
// Check if the number of page size is 9.
cy.get('#card-list').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1600px x 1080px
cy.viewport(1600, 1080);
cy.wait(1000);
// Check if the number of page size is 9.
cy.get('#card-list').should('exist').children().should('have.length', 9);
// The viewport will now be changed to 1920px x 1080px
cy.viewport(1920, 1080);
cy.wait(1000);
// Check if the number of page size is 12.
cy.get('#card-list').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2048px x 1080px
cy.viewport(2048, 1080);
cy.wait(1000);
// Check if the number of page size is 12.
cy.get('#card-list').should('exist').children().should('have.length', 12);
// The viewport will now be changed to 2560px x 1080px
cy.viewport(2560, 1080);
cy.wait(1000);
// Check if the number of page size is 15.
cy.get('#card-list').should('exist').children().should('have.length', 15);
});
});
describe('search', () => {
it('can search cluster', () => {
cy.get('#search-cluster').type('cluster-1{enter}');
// Check the card list.
cy.get('#clusters-card').children().should('have.length', 9);
cy.get('#search-cluster').clear();
cy.get('#search-cluster').type('cluster-11{enter}');
// Check the card list.
cy.get('#clusters-card').children().should('have.length', 1);
cy.get('#no-clusters').should('not.exist');
cy.get('#search-cluster').clear();
cy.get('#search-cluster').type('cluster-111{enter}');
cy.get('#no-clusters').should('exist');
});
it('can search persistent cache task', () => {
cy.get('#cluster-name-1').click();
cy.get('#search-task').type('2484851399{enter}');
// Check the card list.
cy.get('#card-list').children().should('have.length', 1);
cy.get('#search-task').clear();
// Check the card list.
cy.get('#card-list').children().should('have.length', 9);
cy.get('#search-task').type('9023');
// It should prompt that there is no task.
cy.get('#no-task').should('have.text', 'This scheduler cluster has no persistent cache task.');
});
it('should be queried based on the query string', () => {
cy.visit('/resource/persistent-cache-task?search=cluster-11');
cy.get('#search-cluster').should('have.value', 'cluster-11');
// Check the card list.
cy.get('#clusters-card').children().should('have.length', 1);
cy.visit('/resource/persistent-cache-task/clusters/1?search=2865345332');
// Check the card list.
cy.get('#card-list').children().should('have.length', 3);
});
});
describe('delete', () => {
beforeEach(() => {
cy.visit('/resource/persistent-cache-task/clusters/1');
});
it('can the delet persistent cache task', () => {
cy.get('#operation-0').click();
cy.get('#delete-task').should('not.exist');
cy.get(':nth-child(11) > .MuiPaper-root > .MuiList-root > .information_menu__CXV1V > #delete-3810320977').click();
cy.get('#delete-task').should('exist');
cy.get('#help-delete-task').should('have.text', 'Persistent cache task will be permanently deleted.');
cy.get('#deletCache').type('delete');
// Shoe help text.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deleteTask').click();
cy.get('#delete-task').should('exist');
cy.get('#deletCache').clear();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/3810320977?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: deletePersistentCacheTasks,
});
},
);
cy.get('#deletCache').type('DELETE');
cy.get('#total').should('have.text', 19);
cy.get('#deleteTask').click();
// Show Success Message.
cy.get('#success-message').should('have.text', 'Submission successful!');
cy.get('#total').should('have.text', 18);
});
it('should handle API error response', () => {
cy.get('#operation-0').click();
cy.get('body').click('topLeft');
cy.get('#operation-0').click();
cy.get('#delete-task').should('not.exist');
cy.get(':nth-child(11) > .MuiPaper-root > .MuiList-root > .information_menu__CXV1V > #delete-3810320977').click();
cy.get('#delete-task').should('exist');
cy.get('#help-delete-task').should('have.text', 'Persistent cache task will be permanently deleted.');
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/3810320977?scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#deletCache').type('DELETE');
cy.get('#deleteTask').click();
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
});
it('when a task is removed, this task is the only task on the last page', () => {
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(4) > .MuiButtonBase-root').click();
cy.url().should('include', '/resource/persistent-cache-task/clusters/1?page=3');
cy.get('#operation-0').click();
cy.get('#delete-2865345332').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: deletePersistentCacheTasksAfter,
});
},
);
cy.get('#deletCache').type('DELETE');
cy.get('#total').should('have.text', 19);
cy.get('#deleteTask').click();
// Show Success Message.
cy.get('#success-message').should('have.text', 'Submission successful!');
cy.get('#total').should('have.text', 18);
cy.url().should('include', '/resource/persistent-cache-task/clusters/1?page=2');
});
it('when deleting a task, there is only one task on the next page', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#task-pagination > .MuiPagination-ul').children().should('have.length', '5');
// Check the last task ID.
cy.get('#card-id-8').should('have.text', '2865345332');
cy.url().should('include', '/resource/persistent-cache-task/clusters/1?page=2');
cy.get('#operation-8').click();
cy.get(':nth-child(11) > .MuiPaper-root > .MuiList-root > .information_menu__CXV1V > #delete-2865345332').click();
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/persistent-cache-tasks/2865345332?scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: deletePersistentCacheTasks,
});
},
);
cy.get('#deletCache').type('DELETE');
cy.get('#total').should('have.text', 19);
cy.get('#deleteTask').click();
// Show Success Message.
cy.get('#success-message').should('have.text', 'Submission successful!');
cy.get('#total').should('have.text', 18);
// Check the current page number.
cy.get('#task-pagination > .MuiPagination-ul').children().should('have.length', '4');
// Check the last task ID.
cy.get('#card-id-8').should('have.text', '2865345332');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/persistent-cache-tasks?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
});
it('cluster API response error', () => {
cy.visit('/resource/persistent-cache-task');
cy.get('#no-date').should('exist');
cy.get('#no-date-text').should('have.text', 'You have no clusters.');
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
});
it('persistent cache task API response error', () => {
cy.visit('/resource/persistent-cache-task/clusters/1');
// It should prompt that there is no task.
cy.get('#no-task').should('have.text', 'This scheduler cluster has no persistent cache task.');
// Show error message.
cy.get('.MuiAlert-message').should('have.text', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
cy.get('#table').click();
// It should prompt that there is no task.
cy.get('#no-task-table').should('have.text', 'This scheduler cluster has no persistent cache task.');
});
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
cy.get('.MuiPagination-ul > :nth-child(3)').click();
// Show cluster name.
cy.get('#cluster-name-10').should('be.visible').and('contain', 'cluster-10');
// Show persistent cache task
cy.visit('/resource/persistent-cache-task/clusters/1');
cy.get('#card-list').children().should('have.length', 9);
cy.get('#card-id-0').should('have.text', '3810320977');
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#card-list').children().should('have.length', 9);
cy.get('#card-id-0').should('have.text', '3870122509');
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
cy.get('#clusters-card').children().should('have.length', 9);
cy.get('.MuiPagination-ul > :nth-child(6) > .MuiButtonBase-root').click();
cy.get('#clusters-card').children().should('have.length', 1);
cy.get('#cluster-name-37').should('have.text', 'cluster-37');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
cy.get('#clusters-card').children().should('have.length', 1);
cy.get('#cluster-name-37').should('have.text', 'cluster-37');
// Show persistent cache task
cy.visit('/resource/persistent-cache-task/clusters/1?page=2');
cy.get('#card-list').children().should('have.length', 9);
cy.get('#card-id-0').should('have.text', '3870122509');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
cy.get('#card-list').children().should('have.length', 9);
cy.get('#card-id-0').should('have.text', '3870122509');
});
});
});

View File

@ -0,0 +1,940 @@
import createTaskJob from '../../../fixtures/resource/task/create-task-job.json';
import task from '../../../fixtures/resource/task/task.json';
import pendingTask from '../../../fixtures/resource/task/pending-task.json';
import taskIDByTask from '../../../fixtures/resource/task/task-id-by-task.json';
import noTask from '../../../fixtures/resource/task/no-task.json';
import ImageManifest from '../../../fixtures/resource/task/image-manifest-url-task.json';
import _ from 'lodash';
describe('Clear', () => {
beforeEach(() => {
cy.signin();
cy.visit('/resource/task/clear');
cy.viewport(1440, 1080);
});
describe('when no data is loaded', () => {
it('when search by url has no data to load', () => {
cy.get('#no-task').should('not.exist');
cy.get('#light').should('exist');
cy.get('#no-task-image').should('not.exist');
// Click the Toggle Light button.
cy.get('#light').click();
cy.get('#light').should('have.class', 'Mui-selected');
// Check if it is switched to light mode.
cy.get('#main').should('have.css', 'background-color', 'rgb(244, 246, 248)');
cy.get('#no-task-image').should('exist');
cy.get('#dark-no-task-image').should('not.exist');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: noTask,
});
},
);
cy.get('#url').click();
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#searchByURL').click();
cy.get('#no-task').should('exist');
});
it('when search by image manifest url has no data to load', () => {
cy.get('#no-task').should('not.exist');
cy.get('#serach-image-manifest-url').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
async (req) => {
await new Promise((resolve) => setTimeout(resolve, 200));
req.reply({
statusCode: 200,
body: {
image: {
layers: [
{
url: 'https://ghcr.io/v2/dragonflyoss/scheduler/blobs/sha256:c7c72808bf776cd122bdaf4630a4a35ea319603d6a3b6cbffddd4c7fd6d2d269',
},
{
url: 'https://ghcr.io/v2/dragonflyoss/scheduler/blobs/sha256:9986a736f7d3d24bb01b0a560fa0f19c4b57e56c646e1f998941529d28710e6b',
},
],
},
peers: [],
},
});
},
);
cy.get('#image-manifest-url').type('https://example.com/path/to/file{enter}');
// Shou You don't find any results!
cy.get('#no-image-manifest-URL-task').should('exist').and('contain', `You don't find any results!`);
});
});
describe('when data is loaded', () => {
it('click the `CANCEL button', () => {
cy.get('#url').click();
// Add tag input.
cy.get('#tag').should('exist');
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
// Add piece length.
cy.get('#pieceLength').type('4');
cy.get('#cancelSearchByURL').click();
cy.get('#url').click();
cy.get('#tag').should('have.value', '');
cy.get('#url').should('have.value', '');
cy.get('#pieceLength').should('have.value', '');
});
it('can search by url', () => {
let interceptCount = 0;
cy.get('#url').click();
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
// Add piece length.
cy.get('#pieceLength').type('4');
// Add tag input.
cy.get('#tag').type('tag');
// Add tag input.
cy.get('#application').type('application');
// Add filtered query params input.
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('filteredQueryParams{enter}');
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('X-Amz-Algorithm{enter}');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingTask,
});
interceptCount++;
},
).as('cache');
cy.get('#searchByURL').click();
cy.get('#isLoading').should('be.exist');
cy.wait(59000);
// Executed every 3 seconds, it should be executed 2 times after 6 seconds.
cy.get('@cache').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(1, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
cy.get('#url').click();
// Show url.
cy.get('#url').should('have.value', 'https://example.com/path/to/file');
cy.get('#tag').should('have.value', 'tag');
cy.get('#application').should('have.value', 'application');
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
.should('contain', 'filteredQueryParams')
.and('contain', 'X-Amz-Algorithm');
});
it('can search by task id', () => {
cy.get('#serach-task-id').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
cy.get('.MuiInputBase-root > #task-id').type(
'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916{enter}',
);
cy.get('#cache').children().should('have.length', 3);
// Go to next page.
cy.get('#pagination-0 > .MuiPagination-ul > :nth-child(4) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#pagination-0 > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#cache-0 > :nth-child(1) > .css-tzff0k > .MuiBox-root > .MuiTypography-root').should(
'have.text',
'dragonfly-seed-client-5',
);
cy.get('#cache-0').children().should('have.length', 2);
// Pagination should not be displayed.
cy.get('#pagination-1').should('exist');
// Pagination should be shown.
cy.get('#pagination-2').should('not.exist');
cy.get('#cache-1 > :nth-child(1)')
.should('contain', 'kind-worker3')
.and('contain', '172.18.0.2-kind-worker3-3de3df03-a97d-4784-b608-f9b04b3085f3')
.and('contain', 'Normal');
cy.get('#pagination-1 > .MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#cache-1').children().should('have.length', 1);
// Go back to the last page.
cy.get('#pagination-0 > .MuiPagination-ul > :nth-child(1) > .MuiButtonBase-root').click();
// Check the current data list.
cy.get('#cache-0').children().should('have.length', 5);
cy.get('.MuiInputBase-root > .MuiButtonBase-root').click();
cy.get('.MuiInputBase-root > #task-id').should('not.have.value');
cy.get('.MuiInputBase-root > #task-id').type('{enter}');
});
it('can search by content for calculating task id', () => {
cy.get('#serach-content-for-calculating-task-id').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
cy.get('#content-for-calculating-task-id').type('3870122509{enter}');
cy.get('#cache').children().should('have.length', 3);
// Go to next page.
cy.get('#pagination-0 > .MuiPagination-ul > :nth-child(4) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#pagination-0 > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#cache-0 > :nth-child(1) > .css-tzff0k > .MuiBox-root > .MuiTypography-root').should(
'have.text',
'dragonfly-seed-client-5',
);
cy.get('#cache-0').children().should('have.length', 2);
// Pagination should not be displayed.
cy.get('#pagination-1').should('exist');
});
it('can search by image manifest url', () => {
cy.get('#no-task').should('not.exist');
cy.get('#serach-image-manifest-url').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
async (req) => {
await new Promise((resolve) => setTimeout(resolve, 200));
req.reply({
statusCode: 200,
body: ImageManifest,
});
},
);
cy.get('#image-manifest-url').type('https://example.com/path/to/file{enter}');
// Show is loading.
cy.get('#isLoading').should('exist');
// Display cache information.
cy.get('#blobs').should('have.text', 'Total: 5');
cy.get('#scheduler-id-0').should('exist', 'ID : 1');
cy.get('#isLoading').should('not.exist');
cy.get('#scheduler-1-hostname-0').should('have.text', 'kind-worker1');
cy.get('#scheduler-1-ip-0').should('have.text', '172.18.0.4');
cy.get('#scheduler-1-proportion-0').should('contain', '60.00%');
// Should display URL.
cy.get('#scheduler-1-url-0').click();
});
});
describe('should handle API error response', () => {
it('create job API error', () => {
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Search by URL.
cy.get('#url').click();
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#searchByURL').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
// Search by task id.
cy.get('#serach-task-id').click();
cy.get('.MuiInputBase-root > #task-id').type(
'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916{enter}',
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('when the status is pending, delete cache API error response', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingTask,
});
interceptCount++;
},
).as('cache');
// Search by URL.
cy.get('#url').click();
cy.get('#url').type('https://example.com/path/to/file');
cy.get('#searchByURL').click();
cy.get('#isLoading').should('be.exist');
cy.wait(59000);
// Executed every 1 minute and once after 1 minute.
cy.get('@cache').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(1, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
it('delete cache API error response', () => {
// Search by task id.
cy.get('#serach-task-id').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
cy.get('.MuiInputBase-root > #task-id').type(
'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916{enter}',
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('search by image manifest url API error response', () => {
cy.get('#no-task').should('not.exist');
cy.get('#serach-image-manifest-url').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
async (req) => {
await new Promise((resolve) => setTimeout(resolve, 200));
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#image-manifest-url').type('https://example.com/path/to/file{enter}');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
describe('delete', () => {
it('can delete cache searched by URL', () => {
cy.get('#url').click();
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
cy.get('#searchByURL').click();
cy.get(':nth-child(2) > .MuiPaper-root > .css-whqzh4 > .MuiButtonBase-root').click();
cy.get('#deletCache').type('e');
// Should display message delete cache the validation error.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deletCache').clear();
cy.get('#deletCache').type('DELETE');
cy.get('#deletCache-helper-text').should('not.exist');
// Click delete cache button.
cy.get('#deleteTask').click();
// Then I see that the current page is the executions id.
cy.url().should('include', '/resource/task/executions/1');
});
it('Can delete cache searched by task id', () => {
// Search by task id.
cy.get('#serach-task-id').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: taskIDByTask,
});
},
);
cy.get('.MuiInputBase-root > #task-id').type(
'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916{enter}',
);
cy.get(':nth-child(2) > .MuiPaper-root > .css-whqzh4 > .MuiButtonBase-root').click();
cy.get('#deletCache').type('e');
// Should display message delete cache the validation error.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deletCache').clear();
cy.get('#deletCache').type('DELETE');
cy.get('#deletCache-helper-text').should('not.exist');
// Click delete cache button.
cy.get('#deleteTask').click();
// Then I see that the current page is the executions id.
cy.url().should('include', '/resource/task/executions/1');
});
it('Can delete cache searched by content for calculating task id', () => {
cy.get('#serach-content-for-calculating-task-id').click();
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: taskIDByTask,
});
},
);
cy.get('#content-for-calculating-task-id').type('3870122509{enter}');
cy.get(':nth-child(2) > .MuiPaper-root > .css-whqzh4 > .MuiButtonBase-root').click();
cy.get('#deletCache').type('e');
// Should display message delete cache the validation error.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deletCache').clear();
cy.get('#deletCache').type('DELETE');
cy.get('#deletCache-helper-text').should('not.exist');
// Click delete cache button.
cy.get('#deleteTask').click();
// Then I see that the current page is the executions id.
cy.url().should('include', '/resource/task/executions/1');
});
it('search by task id API error response should be handled', () => {
cy.get('#url').click();
// Add url.
cy.get('#url').type('https://example.com/path/to/file');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
cy.get('#searchByURL').click();
cy.get('#scheduler-id-1').should('contain', '2');
cy.get(':nth-child(2) > .MuiPaper-root > .css-whqzh4 > .MuiButtonBase-root').click();
cy.get('#deletCache').type('e');
// Should display message delete cache the validation error.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deletCache').clear();
cy.get('#deletCache').type('DELETE');
cy.get('#deletCache-helper-text').should('not.exist');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Click delete cache button.
cy.get('#deleteTask').click();
// Then I see that the current page is the clear.
cy.url().should('include', '/resource/task/clear');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
it('search by URL API error response should be handled', () => {
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
statusCode: 200,
body: createTaskJob,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/1',
},
(req) => {
req.reply({
statusCode: 200,
body: task,
});
},
);
// Search by task id.
cy.get('#serach-task-id').click();
cy.get('.MuiInputBase-root > #task-id').type(
'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916{enter}',
);
cy.get('#scheduler-id-1').should('contain', '2');
cy.get(':nth-child(2) > .MuiPaper-root > .css-whqzh4 > .MuiButtonBase-root').click();
cy.get('#deletCache').type('e');
// Should display message delete cache the validation error.
cy.get('#deletCache-helper-text').should('have.text', 'Please enter "DELETE"');
cy.get('#deletCache').clear();
cy.get('#deletCache').type('DELETE');
cy.get('#deletCache-helper-text').should('not.exist');
cy.intercept(
{
method: 'post',
url: '/api/v1/jobs',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Click delete cache button.
cy.get('#deleteTask').click();
// Then I see that the current page is the clear.
cy.url().should('include', '/resource/task/clear');
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
});
});
describe('cannot search cache with invalid attributes', () => {
it('try to verify url', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const url = _.times(1001, () => _.sample(characters)).join('');
const tag = _.times(401, () => _.sample(characters)).join('');
const filter = _.times(101, () => _.sample(characters)).join('');
cy.get('#url').click();
// Should display message url the validation error.
cy.get('#url').type(`https://docs${url}`);
cy.get('#url-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-1000.');
cy.get('#searchByURL').click();
cy.get('#url').clear();
cy.get('#url').type('https://docs');
cy.get('#url-helper-text').should('not.exist');
// Should display message tag the validation error.
cy.get('#tag').type(tag);
cy.get('#tag-helper-text').should('be.visible').and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#tag').clear();
// Should display message filter the validation error.
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('filter');
cy.get('#searchByURL').click();
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Please press ENTER to end the filter creation');
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').clear();
cy.get('#filteredQueryParams-helper-text').should('not.exist');
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type('filter{enter}');
cy.get('.MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(filter);
// Show verification error message.
cy.get('#filteredQueryParams-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#searchByURL').click();
// Should display message application the validation error.
cy.get('#application').type(tag);
cy.get('#application-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-400.');
cy.get('#application').clear();
cy.get('#searchByURL').click();
cy.get('#serach-task-id').click();
cy.get('#task-id').type(`${tag}{enter}`);
cy.get('#task-id-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-400.');
});
it('try to verify task id', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const taskID = _.times(401, () => _.sample(characters)).join('');
cy.get('#serach-task-id').click();
cy.get('#task-id').type(`${taskID}{enter}`);
cy.get('#task-id-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-400.');
});
it('try to verify content for calculating task id', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const contentForCalculatingTaskID = _.times(401, () => _.sample(characters)).join('');
cy.get('#serach-content-for-calculating-task-id').click();
cy.get('#content-for-calculating-task-id').type(`${contentForCalculatingTaskID}{enter}`);
cy.get('#content-for-calculating-task-id-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-400.');
});
it('try to verify image manifest url', () => {
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const url = _.times(401, () => _.sample(characters)).join('');
cy.get('#serach-image-manifest-url').click();
cy.get('#image-manifest-url').click();
// Should display message url the validation error.
cy.get('#image-manifest-url').type(`https://docs${url}`);
cy.get('#image-manifest-url-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-400.');
cy.get('#image-manifest-url').clear();
cy.get('#image-manifest-url').type('https://docs');
cy.get('#image-manifest-url-helper-text').should('not.exist');
});
});
});

View File

@ -0,0 +1,422 @@
import executions from '../../../fixtures/resource/task/executions.json';
import execution from '../../../fixtures/resource/task/execution.json';
import pendingExecution from '../../../fixtures/resource/task/pending-execution.json';
import failureExecution from '../../../fixtures/resource/task/failure-execution.json';
describe('Executions', () => {
beforeEach(() => {
cy.signin();
cy.visit('/resource/task/executions/6');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=next,</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=first,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=last',
};
res.send(200, executions, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/9',
},
(req) => {
req.reply({
statusCode: 200,
body: execution,
});
},
);
cy.visit('/resource/task/executions');
});
it('click the breadcrumb', () => {
// Show isloading.
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#detail-9').click();
cy.url().should('include', '/resource/task/executions/9');
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist').and('contain', 'Executions').and('contain', '9');
cy.get('.MuiBreadcrumbs-ol > :nth-child(5) > .MuiTypography-root').click();
cy.get('[data-testid="isloading"]').should('not.exist');
// Then I see that the current page is the executions page!
cy.url().should('include', '/resource/task/executions');
});
it('should display detailed execution failure information', () => {
// Click the execution details button.
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/10',
},
(req) => {
req.reply((res) => {
res.setDelay(1000);
res.send({
statusCode: 200,
body: failureExecution,
});
});
},
);
cy.get('#detail-10').click();
cy.get('[data-testid="execution-isloading"]').should('be.exist');
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist').and('contain', 10);
// Show execution id.
cy.get('#id').should('contain', 10);
// Show execution content for calculating task id.
cy.get('#content-for-calculating-task-id').should('have.text', '-');
cy.get('[data-testid="execution-isloading"]').should('not.exist');
// Show execution piece length.
cy.get('#piece-length').should('have.text', '4 MiB');
// Show execution status.
cy.get('#status')
.should('have.text', 'FAILURE')
.and('have.css', 'background-color', 'rgb(212, 37, 54)')
.find('#error-log-icon')
.and('exist');
cy.get('#task-id').should('contain', 'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916');
// Show execution tag.
cy.get('#tag').should('contain', 'execution-tag');
// Show execution application.
cy.get('#application').should('contain', 'execution-application');
// Show execution scheduler clusters ID.
cy.get('#scheduler-clusters-id').should('have.text', 1);
// Click the show error log button.
cy.get('#status > .MuiButtonBase-root').click();
cy.get('#error-log').should('have.text', 'Error log');
cy.get('#panel1d-header').click();
// Check error log.
cy.get('.MuiAccordionDetails-root > .MuiTypography-root')
.should('be.visible')
.and('have.text', 'rpc error: code = Aborted desc = source response 401/401 Unauthorized is not valid');
});
it('should display detailed execution success information', () => {
cy.get('#detail-9').click();
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist').and('contain', 9);
// Show execution id.
cy.get('#id').should('contain', 9);
cy.get('[data-testid="execution-isloading"]').should('not.exist');
// Show execution status.
cy.get('#status')
.should('have.text', 'SUCCESS')
.and('have.css', 'background-color', 'rgb(34, 139, 34)')
.find('#error-log-icon')
.and('not.exist');
// Show execution URL.
cy.get('.MuiPaper-root > :nth-child(4)').should('contain', 'https://example.com/path/to/file');
// Show execution piece length.
cy.get('#piece-length').should('have.text', '-');
// Show failure task.
cy.get('#failure-tasks').should('exist');
cy.get('#failure-tasks-list > :nth-child(1) > :nth-child(1)').should('contain', 'kind-worker');
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#failure-tasks-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#failure-tasks-list').children().should('have.length', 1);
cy.get('#failure-tasks-list > .MuiTableRow-root > :nth-child(1)').should('have.text', 'dragonfly-seed-client-5');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
// Check the current page number.
cy.get('#failure-tasks-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#failure-tasks-list').children().should('have.length', 1);
cy.get('#failure-tasks-list > .MuiTableRow-root > :nth-child(1)').should('have.text', 'dragonfly-seed-client-5');
// Show error log.
cy.get('#error-log-icon').click();
cy.get('#panel1d-header').click();
cy.get('.MuiAccordionDetails-root').should(
'contain',
'task a1e21fceseba95d4407a83b3fc767da6de2a2fe35736c2ba3b95473229de1894 failed: rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 172.18.0.3:4000: connect: connection refused"',
);
});
it('should display detailed execution pending information', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingExecution,
});
interceptCount++;
},
).as('execution');
cy.get('#detail-11').click();
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist').and('contain', 11);
// Show execution id.
cy.get('#id').should('contain', 11);
// Show execution status.
cy.get('#status')
.should('have.text', 'PENDING')
.and('have.css', 'background-color', 'rgb(219, 171, 10)')
.find('#pending-icon')
.and('exist')
.find('#error-log-icon')
.and('not.exist');
cy.wait(59000);
// Check how many times the API should be executed after six seconds.
cy.get('@execution').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(2, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: failureExecution,
});
},
);
// Show execution status.
cy.get('#status')
.should('have.text', 'FAILURE')
.and('have.css', 'background-color', 'rgb(212, 37, 54)')
.find('#error-log-icon')
.and('exist');
// Show execution piece length.
cy.get('#piece-length').should('have.text', '4 MiB');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/6',
},
(req) => {
req.reply({
statusCode: 200,
body: {},
});
},
);
});
it('execution information should appear empty', () => {
// Show execution id.
cy.get('#id').should('have.text', 0);
// Show execution status.
cy.get('#status').should('not.exist');
// Show execution task id.
cy.get('#task-id').should('have.text', '-');
// Show execution content for calculating task id.
cy.get('#content-for-calculating-task-id').should('have.text', '-');
// Show execution url.
cy.get('#url').should('have.text', '-');
// Show execution piece length.
cy.get('#piece-length').should('have.text', '-');
// Show execution tag.
cy.get('#tag').should('have.text', '-');
// Show execution scheduler clusters ID.
cy.get('#scheduler-clusters-id').should('have.text', '-');
// Show execution Created At.
cy.get('#created-at').should('have.text', '-');
// Don't show failure tasks.
cy.get('#failure-tasks').should('not.exist');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/10',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/resource/task/executions/10');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('execution information should appear empty', () => {
// Show execution id.
cy.get('#id').should('have.text', 0);
// Show execution status.
cy.get('#status').should('not.exist');
// Show execution task id.
cy.get('#task-id').should('have.text', '-');
// Show execution content for calculating task id.
cy.get('#content-for-calculating-task-id').should('have.text', '-');
// Show execution url.
cy.get('#url').should('have.text', '-');
// Show execution piece length.
cy.get('#piece-length').should('have.text', '-');
// Show execution tag.
cy.get('#tag').should('have.text', '-');
// Show execution scheduler clusters ID.
cy.get('#scheduler-clusters-id').should('have.text', '-');
// Show execution Created At.
cy.get('#created-at').should('have.text', '-');
// Don't show failure tasks.
cy.get('#failure-tasks').should('not.exist');
});
it('when the status is pending, execution API error response', () => {
cy.visit('/resource/task/executions/11');
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 200,
body: pendingExecution,
});
interceptCount++;
},
).as('execution');
// Check for breadcrumb.
cy.get('.MuiBreadcrumbs-ol').should('exist').and('contain', 11);
// Show execution id.
cy.get('#id').should('contain', 11);
// Show execution status.
cy.get('#status')
.should('have.text', 'PENDING')
.and('have.css', 'background-color', 'rgb(219, 171, 10)')
.find('#pending-icon')
.and('exist')
.find('#error-log-icon')
.and('not.exist');
// Show failure tasks.
cy.get('#failure-tasks').should('exist');
cy.get('#failure-tasks-list > :nth-child(1) > :nth-child(1)').should('have.text', 'kind-worker');
cy.get('#failure-tasks-list > :nth-child(1) > :nth-child(2)').should('have.text', '172.18.0.3');
cy.wait(59000);
// Check how many times the API should be executed after six seconds.
cy.get('@execution').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(2, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs/11',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
});
});

View File

@ -0,0 +1,298 @@
import executions from '../../../fixtures/resource/task/executions.json';
import paginationExecutions from '../../../fixtures/resource/task/pagination-executions.json';
import successExecutions from '../../../fixtures/resource/task/success-executions.json';
import failureExecutions from '../../../fixtures/resource/task/failure-executions.json';
import pendingExecutions from '../../../fixtures/resource/task/pending-executions.json';
describe('Executions', () => {
beforeEach(() => {
cy.signin();
cy.visit('/resource/task/executions');
cy.viewport(1440, 1080);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=next,</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=first,</api/v1/jobs?page=2&per_page=10&state=FAILURE>;rel=last',
};
res.send(200, executions, responseHeaders);
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=2&per_page=10&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=2&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=2&per_page=10>;rel=last',
};
res.send(200, paginationExecutions, responseHeaders);
});
},
);
});
describe('when data is loaded', () => {
it('should display executions all list', () => {
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('.MuiTabs-flexContainer > .Mui-selected').should('be.visible').and('have.text', 'Executions');
cy.get('[data-testid="isloading"]').should('not.exist');
cy.get('#execution-11').should('exist').find('#PENDING-11').should('exist');
cy.get('.MuiList-root > :nth-child(3) > .MuiButtonBase-root').click();
// The executions status is displayed as PENDING.
cy.get('#execution-11').should('exist').find('#PENDING-11').should('exist');
cy.get('#id-11').should('have.text', 11);
cy.get('#task-id-11').should('have.text', 'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916');
// The executions status is displayed as FAILURE.
cy.get('#execution-10').should('exist').find('#FAILURE-10').should('exist');
cy.get('#task-id-10').should('have.text', 'fe0c4a611d35e338efd342c346a2c671c358c5187c483a5fc7cd66c6685ce916');
cy.get('#tab-clear').click();
// Then I see that the current page is the clear page!
cy.url().should('include', '/resource/task/clear');
cy.get('#tab-executions').click();
// Then I see that the current page is the executions page!
cy.url().should('include', '/resource/task/executions');
});
it('should display executions success list', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=SUCCESS&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=prev,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=next,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=first,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=last',
};
res.send(200, successExecutions, responseHeaders);
});
},
);
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="SUCCESS"]').click();
// Check how many executions are in success status.
cy.get('#executions-list').children().should('have.length', 9);
cy.get('#executions-pagination').should('not.exist');
});
it('should display executions failure list', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=FAILURE&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=FAILURE>;rel=prev,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=next,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=first,</api/v1/jobs?page=1&per_page=10&state=SUCCESS>;rel=last',
};
res.send(200, failureExecutions, responseHeaders);
});
},
);
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="FAILURE"]').click();
// Check how many executions are in success failure.
cy.get('#executions-list').children().should('have.length', 1);
});
it('should display executions pending list', () => {
let interceptCount = 0;
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=PENDING&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: '</api/v1/jobs?page=1&per_page=10&state=PENDING>;rel=prev,</api/v1/jobs?page=2&per_page=10&state=PENDING>;rel=next,</api/v1/jobs?page=1&per_page=10&state=PENDING>;rel=first,</api/v1/jobs?page=0&per_page=10&state=PENDING>;rel=last',
};
res.send(200, pendingExecutions, responseHeaders);
}),
interceptCount++;
},
).as('executions');
cy.get('.MuiInputBase-root > #states-select').click();
cy.get('[data-value="PENDING"]').click();
// Check how many executions are in pending failure.
cy.get('#executions-list').children().should('have.length', 1);
cy.wait(59000);
// The API should poll.
cy.get('@executions').then(() => {
expect(interceptCount).to.be.greaterThan(0);
expect(interceptCount).to.be.closeTo(1, 0);
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&state=PENDING&type=delete_task',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'Unauthorized' },
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
});
});
it('when no data is loaded', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=delete_task',
},
(req) => {
req.reply((res: any) => {
const responseHeaders = {
...res.headers,
Link: `
</api/v1/jobs?page=1&per_page=10>;rel=prev,</api/v1/jobs?page=1&per_page=10>;rel=next,</api/v1/jobs?page=1&per_page=10>;rel=first,</api/v1/jobs?page=1&per_page=10>;rel=last`,
};
res.send(200, [], responseHeaders);
});
},
);
// No executions list exists.
cy.get('#executions-list').should('not.exist');
// Show You don't have any executions tasks.
cy.get('#no-executions').should('be.visible').and('contain', `You don't have any executions.`);
});
it('should handle API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/jobs?page=1&per_page=10&type=delete_task',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
// Check number of pagination.
cy.get('#executions-pagination > .MuiPagination-ul').children().should('have.length', 4);
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
// The executions status is displayed as PENDING.
cy.get('#execution-11').should('exist').find('#PENDING-11').should('exist');
cy.get('#id-11').should('have.text', 11);
});
it('when pagination changes, different page results are rendered', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#executions-list').children().should('have.length', 1);
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
cy.get('.css-mu8687 > .MuiTypography-body1').should('have.text', 1);
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(4) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
// Refresh page.
cy.reload().then(() => {
cy.wait(1000);
});
// Check the current page number.
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Show page 1 executions task.
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
});
it('when returning to the previous page, pagination and results remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// Check the current page number.
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
// Go to show executions page.
cy.get('#detail-1').click();
// Then I see that the current page is the show update personal-access-tokens.
cy.url().should('include', '/resource/task/executions/1');
// Go back to the last page.
cy.go('back');
// Check the current page number.
cy.get('#executions-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#list-1').should('exist').find('#SUCCESS-1').should('exist');
});
});
});

View File

@ -0,0 +1,251 @@
import cluster from '../../fixtures/clusters/cluster/cluster.json';
import schedulers from '../../fixtures/clusters/cluster/scheduler.json';
import scheduler from '../../fixtures/schedulers/scheduler.json';
import schedulerInactive from '../../fixtures/schedulers/scheduler-inactive.json';
describe('Scheduler', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000&scheduler_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulers,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers/7',
},
(req) => {
req.reply({
statusCode: 200,
body: scheduler,
});
},
);
cy.signin();
cy.visit('/clusters/1/schedulers/7');
cy.viewport(1440, 1080);
});
it('click the hostname', () => {
cy.visit('/clusters/1/schedulers');
cy.get('#table').click();
cy.get('#hostname-scheduler-51').should('have.text', 'scheduler-51');
cy.get('#hostname-scheduler-51').click();
// Then I see that the current page is the clusters/1/schedulers/7!
cy.url().should('include', '/clusters/1/schedulers/51');
});
it('click the breadcrumb', () => {
// Check for breadcrumb.
cy.get('#cluster-id').should('be.visible').and('contain', 'scheduler-cluster-1');
cy.get('#cluster-id').click();
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
});
describe('when data is loaded', () => {
it('can display breadcrumb', () => {
// Display is loading.
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#cluster-id').should('be.visible').and('contain', 'scheduler-cluster-1');
cy.get('#scheduler-host-name').should('be.visible').and('contain', 'scheduler-7');
cy.get('[data-testid="isloading"]').should('not.exist');
});
it('can display active scheduler', () => {
// Displays the scheduler ID.
cy.get('#id').should('be.visible').and('contain', '7');
// Displays the scheduler hostname.
cy.get('#hostname').should('be.visible').and('contain', 'scheduler-7');
// Displays the scheduler IP.
cy.get('#ip').should('be.visible').and('contain', '30.44.98.202');
// Displays the scheduler cluster ID.
cy.get('#cluster-id').should('be.visible').and('contain', '1');
// Displays the scheduler port.
cy.get('#port').should('be.visible').and('contain', '8002');
// Displays the active background color.
cy.get('#status')
.should('be.visible')
.and('contain', 'Active')
.and('have.css', 'background-color', 'rgb(0, 129, 112)');
// Displays the scheduler features.
cy.get('#features').should('be.visible').and('contain', 'Schedule').and('contain', 'Preheat');
// Displays the scheduler creation time.
cy.get('#created-at').should('have.text', '2023-11-09 07:09:06');
// Displays the scheduler update time.
cy.get('#updated-at').should('have.text', '2023-11-09 07:09:11');
});
it('can display inactive scheduler', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers/2',
},
(req) => {
req.reply({
statusCode: 200,
body: schedulerInactive,
});
},
);
cy.visit('/clusters/1/schedulers/2');
// Displays the scheduler hostname.
cy.get('#hostname').should('be.visible').and('contain', 'scheduler-2');
// Displays the inactive background color.
cy.get('#status')
.should('be.visible')
.and('contain', 'Inactive')
.and('have.css', 'background-color', 'rgb(93, 95, 97)');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept({ method: 'GET', url: '/api/v1/schedulers/7' }, (req) => {
req.reply({
statusCode: 200,
body: [],
});
});
});
it('unable to display breadcrumb', () => {
cy.get('#cluster-id').should('be.visible').and('contain', 'scheduler-cluster-1');
cy.get('#scheduler-host-name').should('be.visible').and('contain', '-');
});
it('scheduler should render empty status', () => {
// Displays the scheduler ID.
cy.get('#id').should('contain', '-');
// Displays the scheduler hostname.
cy.get('#hostname').should('contain', '-');
// Displays the scheduler IP.
cy.get('#ip').should('contain', '-');
// Displays the scheduler cluster ID.
cy.get('#cluster-id').should('contain', '-');
// Displays the scheduler port.
cy.get('#port').should('contain', '-');
// Displays the scheduler status.
cy.get('#status').should('contain', '-');
// Displays the scheduler features.
cy.get('#features').should('contain', '-');
// Displays the scheduler creation time.
cy.get('#created-at').should('contain', '-');
// Displays the scheduler update time.
cy.get('#updated-at').should('contain', '-');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers/1',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.visit('/clusters/1/schedulers/1');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('unable to display breadcrumb', () => {
cy.get('#cluster-id').should('be.visible').and('contain', 'scheduler-cluster-1');
cy.get('#scheduler-host-name').should('be.visible').and('contain', '-');
});
it('scheduler should render empty status', () => {
// Displays the scheduler ID.
cy.get('#id').should('contain', '-');
// Displays the scheduler hostname.
cy.get('#hostname').should('contain', '-');
// Displays the scheduler IP.
cy.get('#ip').should('contain', '-');
// Displays the scheduler cluster ID.
cy.get('#cluster-id').should('contain', '-');
// Displays the scheduler port.
cy.get('#port').should('contain', '-');
// Displays the scheduler status.
cy.get('#status').should('contain', '-');
// Displays the scheduler features.
cy.get('#features').should('contain', '-');
// Displays the scheduler creation time.
cy.get('#created-at').should('contain', '-');
// Displays the scheduler update time.
cy.get('#updated-at').should('contain', '-');
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,250 @@
import cluster from '../../fixtures/clusters/cluster/cluster.json';
import seedPeers from '../../fixtures/clusters/cluster/seed-peer.json';
import seedPeer from '../../fixtures/seed-peers/seed-peer.json';
import seedPeerInactive from '../../fixtures/seed-peers/seed-peer-inactive.json';
describe('Seed peer', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters/1',
},
(req) => {
req.reply({
statusCode: 200,
body: cluster,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000&seed_peer_cluster_id=1',
},
(req) => {
req.reply({
statusCode: 200,
body: seedPeers,
});
},
);
cy.intercept({ method: 'GET', url: '/api/v1/seed-peers/10' }, (req) => {
req.reply({
statusCode: 200,
body: seedPeer,
});
});
cy.signin();
cy.visit('/clusters/1/seed-peers/10');
cy.viewport(1440, 1080);
});
it('click the hostname', () => {
cy.visit('/clusters/1/seed-peers');
cy.get('.MuiPagination-ul > :nth-child(4) > .MuiButtonBase-root').click();
cy.get('#card-hostname-seed-peer-10').should('have.text', 'seed-peer-10');
cy.get('#card-hostname-seed-peer-10').click();
// Then I see that the current page is the clusters/1/seed-peers/10!
cy.url().should('include', '/clusters/1/seed-peers/10');
});
it('click the breadcrumb', () => {
// Check for breadcrumb.
cy.get('#seed-peer-cluster-id').should('be.visible').and('contain', 'seed-peer-cluster-1');
cy.get('#seed-peer-cluster-id').click();
// Then I see that the current page is the clusters/1!
cy.url().should('include', '/clusters/1');
});
describe('when data is loaded', () => {
it('can display breadcrumb', () => {
// Show isloading.
cy.get('[data-testid="isloading"]').should('be.exist');
cy.get('#seed-peer-cluster-id').should('be.visible').and('contain', 'seed-peer-cluster-1');
cy.get('#seed-peer-hostname').should('be.visible').and('contain', 'seed-peer-10');
cy.get('[data-testid="isloading"]').should('not.exist');
});
it('can display active seed peer', () => {
// Displays the seed peer ID.
cy.get('#id').should('be.visible').and('contain', '10');
// Displays the seed peer hostname.
cy.get('#hostname').should('be.visible').and('contain', 'seed-peer-10');
// Displays the seed peer IP.
cy.get('#ip').should('be.visible').and('contain', '33.149.137.183');
// Displays the seed peer cluster ID.
cy.get('#cluster-id').should('be.visible').and('contain', '1');
// Displays the seed peer port.
cy.get('#port').should('be.visible').and('contain', '65006');
// Displays the seed peer Download Port.
cy.get('#download-port').should('be.visible').and('contain', '65002');
// Displays the seed peer Object Storage Port.
cy.get('#object-storage-port').should('be.visible').and('contain', '443');
// Displays the seed peer Type.
cy.get('#type').should('be.visible').and('contain', 'Supe');
// Displays the seed peer Active background color.
cy.get('#status')
.should('be.visible')
.and('contain', 'Active')
.and('have.css', 'background-color', 'rgb(0, 129, 112)');
// Displays the seed peer Created At.
cy.get('#created-at').should('have.text', '2023-11-11 20:09:08');
// Displays the seed peer Updated At.
cy.get('#updated-at').should('have.text', '2023-11-11 20:09:13');
});
it('can display inactive seed peer', () => {
cy.intercept({ method: 'GET', url: '/api/v1/seed-peers/11' }, (req) => {
req.reply({
statusCode: 200,
body: seedPeerInactive,
});
});
cy.visit('/clusters/1/seed-peers/11');
// Displays the seed peer hostname.
cy.get('#hostname').should('be.visible').and('contain', 'seed-peer-11');
// Displays the seed peer Inactive background color.
cy.get('#status')
.should('be.visible')
.and('contain', 'Inactive')
.and('have.css', 'background-color', 'rgb(93, 95, 97)');
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept({ method: 'GET', url: '/api/v1/seed-peers/9' }, (req) => {
req.reply({
statusCode: 200,
body: [],
});
});
cy.visit('/clusters/1/seed-peers/9');
});
it('unable to display breadcrumb', () => {
cy.get('#seed-peer-cluster-id').should('be.visible').and('contain', 'seed-peer-cluster-1');
cy.get('#seed-peer-hostname').should('be.visible').and('contain', '-');
});
it('seed peer should render empty status', () => {
// Displays the seed peer ID.
cy.get('#id').should('contain', '-');
// Displays the seed peer hostname.
cy.get('#hostname').should('contain', '-');
// Displays the seed peer IP.
cy.get('#ip').should('contain', '-');
// Displays the seed peer cluster ID.
cy.get('#cluster-id').should('contain', '-');
// Displays the seed peer port.
cy.get('#port').should('contain', '-');
// Displays the seed peer Download Port.
cy.get('#download-port').should('contain', '-');
// Displays the seed peer Object Storage Port.
cy.get('#object-storage-port').should('contain', '-');
// Displays the seed peer Type.
cy.get('#type').should('contain', '-');
// Show Start.
cy.get('#status').should('contain', '-');
// Displays the seed peer Created At.
cy.get('#created-at').should('contain', '-');
// Displays the seed peer Updated At.
cy.get('#updated-at').should('contain', '-');
});
});
describe('should handle API error response', () => {
beforeEach(() => {
cy.intercept({ method: 'GET', url: '/api/v1/seed-peers/1' }, (req) => {
req.reply({
forceNetworkError: true,
});
});
cy.visit('/clusters/1/seed-peers/1');
});
it('show error message', () => {
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('unable to display breadcrumb', () => {
cy.get('#seed-peer-cluster-id').should('be.visible').and('contain', 'seed-peer-cluster-1');
cy.get('#seed-peer-hostname').should('be.visible').and('contain', '-');
});
it('seed peer should render empty status', () => {
// Displays the seed peer ID.
cy.get('#id').should('contain', '-');
// Displays the seed peer hostname.
cy.get('#hostname').should('contain', '-');
// Displays the seed peer IP.
cy.get('#ip').should('contain', '-');
// Displays the seed peer cluster ID.
cy.get('#cluster-id').should('contain', '-');
// Displays the seed peer port.
cy.get('#port').should('contain', '-');
// Displays the seed peer Download Port.
cy.get('#download-port').should('contain', '-');
// Displays the seed peer Object Storage Port.
cy.get('#object-storage-port').should('contain', '-');
// Displays the seed peer Type.
cy.get('#type').should('contain', '-');
// Show Start.
cy.get('#status').should('contain', '-');
// Displays the seed peer Created At.
cy.get('#created-at').should('contain', '-');
// Displays the seed peer Updated At.
cy.get('#updated-at').should('contain', '-');
});
});
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,199 @@
import signin from '../../fixtures/signin/signin.json';
import _ from 'lodash';
describe('Signin', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/users/signin', (req) => {
const { name, password } = req.body;
if (name === 'root' && password === 'dragonfly') {
req.reply({
statusCode: 200,
body: signin,
});
} else {
req.reply({
statusCode: 401,
body: {
message: 'Unauthorized',
},
});
}
});
cy.visit('/signin');
});
it('signin with valid account and password', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/schedulers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/clusters?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/seed-peers?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.get('#account').type('root');
cy.get('#password').type(`dragonfly`);
cy.signin();
cy.get('form').submit();
// Then I see that the current page is the clusters.
cy.url().should('include', '/clusters');
cy.location('pathname').should('eq', '/clusters');
// Prompt message: Please change your password promptly when logging in for the first time!
cy.get('#change-password-warning').should('exist');
// Close the prompt message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('#change-password-warning').should('not.exist');
// Menu exists users.
cy.get('[href="/users"]').should('exist');
});
it('try to signin with valid account and invalid password', () => {
cy.get('#account').type('root');
cy.get('#password').type('rooot1');
cy.get('form').submit();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('try to signin with invalid account', () => {
cy.get('#account').type('root-1');
cy.get('#password').type('dragonfly');
cy.get('form').submit();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Unauthorized');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('try to signin with guest user', () => {
cy.intercept('POST', '/api/v1/users/signin', (req) => {
(req.body = { name: 'root-2', password: 'dragonrly' }),
req.reply({
statusCode: 200,
body: signin,
});
});
cy.get('#account').type('root-2');
cy.get('#password').type(`dragonfly`);
cy.guestSignin();
cy.get('form').submit();
// Then I see that the current page is the clusters!
cy.url().should('include', '/clusters');
cy.location('pathname').should('eq', '/clusters');
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('exist');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
// Users menu does not exist.
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
// Menu not exists for users.
cy.get('[href="/users"]').should('not.exist');
});
it('click the `Create an account` button', () => {
cy.get('#create-account').click();
// Then I see that the current page is the signup!
cy.url().should('include', '/signup');
cy.get('#sign-in').click();
// Then I see that the current page is the signin!
cy.url().should('include', '/signin');
});
it('click the password hide button', () => {
cy.get('#account').type('root');
cy.get('#password').type(`dragonfly`);
cy.get('#visibility-off').click();
cy.get('#password').should('have.value', 'dragonfly');
cy.get('#visibility').click();
cy.get('#password').should('not.have.text', 'dragonfly');
});
it('should handle API error response', () => {
cy.intercept('POST', '/api/v1/users/signin', (req) => {
(req.body = { name: 'root', password: 'dragonfly' }),
req.reply({
forceNetworkError: true,
});
});
cy.get('#account').type('root');
cy.get('#password').type(`dragonfly`);
cy.get('form').submit();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('try to verify account and password', () => {
const nameNotLongEnough = _.times(2, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const nameLengthExceeds = _.times(11, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const passwordLengthExceeds = _.times(17, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
cy.get('#account').type(nameNotLongEnough);
// Show account help text.
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#account').type(nameLengthExceeds);
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
// Show password help text.
cy.get('#password').type(passwordLengthExceeds);
cy.get('#password-helper-text')
.should('be.visible')
.and('contain', 'Fill in the characters, the maximum length is 16.');
});
});

View File

@ -0,0 +1,180 @@
import signup from '../../fixtures/signup/signup.json';
import _ from 'lodash';
describe('Signup', () => {
beforeEach(() => {
cy.intercept('POST', '/api/v1/users/signup', (req) => {
const { name, password, email } = req.body;
if (name === 'root-1' && password === 'dragonfly1' && email === 'root@console.com') {
req.reply({
statusCode: 200,
body: signup,
});
} else {
req.reply({
statusCode: 409,
body: {
message: 'Conflict',
},
});
}
});
cy.visit('/signup');
});
it('can create user account', () => {
cy.get('#account').type('root-1');
cy.get('#email').type('root@console.com');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Then I see that the current page is the signin!
cy.url().should('include', '/signin');
});
it('cannot create account with existing email', () => {
cy.get('#account').type('root-1');
cy.get('#email').type('lucy@example.com');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('cannot create account with existing account', () => {
cy.get('#account').type('root');
cy.get('#email').type('root@console.co');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('click the password hide butto and confirm password hide butto', () => {
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Click the password hide butto.
cy.get('#visibility-off').click();
// Can show password.
cy.get('#confirmPassword').should('have.value', 'dragonfly1');
cy.get('#visibility').should('be.visible');
// Click the password hide butto.
cy.get('#confirm-password-visibility-off').click();
// // Can show confirm password.
cy.get('#confirmPassword').should('have.value', 'dragonfly1');
cy.get('#confirm-password-visibility').should('be.visible');
});
it('cannot signup without required attributes', () => {
cy.get('.MuiButton-root').click();
// The help text should be displayed.
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#email-helper-text').should('be.visible').and('contain', 'Email is invalid or already taken.');
cy.get('#confirmPassword-helper-text').should('be.visible').and('contain', 'Please enter the same password.');
cy.get('#confirmPassword-helper-text').should('be.visible').and('contain', 'Please enter the same password.');
});
it('should handle API error response', () => {
cy.intercept('POST', '/api/v1/users/signup', (req) => {
(req.body = { name: 'root-1', password: 'dragonrly1', email: 'root@console.com' }),
req.reply({
forceNetworkError: true,
});
});
// Fill in the form.
cy.get('#account').type('root-1');
cy.get('#email').type('root@console.com');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
});
it('click the `Sign in` button', () => {
cy.get('#sign-in').click();
// Then I see that the current page is the signin!
cy.url().should('include', '/signin');
cy.get('#create-account').click();
// Then I see that the current page is the signup!
cy.url().should('include', '/signup');
});
it('cannot signup with invalid attributes', () => {
const nameNotLongEnough = _.times(2, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const nameLengthExceeds = _.times(11, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const passsword = _.times(8, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
// Should display message account the validation error.
cy.get('#account').type(nameNotLongEnough);
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#account').type(nameLengthExceeds);
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#account').clear();
cy.get('#account').type('root');
// Verification passed.
cy.get('#account-helper-text').should('not.exist');
// Should display message email the validation error.
cy.get('#email').type('root');
cy.get('#email-helper-text').should('be.visible').and('contain', 'Email is invalid or already taken.');
cy.get('#email').clear();
cy.get('#email').type('root@console.com');
// Verification passed.
cy.get('#email-helper-text').should('not.exist');
// Should display message password the validation error.
cy.get('#password').type(passsword);
// Missing number.
cy.get('#password-helper-text')
.should('be.visible')
.and('contain', 'At least 8-16 characters, with at least 1 lowercase letter and 1 number.');
cy.get('#password').clear();
cy.get('#password').type('dragonfly1');
// Verification passed.
cy.get('#password-helper-text').should('not.exist');
// Should display message confirm password the validation error.
cy.get('#confirmPassword').type(`dragonfly`);
// Confirm password verification error when the two passwords are not the same.
cy.get('#confirmPassword-helper-text').should('be.visible').and('contain', 'Please enter the same password.');
cy.get('#confirmPassword').clear();
cy.get('#confirmPassword').type('dragonfly1');
// verification passed.
cy.get('#confirmPassword-helper-text').should('not.exist');
});
});

View File

@ -0,0 +1,252 @@
import _ from 'lodash';
import createUsers from '../../fixtures/users/create-user.json';
import users from '../../fixtures/users/users.json';
describe('Create user', () => {
beforeEach(() => {
cy.signin();
cy.visit('/users/new');
cy.viewport(1440, 1080);
});
it('can create user', () => {
cy.visit('/users');
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: users,
});
},
);
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// There is only one piece of data on the last pag.
cy.get('#user-table-body').children().should('have.length', 1);
cy.get('#create-user').click();
// Then I see that the current page is the New user!
cy.url().should('include', '/users/new');
cy.get('.MuiBreadcrumbs-ol').should('contain', 'New user');
cy.get('#account').type('billy');
cy.get('#email').type('billy@example.com');
cy.get('#bio').type('I am billy');
cy.get('#phone').type('18012341234');
cy.get('#location').type('ParisFrance');
cy.get('#password').type('Dragonfly1');
cy.get('#confirmPassword').type('Dragonfly1');
cy.intercept('POST', '/api/v1/users/signup', (req) => {
req.reply({
statusCode: 200,
body: [],
});
});
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: createUsers,
});
},
);
cy.get('#save').click();
// Go to last page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// There is only one piece of data on the last pag.
cy.get('#user-table-body').children().should('have.length', 2);
cy.get('#user-table-body > :nth-child(2) > :nth-child(2)').should('have.text', 'billy');
});
it('cannot create account with existing email', () => {
cy.intercept('POST', '/api/v1/users/signup', (req) => {
req.reply({
statusCode: 409,
body: {
message: 'Conflict',
},
});
});
cy.get('#account').type('root-1');
cy.get('#email').type('lucy@example.com');
cy.get('#phone').type('18012341234');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
// Close error message.
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
});
it('cannot create account with existing account', () => {
cy.intercept('POST', '/api/v1/users/signup', (req) => {
req.reply({
statusCode: 409,
body: {
message: 'Conflict',
},
});
});
cy.get('#account').type('root');
cy.get('#email').type('root@console.co');
cy.get('#phone').type('18012341234');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Conflict');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
});
it('click the password hide butto and confirm password hide butto', () => {
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
cy.get('.MuiInputBase-root > .MuiButtonBase-root > [data-testid="VisibilityOffIcon"] > path').click();
cy.get('#confirmPassword').should('have.value', 'dragonfly1');
cy.get('[data-testid="VisibilityOffIcon"]').click();
cy.get('#confirmPassword').should('have.value', 'dragonfly1');
});
it('should handle API error response', () => {
cy.intercept('POST', '/api/v1/users/signup', (req) => {
req.reply({
forceNetworkError: true,
});
});
cy.get('#account').type('root-1');
cy.get('#email').type('root@console.com');
cy.get('#phone').type('18012341234');
cy.get('#password').type('dragonfly1');
cy.get('#confirmPassword').type(`dragonfly1{enter}`);
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('contain', 'Failed to fetch');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiSnackbar-root > .MuiPaper-root').should('not.exist');
});
it('click the `CANCEL button', () => {
cy.get('#cancel').click();
// Then I see that the current page is the users!
cy.url().should('include', '/users');
});
it('cannot signup with invalid attributes', () => {
const nameNotLongEnough = _.times(2, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const nameLengthExceeds = _.times(11, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const passsword = _.times(8, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
const location = _.times(101, () => _.sample('abcdefghijklmnopqrstuvwxyz')).join('');
// Should display message account the validation error.
cy.get('#account').type(nameNotLongEnough);
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#account').type(nameLengthExceeds);
cy.get('#account-helper-text').should('be.visible').and('contain', 'Fill in the characters, the length is 3-10.');
cy.get('#account').clear();
cy.get('#account').type('root');
// Verification passed.
cy.get('#account-helper-text').should('not.exist');
// Should display message email the validation error.
cy.get('#email').type('root');
cy.get('#email-helper-text').should('be.visible').and('contain', 'Email is invalid or already taken.');
cy.get('#email').clear();
cy.get('#email').type('root@console.com');
// Verification passed.
cy.get('#email-helper-text').should('not.exist');
// Should display message phone the validation error.
cy.get('#phone').type('001');
cy.get('#phone-helper-text').should('be.visible').and('contain', 'Enter a valid phone number.');
cy.get('#phone').clear();
cy.get('#phone').type('+86 19101011212');
cy.get('#phone-helper-text').should('not.exist');
// Should display message location the validation error.
cy.get('#location').clear();
cy.get('#location').type(location);
// Show verification error message.
cy.get('#location-helper-text')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 0-100.');
cy.get('#location').clear();
cy.get('#location').type('Shanghai');
cy.get('#location-helper-text').should('not.exist');
// Should display message password the validation error.
cy.get('#password').type(passsword);
// Missing number.
cy.get('#password-helper-text')
.should('be.visible')
.and('contain', 'At least 8-16 characters, with at least 1 lowercase letter and 1 number.');
cy.get('#password').clear();
cy.get('#password').type('dragonfly1');
// Verification passed.
cy.get('#password-helper-text').should('not.exist');
// Should display message confirm password the validation error.
cy.get('#confirmPassword').type(`dragonfly`);
// Confirm password verification error when the two passwords are not the same.
cy.get('#confirmPassword-helper-text').should('be.visible').and('contain', 'Please enter the same password.');
cy.get('#confirmPassword').clear();
cy.get('#confirmPassword').type('dragonfly1');
// verification passed.
cy.get('#confirmPassword-helper-text').should('not.exist');
});
});

View File

@ -0,0 +1,753 @@
import root from '../../fixtures/users/role-root.json';
import user from '../../fixtures/users/user.json';
import users from '../../fixtures/users/users.json';
import guestUser from '../../fixtures/users/guest-user.json';
import guest from '../../fixtures/users/role-guest.json';
describe('Users', () => {
beforeEach(() => {
cy.signin();
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: users,
});
},
);
cy.visit('/users');
cy.viewport(1440, 1080);
});
describe('when data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2',
},
(req) => {
req.reply({
statusCode: 200,
body: user,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: root,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: guest,
});
},
);
});
it('can display users table', () => {
// Show isloading.
cy.get('[data-testid="isloading"]').should('be.exist');
// Show root user information.
cy.get('.MuiTableBody-root > :nth-child(1) > :nth-child(2)').should('be.visible').and('have.text', 'root');
// Show root user email.
cy.get('.MuiTableBody-root > :nth-child(1) > :nth-child(3)')
.should('be.visible')
.and('have.text', 'root@example.com');
// Show root user #location.
cy.get('.MuiTableBody-root > :nth-child(1) > :nth-child(4)').should('be.visible').and('have.text', 'Shanghai');
// Show root user state.
cy.get('.MuiTableBody-root > :nth-child(1) > :nth-child(5)').should('be.visible').and('have.text', 'Enable');
// The update role button for the root user is not displayed.
cy.get('#edit-root > .MuiBox-root').should('not.exist');
// Does not show isloading.
cy.get('[data-testid="isloading"]').should('not.exist');
cy.get('#action-root').click();
// Show root user detail button.
cy.get('#detail-root').should('exist');
// Show lucy user information.
cy.get('.MuiTableBody-root > :nth-child(2) > :nth-child(2)').should('be.visible').and('have.text', 'lucy');
cy.get('.MuiTableBody-root > :nth-child(2) > :nth-child(3)')
.should('be.visible')
.and('have.text', 'lucy@example.com');
cy.get('.MuiTableBody-root > :nth-child(2) > :nth-child(4)').should('be.visible').and('have.text', 'Hangzhou');
cy.get('.MuiTableBody-root > :nth-child(2) > :nth-child(5)').should('be.visible').and('have.text', 'Enable');
cy.get('body').click('topLeft');
cy.get('#action-lucy').click();
cy.get('#edit-lucy').should('exist');
cy.get('#detail-lucy').should('exist');
// Show jack user information.
cy.get('.MuiTableBody-root > :nth-child(3) > :nth-child(2)').should('be.visible').and('have.text', 'jack');
cy.get('.MuiTableBody-root > :nth-child(3) > :nth-child(3)')
.should('be.visible')
.and('have.text', 'jack@example.com');
cy.get('.MuiTableBody-root > :nth-child(3) > :nth-child(4)').should('be.visible').and('have.text', 'Shanghai');
cy.get('.MuiTableBody-root > :nth-child(3) > :nth-child(5)').should('be.visible').and('have.text', 'Enable');
// Close menu.
cy.get('body').click('topLeft');
cy.get('#action-jack').click();
cy.get('#edit-jack').should('exist');
cy.get('#detail-jack').should('exist');
});
it('can display user detail', () => {
// Click detail button.
cy.get('#action-root').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #detail-root').click();
// Display user lucy details.
cy.get('.MuiDrawer-root > .MuiPaper-root').should('be.visible');
cy.get('#id').should('have.text', 1);
cy.get('#name').should('have.text', 'root');
cy.get('#role').should('have.text', 'root');
cy.get('#email').should('have.text', 'root@example.com');
cy.get('#phone').should('have.text', '+86 153 1234 5678');
cy.get('#location').should('have.text', 'Hangzhou');
cy.get('#created-at').should('contain', '2023-11-06 06:09:04');
cy.get('#updated-at').should('contain', '2023-11-06 06:09:04');
// closure user details.
cy.get('#closure-user-detail').click();
cy.get('#action-jack').click();
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3',
},
(req) => {
req.reply((res) => {
res.setDelay(1000);
res.send({
statusCode: 200,
body: guestUser,
});
});
},
);
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #detail-jack').click();
cy.get('[data-testid="detail-isloading"]').should('be.exist');
// Display user jack details.
cy.get('.MuiDrawer-root > .MuiPaper-root').should('be.visible');
cy.get('#id').should('have.text', 2);
cy.get('#name').should('have.text', 'jack');
cy.get('#role').should('have.text', 'guest');
cy.get('#email').should('have.text', 'jack@example.com');
cy.get('#phone').should('have.text', '+86 153 1234 5678');
cy.get('#location').should('have.text', 'Shanghai');
cy.get('#created-at').should('contain', '2023-11-07 06:09:04');
cy.get('#updated-at').should('contain', '2023-11-07 06:09:04');
cy.get('[data-testid="detail-isloading"]').should('not.exist');
});
it('can display update user', () => {
// Click update user button.
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
// Check role.
cy.get('#role-root').should('be.checked').check({ force: true });
cy.get('#role-guest');
cy.get('body').click('topLeft');
cy.get('#action-jack').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-jack').click();
cy.get('#role-root').should('not.be.checked');
cy.get('#role-guest').should('be.checked').check({ force: true });
});
});
describe('when no data is loaded', () => {
beforeEach(() => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/1',
},
(req) => {
req.reply({
statusCode: 200,
body: user,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/1/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: root,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
statusCode: 200,
body: [],
});
},
);
cy.visit('/users');
cy.viewport(1440, 1080);
});
it('cannot display users table', () => {
cy.get('#user-table-row').should('not.exist');
});
});
it('try to show users page using guest user', () => {
cy.guestSignin();
// The 404 page is displayed and the user page does not exist.
cy.get('#something-went-wrong').should('have.text', 'Something gone wrong!');
cy.get('#404-help-text').should('have.text', `The page you were looking for doesn't exist.`);
});
describe('get role API error response', () => {
it('cannot display users table', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users?page=1&per_page=10000000',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Failed to fetch');
});
it('user detail should render empty', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3/roles',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#action-jack').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #detail-jack').click();
// Display user jack details.
cy.get('#id').should('have.text', 0);
cy.get('#name').should('have.text', '-');
cy.get('.MuiList-root > :nth-child(7)').should('contain', '-');
cy.get('#email').should('have.text', '-');
cy.get('#phone').should('have.text', '-');
cy.get('#location').should('have.text', '-');
cy.get('#created-at').should('contain', '-');
cy.get('#updated-at').should('contain', '-');
});
});
describe('pagination', () => {
it('pagination updates results and page number', () => {
cy.get('#user-pagination').should('exist');
// Check number of pagination.
cy.get('#user-pagination > .MuiPagination-ul').children().should('have.length', 4);
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '1');
});
it('when pagination changes, different page results are rendered', () => {
cy.get('.MuiTableBody-root > :nth-child(1) > :nth-child(2)').should('be.visible').and('have.text', 'root');
// There are ten users on the current page.
cy.get('#user-table-body').children().should('have.length', 10);
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
cy.get('#user-table-row > :nth-child(2)').should('be.visible').and('have.text', 'noah');
// There is only one user on the current page.
cy.get('#user-table-body').children().should('have.length', 1);
// Check the current page number.
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
});
it('when you click refresh, the paginated results and page numbers remain unchanged.', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// There is only one user on the current page.
cy.get('#user-table-body').children().should('have.length', 1);
// Check the current page number.
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
// Refresh page.
cy.reload().then(() => {
cy.wait(2000);
});
// There are ten users on the current page.
cy.get('#user-table-body').children().should('have.length', 1);
// Check the current page number.
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
});
it('when returning to the previous page, pagination and results remain unchanged', () => {
// Go to next page.
cy.get('.MuiPagination-ul > :nth-child(3) > .MuiButtonBase-root').click();
// There is only one user on the current page.
cy.get('#user-table-body').children().should('have.length', 1);
// Check the current page number.
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#clusters').click();
// Then I see that the current page is the show update personal-access-tokens.
cy.url().should('include', '/clusters');
// Go back to the last page。
cy.go('back');
// There is only one user on the current page.
cy.get('#user-table-body').children().should('have.length', 1);
// Check the current page number.
cy.get('#user-pagination > .MuiPagination-ul .Mui-selected').should('have.text', '2');
cy.get('#user-table-row > :nth-child(2)').should('have.text', 'noah');
});
});
describe('update role', () => {
it('can change the root user to the guest user', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: root,
});
},
);
cy.intercept(
{
method: 'PUT',
url: '/api/v1/users/2/roles/guest',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/users/2/roles/root',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
cy.get('#role-root').should('be.checked').check({ force: true });
cy.get('#role-guest').should('not.be.checked');
// Switch role to guest.
cy.get('#role-guest').click();
cy.get('#save').click();
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: ['guest'],
});
},
);
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
// Change success message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Submission successful!');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.get('.MuiAlert-message').should('not.exist');
// Check role.
cy.get('#role-root').should('not.be.checked');
cy.get('#role-guest').should('be.checked').check({ force: true });
});
it('can change the guest user to the root user', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: guest,
});
},
);
cy.intercept(
{
method: 'PUT',
url: '/api/v1/users/3/roles/root',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/users/3/roles/guest',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.get('#action-jack').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-jack').click();
// Check if role is guest.
cy.get('#role-root').should('not.be.checked');
cy.get('#role-guest').should('be.checked').check({ force: true });
// Switch role to root.
cy.get('#role-root').click();
cy.get('#save').click();
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Submission successful!');
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/3/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: ['root'],
});
},
);
cy.get('#action-jack').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-jack').click();
// Check if role is root.
cy.get('#role-root').should('be.checked').check({ force: true });
cy.get('#role-guest').should('not.be.checked');
});
it('try using root user to change to guest user and then update to root user', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: root,
});
},
);
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2',
},
(req) => {
req.reply({
statusCode: 200,
body: user,
});
},
);
const jwtToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MDAwNTExMDcsImlkIjoyLCJvcmlnX2lhdCI6MTY5OTg3ODMwN30.GynYMK_KKFfbAe_NAtFgthmEg_p8xKJOu_ZhRkr1ECE';
cy.setCookie('jwt', jwtToken);
cy.intercept(
{
method: 'PUT',
url: '/api/v1/users/2/roles/guest',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/users/2/roles/root',
},
(req) => {
req.reply({
statusCode: 200,
});
},
);
// Click edit button.
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
cy.get('#role-root').should('be.checked').check({ force: true });
cy.get('#role-guest').should('not.be.checked');
cy.get('#role-guest').click();
cy.get('#save').click();
// Change success message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Submission successful!');
cy.get('.MuiAlert-action > .MuiButtonBase-root').click();
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: ['guest'],
});
},
);
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
// Check role.
cy.get('#role-root').should('not.be.checked');
cy.get('#role-guest').should('be.checked').check({ force: true });
// Switch role to guest.
cy.get('#role-root').click();
cy.intercept(
{
method: 'PUT',
url: '/api/v1/users/2/roles/root',
},
(req) => {
req.reply({
statusCode: 401,
body: { message: 'permission deny' },
});
},
);
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'permission deny');
});
it('get role API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Failed to fetch');
// Check role.
cy.get('#role-root').should('not.be.checked');
cy.get('#role-guest').should('not.be.checked');
});
it('change role API error response', () => {
cy.intercept(
{
method: 'GET',
url: '/api/v1/users/2/roles',
},
(req) => {
req.reply({
statusCode: 200,
body: root,
});
},
);
cy.intercept(
{
method: 'PUT',
url: '/api/v1/users/2/roles/guest',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.intercept(
{
method: 'DELETE',
url: '/api/v1/users/2/roles/root',
},
(req) => {
req.reply({
forceNetworkError: true,
});
},
);
cy.get('#action-lucy').click();
cy.get(':nth-child(12) > .MuiPaper-root > .MuiList-root > .users_menu__4L0WC > #edit-lucy').click();
// Check if role is root.
cy.get('#role-root').should('be.checked').check({ force: true });
cy.get('#role-guest').should('not.be.checked');
cy.get('#role-guest').click();
cy.get('#save').click();
// Show error message.
cy.get('.MuiAlert-message').should('be.visible').and('have.text', 'Failed to fetch');
});
});
describe('search', () => {
it('can search for user name', () => {
cy.get('#user-table-body').children().should('have.length', 10);
// Enter user name root.
cy.get('#search-user').type('root');
// Check table.
cy.get('#user-table-body').children().should('have.length', 1);
cy.get('#user-name-root').should('have.text', 'root');
});
it('should be queried based on the query string', () => {
cy.visit('/users?search=jack');
// The search box should be jack.
cy.get('#search-user').should('have.value', 'jack');
cy.get('#user-name-jack').should('have.text', 'jack');
});
it('should search for non-existent user name', () => {
cy.get('#search-user').type('dragonfly');
// No users.
cy.get('#no-user-table').should('have.text', `You don't have user.`);
});
});
});

View File

@ -0,0 +1,17 @@
[
{
"id": 12,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "PAT",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,47 @@
[
{
"id": 7,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 10,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
},
{
"id": 11,
"created_at": "2025-05-20T02:34:44.139Z",
"updated_at": "2025-05-20T02:34:44.139Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-20T02:34:41Z",
"state": "FAILURE",
"path": "/api/v1/users/signin",
"status_code": 401,
"detail": null
}
]

View File

@ -0,0 +1,137 @@
[
{
"id": 1,
"created_at": "2025-05-26T03:19:25.585Z",
"updated_at": "2025-05-26T03:19:25.585Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:23Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 2,
"created_at": "2025-05-26T03:19:20.594Z",
"updated_at": "2025-05-26T03:19:20.594Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:16Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 3,
"created_at": "2025-05-26T03:19:18.583Z",
"updated_at": "2025-05-26T03:19:18.583Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:17Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 4,
"created_at": "2025-05-26T03:19:13.659Z",
"updated_at": "2025-05-26T03:19:13.659Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:09Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 5,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 6,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 8,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 9,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 13,
"created_at": "2025-05-19T08:09:16.26Z",
"updated_at": "2025-05-19T08:09:16.26Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-19T08:09:14Z",
"state": "SUCCESS",
"path": "/api/v1/users/3",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,152 @@
[
{
"id": 1,
"created_at": "2025-05-26T03:19:25.585Z",
"updated_at": "2025-05-26T03:19:25.585Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:23Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 2,
"created_at": "2025-05-26T03:19:20.594Z",
"updated_at": "2025-05-26T03:19:20.594Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:16Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 3,
"created_at": "2025-05-26T03:19:18.583Z",
"updated_at": "2025-05-26T03:19:18.583Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:17Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 4,
"created_at": "2025-05-26T03:19:13.659Z",
"updated_at": "2025-05-26T03:19:13.659Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:09Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 5,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 6,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 7,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 8,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 9,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 10,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,32 @@
[
{
"id": 11,
"created_at": "2025-05-20T02:34:44.139Z",
"updated_at": "2025-05-20T02:34:44.139Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-20T02:34:41Z",
"state": "FAILURE",
"path": "/api/v1/users/signin",
"status_code": 401,
"detail": null
},
{
"id": 14,
"created_at": "2025-05-19T08:09:30.125Z",
"updated_at": "2025-05-19T08:09:30.125Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "PATCH",
"operated_at": "2025-05-19T08:09:28Z",
"state": "FAILURE",
"path": "/api/v1/clusters/1",
"status_code": 401,
"detail": null
}
]

View File

@ -0,0 +1,17 @@
[
{
"id": 15,
"created_at": "2025-05-21T09:03:51.518Z",
"updated_at": "2025-05-21T09:03:51.518Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "DELETE",
"operated_at": "2025-05-21T09:03:50Z",
"state": "SUCCESS",
"path": "/api/v1/personal-access-tokens/1",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,152 @@
[
{
"id": 1,
"created_at": "2025-05-26T03:19:25.585Z",
"updated_at": "2025-05-26T03:19:25.585Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:23Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 2,
"created_at": "2025-05-26T03:19:20.594Z",
"updated_at": "2025-05-26T03:19:20.594Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:16Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 3,
"created_at": "2025-05-26T03:19:18.583Z",
"updated_at": "2025-05-26T03:19:18.583Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:17Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 4,
"created_at": "2025-05-26T03:19:13.659Z",
"updated_at": "2025-05-26T03:19:13.659Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:09Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 5,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 6,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 7,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 8,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users/1",
"status_code": 200,
"detail": null
},
{
"id": 9,
"created_at": "2025-05-26T03:19:08.613Z",
"updated_at": "2025-05-26T03:19:08.613Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/audits",
"status_code": 200,
"detail": null
},
{
"id": 13,
"created_at": "2025-05-19T08:09:16.26Z",
"updated_at": "2025-05-19T08:09:16.26Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-19T08:09:14Z",
"state": "SUCCESS",
"path": "/api/v1/users/3",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,17 @@
[
{
"id": 14,
"created_at": "2025-05-19T08:09:30.125Z",
"updated_at": "2025-05-19T08:09:30.125Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "PATCH",
"operated_at": "2025-05-19T08:09:28Z",
"state": "FAILURE",
"path": "/api/v1/clusters/1",
"status_code": 401,
"detail": null
}
]

View File

@ -0,0 +1,47 @@
[
{
"id": 10,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
},
{
"id": 11,
"created_at": "2025-05-20T02:34:44.139Z",
"updated_at": "2025-05-20T02:34:44.139Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-20T02:34:41Z",
"state": "FAILURE",
"path": "/api/v1/users/signin",
"status_code": 401,
"detail": null
},
{
"id": 12,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "PAT",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,17 @@
[
{
"id": 16,
"created_at": "2025-05-21T09:16:16.348Z",
"updated_at": "2025-05-21T09:16:16.348Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "PUT",
"operated_at": "2025-05-21T09:16:15Z",
"state": "SUCCESS",
"path": "/api/v1/users/2/roles/root",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,92 @@
[
{
"id": 11,
"created_at": "2025-05-20T02:34:44.139Z",
"updated_at": "2025-05-20T02:34:44.139Z",
"is_del": 0,
"actor_type": "UNKNOWN",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-20T02:34:41Z",
"state": "FAILURE",
"path": "/api/v1/users/signin",
"status_code": 401,
"detail": null
},
{
"id": 12,
"created_at": "2025-05-21T02:34:11.025Z",
"updated_at": "2025-05-21T02:34:11.025Z",
"is_del": 0,
"actor_type": "PAT",
"actor_name": "unknown",
"event_type": "API",
"operation": "POST",
"operated_at": "2025-05-21T02:34:07Z",
"state": "SUCCESS",
"path": "/api/v1/users/signin",
"status_code": 200,
"detail": null
},
{
"id": 13,
"created_at": "2025-05-19T08:09:16.26Z",
"updated_at": "2025-05-19T08:09:16.26Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-19T08:09:14Z",
"state": "SUCCESS",
"path": "/api/v1/users/3",
"status_code": 200,
"detail": null
},
{
"id": 14,
"created_at": "2025-05-19T08:09:30.125Z",
"updated_at": "2025-05-19T08:09:30.125Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "PATCH",
"operated_at": "2025-05-19T08:09:28Z",
"state": "FAILURE",
"path": "/api/v1/clusters/1",
"status_code": 401,
"detail": null
},
{
"id": 15,
"created_at": "2025-05-21T09:03:51.518Z",
"updated_at": "2025-05-21T09:03:51.518Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "DELETE",
"operated_at": "2025-05-21T09:03:50Z",
"state": "SUCCESS",
"path": "/api/v1/personal-access-tokens/1",
"status_code": 200,
"detail": null
},
{
"id": 16,
"created_at": "2025-05-21T09:16:16.348Z",
"updated_at": "2025-05-21T09:16:16.348Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "root",
"event_type": "API",
"operation": "PUT",
"operated_at": "2025-05-21T09:16:15Z",
"state": "SUCCESS",
"path": "/api/v1/users/2/roles/root",
"status_code": 200,
"detail": null
}
]

View File

@ -0,0 +1,47 @@
[
{
"id": 5,
"created_at": "2025-05-26T03:19:08.822Z",
"updated_at": "2025-05-26T03:19:08.822Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-26T03:19:08Z",
"state": "SUCCESS",
"path": "/api/v1/users",
"status_code": 200,
"detail": null
},
{
"id": 13,
"created_at": "2025-05-19T08:09:16.26Z",
"updated_at": "2025-05-19T08:09:16.26Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "GET",
"operated_at": "2025-05-19T08:09:14Z",
"state": "SUCCESS",
"path": "/api/v1/users/3",
"status_code": 200,
"detail": null
},
{
"id": 14,
"created_at": "2025-05-19T08:09:30.125Z",
"updated_at": "2025-05-19T08:09:30.125Z",
"is_del": 0,
"actor_type": "USER",
"actor_name": "jack",
"event_type": "API",
"operation": "PATCH",
"operated_at": "2025-05-19T08:09:28Z",
"state": "FAILURE",
"path": "/api/v1/clusters/1",
"status_code": 401,
"detail": null
}
]

View File

@ -0,0 +1,27 @@
{
"id": 1,
"name": "cluster-1",
"bio": "Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.",
"scopes": {
"idc": "Hangzhou|Shanghai|Beijing|Xiamen|Nanchang",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12", "173.16.0.1/11", "171.18.2.1/21"],
"hostnames": ["cluster-1", "cluster-2", "cluster-3", "cluster-4"]
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 15
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 51
},
"created_at": "2023-10-31T07:48:35Z",
"updated_at": "2023-10-31T07:48:35Z",
"is_default": true
}

View File

@ -0,0 +1,27 @@
{
"id": 10,
"name": "cluster-10",
"bio": "Cluster-10 is a high-performance computing cluster located in England, specifically in London data centers.",
"scopes": {
"idc": "London",
"location": "London|England",
"cidrs": ["192.168.255.255"],
"hostnames": ["cluster-1"]
},
"scheduler_cluster_id": 10,
"seed_peer_cluster_id": 10,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-15T05:19:36Z",
"updated_at": "2023-11-15T05:19:36Z",
"is_default": true
}

View File

@ -0,0 +1,904 @@
[
{
"id": 1,
"name": "cluster-1",
"bio": "Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.",
"scopes": {
"idc": "Hangzhou|Shanghai|Beijing",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"],
"hostnames": null
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 51
},
"created_at": "2023-10-31T07:48:35Z",
"updated_at": "2023-10-31T07:48:35Z",
"is_default": true
},
{
"id": 2,
"name": "cluster-2",
"bio": "",
"scopes": {
"idc": "",
"location": "",
"cidrs": []
},
"scheduler_cluster_id": 2,
"seed_peer_cluster_id": 2,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-10-31T17:48:35Z",
"updated_at": "2023-10-31T17:48:35Z",
"is_default": false
},
{
"id": 3,
"name": "cluster-3",
"bio": "Cluster-3 is a high-performance computing cluster located in Korea, specifically in Seoul data centers.",
"scopes": {
"idc": "Korea",
"location": "Seoul|Korea",
"cidrs": ["192.168.0.0/16", "172.16.0.0/12"]
},
"scheduler_cluster_id": 3,
"seed_peer_cluster_id": 3,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-08T11:19:36Z",
"updated_at": "2023-11-08T11:19:36Z",
"is_default": true
},
{
"id": 4,
"name": "cluster-4",
"bio": "Cluster-4 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|dl",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 4,
"seed_peer_cluster_id": 4,
"scheduler_cluster_config": {
"candidate_parent_limit": 5,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T18:19:36Z",
"updated_at": "2023-11-09T18:19:36Z",
"is_default": true
},
{
"id": 5,
"name": "cluster-5",
"bio": "Cluster-5 is a high-performance computing cluster located in China, specifically in Chongqing data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Qing",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 5,
"seed_peer_cluster_id": 5,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 6,
"name": "cluster-6",
"bio": "Cluster-6 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Du",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 6,
"seed_peer_cluster_id": 6,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T20:12:36Z",
"updated_at": "2023-11-09T20:12:36Z",
"is_default": true
},
{
"id": 7,
"name": "cluster-7",
"bio": "Cluster-7 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cd",
"location": "China|Cheng|Du",
"cidrs": ["10.0.0.0/8", "172.16.0.0/19"]
},
"scheduler_cluster_id": 7,
"seed_peer_cluster_id": 7,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:19:36Z",
"updated_at": "2023-11-11T10:19:36Z",
"is_default": true
},
{
"id": 8,
"name": "cluster-8",
"bio": "Cluster-8 is a high-performance computing cluster located in China, specifically in Jiangsu data centers.",
"scopes": {
"idc": "js",
"location": "China|Jiang|Su",
"cidrs": ["10.0.0.0/5", "172.16.0.0/19"]
},
"scheduler_cluster_id": 8,
"seed_peer_cluster_id": 8,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T13:19:36Z",
"updated_at": "2023-11-11T13:19:36Z",
"is_default": false
},
{
"id": 9,
"name": "cluster-9",
"bio": "Cluster-9 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|hf",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 9,
"seed_peer_cluster_id": 9,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:29:36Z",
"updated_at": "2023-11-11T10:29:36Z",
"is_default": true
},
{
"id": 11,
"name": "cluster-11",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 11,
"seed_peer_cluster_id": 11,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 12,
"name": "cluster-12",
"bio": "Cluster-12 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 12,
"seed_peer_cluster_id": 12,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-01T10:19:36Z",
"updated_at": "2023-12-01T10:19:36Z",
"is_default": false
},
{
"id": 13,
"name": "cluster-13",
"bio": "Cluster-13 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 13,
"seed_peer_cluster_id": 13,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-03T10:19:36Z",
"updated_at": "2023-12-03T10:19:36Z",
"is_default": false
},
{
"id": 14,
"name": "cluster-14",
"bio": "Cluster-14 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 14,
"seed_peer_cluster_id": 14,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-04T10:19:36Z",
"updated_at": "2023-12-04T10:19:36Z",
"is_default": false
},
{
"id": 15,
"name": "cluster-15",
"bio": "Cluster-15 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 15,
"seed_peer_cluster_id": 15,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-05T10:19:36Z",
"updated_at": "2023-12-05T10:19:36Z",
"is_default": false
},
{
"id": 16,
"name": "cluster-16",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 16,
"seed_peer_cluster_id": 16,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 17,
"name": "cluster-17",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 17,
"seed_peer_cluster_id": 17,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 18,
"name": "cluster-18",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 18,
"seed_peer_cluster_id": 18,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 19,
"name": "cluster-19",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.198.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 19,
"seed_peer_cluster_id": 19,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 20,
"name": "cluster-20",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.208.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 20,
"seed_peer_cluster_id": 20,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 21,
"name": "cluster-21",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.218.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 21,
"seed_peer_cluster_id": 21,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 22,
"name": "cluster-22",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.228.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 22,
"seed_peer_cluster_id": 22,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 23,
"name": "cluster-23",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.238.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 23,
"seed_peer_cluster_id": 23,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 24,
"name": "cluster-24",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.248.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 24,
"seed_peer_cluster_id": 24,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 25,
"name": "cluster-25",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.258.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 25,
"seed_peer_cluster_id": 25,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 26,
"name": "cluster-26",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.268.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 26,
"seed_peer_cluster_id": 26,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 27,
"name": "cluster-27",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.278.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 27,
"seed_peer_cluster_id": 27,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 28,
"name": "cluster-28",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.288.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 28,
"seed_peer_cluster_id": 28,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 29,
"name": "cluster-29",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.298.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 29,
"seed_peer_cluster_id": 29,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 30,
"name": "cluster-30",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.308.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 30,
"seed_peer_cluster_id": 30,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 31,
"name": "cluster-31",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.318.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 31,
"seed_peer_cluster_id": 31,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 32,
"name": "cluster-32",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.328.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 32,
"seed_peer_cluster_id": 32,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 33,
"name": "cluster-33",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.338.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 33,
"seed_peer_cluster_id": 33,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 34,
"name": "cluster-34",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.348.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 34,
"seed_peer_cluster_id": 34,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 35,
"name": "cluster-35",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.358.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 35,
"seed_peer_cluster_id": 35,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 36,
"name": "cluster-36",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.368.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 36,
"seed_peer_cluster_id": 36,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 37,
"name": "cluster-37",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.378.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 37,
"seed_peer_cluster_id": 37,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
}
]

View File

@ -0,0 +1,226 @@
[
{
"id": 1,
"created_at": "2023-11-06T06:09:08Z",
"updated_at": "2023-11-06T06:09:13Z",
"is_del": 0,
"host_name": "seed-peer-1",
"type": "super",
"idc": "cd",
"location": "Chengdu",
"ip": "30.44.98.202",
"port": 65006,
"download_port": 65008,
"object_storage_port": 443,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 2,
"created_at": "2022-12-23T15:51:56+08:00",
"updated_at": "2023-11-09T06:12:32+08:00",
"is_del": 0,
"host_name": "seed-peer-2",
"type": "super",
"idc": "sh",
"location": "Shanghai",
"ip": "33.149.137.183",
"port": 65000,
"download_port": 65002,
"object_storage_port": 80,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 4,
"created_at": "2023-11-09T06:12:32+08:00",
"updated_at": "2023-11-09T06:12:32+08:00",
"is_del": 0,
"host_name": "seed-peer-4",
"type": "super",
"idc": "Berlin",
"location": "Berlin|Germany",
"ip": "33.149.137.183",
"port": 65000,
"download_port": 65002,
"object_storage_port": 443,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 5,
"created_at": "2023-11-10T06:09:08Z",
"updated_at": "2023-11-10T06:09:13Z",
"is_del": 0,
"host_name": "seed-peer-5",
"type": "super",
"idc": "washington",
"location": "United|tates|Washington",
"ip": "30.44.98.202",
"port": 65006,
"download_port": 65008,
"object_storage_port": 443,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 6,
"created_at": "2023-11-10T16:09:08Z",
"updated_at": "2023-11-10T16:09:13Z",
"is_del": 0,
"host_name": "seed-peer-6",
"type": "super",
"idc": "Seoul",
"location": "Seoul|Korea",
"ip": "33.149.137.183",
"port": 65000,
"download_port": 65002,
"object_storage_port": 0,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 7,
"created_at": "2023-11-10T17:09:08Z",
"updated_at": "2023-11-10T17:09:13Z",
"is_del": 0,
"host_name": "seed-peer-7",
"type": "super",
"idc": "Seoul",
"location": "Seoul|Korea",
"ip": "30.44.98.202",
"port": 65006,
"download_port": 65008,
"object_storage_port": 0,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 8,
"created_at": "2023-11-10T20:09:08Z",
"updated_at": "2023-11-10T20:09:13Z",
"is_del": 0,
"host_name": "seed-peer-8",
"type": "super",
"idc": "sy",
"location": "China|sheng|yang",
"ip": "33.149.137.183",
"port": 65000,
"download_port": 65002,
"object_storage_port": 0,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
},
{
"id": 10,
"created_at": "2023-11-11T20:09:08Z",
"updated_at": "2023-11-11T20:09:13Z",
"is_del": 0,
"host_name": "seed-peer-10",
"type": "super",
"idc": "hz",
"location": "Hangzhou",
"ip": "192.168.255.255",
"port": 65006,
"download_port": 65002,
"object_storage_port": 443,
"state": "active",
"seed_peer_cluster_id": 1,
"seed_peer_cluster": {
"id": 1,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"name": "cluster-1",
"bio": "cluster-1",
"config": null,
"scheduler_clusters": null,
"seed_peer": null,
"jobs": null
}
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
{
"id": 1,
"name": "cluster-1",
"bio": "update cluster-1",
"scopes": {
"idc": "Hangzhou|Shanghai",
"location": "China|Shang|Hai",
"cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "192.168.20.2"],
"hostnames": ["cluster-1"]
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
"scheduler_cluster_config": {
"candidate_parent_limit": 5,
"filter_parent_limit": 50,
"job_rate_limit": 20
},
"seed_peer_cluster_config": {
"load_limit": 400
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-10-31T07:48:35Z",
"updated_at": "2023-10-31T07:48:35Z",
"is_default": false
}

View File

@ -0,0 +1,929 @@
[
{
"id": 1,
"name": "cluster-1",
"bio": "Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.",
"scopes": {
"idc": "Hangzhou|Shanghai|Beijing",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"],
"hostnames": null
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 51
},
"created_at": "2023-10-31T07:48:35Z",
"updated_at": "2023-10-31T07:48:35Z",
"is_default": true
},
{
"id": 2,
"name": "cluster-2",
"bio": "",
"scopes": {
"idc": "",
"location": "",
"cidrs": []
},
"scheduler_cluster_id": 2,
"seed_peer_cluster_id": 2,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-10-31T17:48:35Z",
"updated_at": "2023-10-31T17:48:35Z",
"is_default": false
},
{
"id": 3,
"name": "cluster-3",
"bio": "Cluster-3 is a high-performance computing cluster located in Korea, specifically in Seoul data centers.",
"scopes": {
"idc": "Korea",
"location": "Seoul|Korea",
"cidrs": ["192.168.0.0/16", "172.16.0.0/12"]
},
"scheduler_cluster_id": 3,
"seed_peer_cluster_id": 3,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-08T11:19:36Z",
"updated_at": "2023-11-08T11:19:36Z",
"is_default": true
},
{
"id": 4,
"name": "cluster-4",
"bio": "Cluster-4 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|dl",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 4,
"seed_peer_cluster_id": 4,
"scheduler_cluster_config": {
"candidate_parent_limit": 5,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T18:19:36Z",
"updated_at": "2023-11-09T18:19:36Z",
"is_default": true
},
{
"id": 5,
"name": "cluster-5",
"bio": "Cluster-5 is a high-performance computing cluster located in China, specifically in Chongqing data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Qing",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 5,
"seed_peer_cluster_id": 5,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 6,
"name": "cluster-6",
"bio": "Cluster-6 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Du",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 6,
"seed_peer_cluster_id": 6,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T20:12:36Z",
"updated_at": "2023-11-09T20:12:36Z",
"is_default": true
},
{
"id": 7,
"name": "cluster-7",
"bio": "Cluster-7 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cd",
"location": "China|Cheng|Du",
"cidrs": ["10.0.0.0/8", "172.16.0.0/19"]
},
"scheduler_cluster_id": 7,
"seed_peer_cluster_id": 7,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:19:36Z",
"updated_at": "2023-11-11T10:19:36Z",
"is_default": true
},
{
"id": 8,
"name": "cluster-8",
"bio": "Cluster-8 is a high-performance computing cluster located in China, specifically in Jiangsu data centers.",
"scopes": {
"idc": "js",
"location": "China|Jiang|Su",
"cidrs": ["10.0.0.0/5", "172.16.0.0/19"]
},
"scheduler_cluster_id": 8,
"seed_peer_cluster_id": 8,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T13:19:36Z",
"updated_at": "2023-11-11T13:19:36Z",
"is_default": false
},
{
"id": 9,
"name": "cluster-9",
"bio": "Cluster-9 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|hf",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 9,
"seed_peer_cluster_id": 9,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:29:36Z",
"updated_at": "2023-11-11T10:29:36Z",
"is_default": true
},
{
"id": 10,
"name": "cluster-10",
"bio": "Cluster-10 is a high-performance computing cluster located in England, specifically in London data centers.",
"scopes": {
"idc": "London",
"location": "London|England",
"cidrs": ["192.168.255.255"]
},
"scheduler_cluster_id": 10,
"seed_peer_cluster_id": 10,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-15T05:19:36Z",
"updated_at": "2023-11-15T05:19:36Z",
"is_default": true
},
{
"id": 11,
"name": "cluster-11",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 11,
"seed_peer_cluster_id": 11,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 12,
"name": "cluster-12",
"bio": "Cluster-12 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 12,
"seed_peer_cluster_id": 12,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-01T10:19:36Z",
"updated_at": "2023-12-01T10:19:36Z",
"is_default": false
},
{
"id": 13,
"name": "cluster-13",
"bio": "Cluster-13 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 13,
"seed_peer_cluster_id": 13,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-03T10:19:36Z",
"updated_at": "2023-12-03T10:19:36Z",
"is_default": false
},
{
"id": 14,
"name": "cluster-14",
"bio": "Cluster-14 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 14,
"seed_peer_cluster_id": 14,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-04T10:19:36Z",
"updated_at": "2023-12-04T10:19:36Z",
"is_default": false
},
{
"id": 15,
"name": "cluster-15",
"bio": "Cluster-15 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 15,
"seed_peer_cluster_id": 15,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-05T10:19:36Z",
"updated_at": "2023-12-05T10:19:36Z",
"is_default": false
},
{
"id": 16,
"name": "cluster-16",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 16,
"seed_peer_cluster_id": 16,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 17,
"name": "cluster-17",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 17,
"seed_peer_cluster_id": 17,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 18,
"name": "cluster-18",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 18,
"seed_peer_cluster_id": 18,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 19,
"name": "cluster-19",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.198.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 19,
"seed_peer_cluster_id": 19,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 20,
"name": "cluster-20",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.208.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 20,
"seed_peer_cluster_id": 20,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 21,
"name": "cluster-21",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.218.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 21,
"seed_peer_cluster_id": 21,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 22,
"name": "cluster-22",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.228.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 22,
"seed_peer_cluster_id": 22,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 23,
"name": "cluster-23",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.238.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 23,
"seed_peer_cluster_id": 23,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 24,
"name": "cluster-24",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.248.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 24,
"seed_peer_cluster_id": 24,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 25,
"name": "cluster-25",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.258.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 25,
"seed_peer_cluster_id": 25,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 26,
"name": "cluster-26",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.268.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 26,
"seed_peer_cluster_id": 26,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 27,
"name": "cluster-27",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.278.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 27,
"seed_peer_cluster_id": 27,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 28,
"name": "cluster-28",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.288.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 28,
"seed_peer_cluster_id": 28,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 29,
"name": "cluster-29",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.298.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 29,
"seed_peer_cluster_id": 29,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 30,
"name": "cluster-30",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.308.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 30,
"seed_peer_cluster_id": 30,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 31,
"name": "cluster-31",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.318.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 31,
"seed_peer_cluster_id": 31,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 32,
"name": "cluster-32",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.328.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 32,
"seed_peer_cluster_id": 32,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 33,
"name": "cluster-33",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.338.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 33,
"seed_peer_cluster_id": 33,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 34,
"name": "cluster-34",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.348.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 34,
"seed_peer_cluster_id": 34,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 35,
"name": "cluster-35",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.358.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 35,
"seed_peer_cluster_id": 35,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 36,
"name": "cluster-36",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.368.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 36,
"seed_peer_cluster_id": 36,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 37,
"name": "cluster-37",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.378.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 37,
"seed_peer_cluster_id": 37,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
}
]

View File

@ -0,0 +1,27 @@
{
"id": 38,
"name": "cluster-38",
"bio": "Add new cluster case",
"scopes": {
"idc": "hz|sh",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
"hostnames": []
},
"scheduler_cluster_id": 17,
"seed_peer_cluster_id": 17,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
}

View File

@ -0,0 +1,993 @@
[
{
"id": 1,
"name": "cluster-1",
"bio": "Cluster-1 is a high-performance computing cluster located in China, specifically in Hangzhou and Beijing data centers.",
"scopes": {
"idc": "Hangzhou|Shanghai|Beijing",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"],
"hostnames": null
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 51
},
"created_at": "2023-10-31T07:48:35Z",
"updated_at": "2023-10-31T07:48:35Z",
"is_default": true
},
{
"id": 2,
"name": "cluster-2",
"bio": "",
"scopes": {
"idc": "",
"location": "",
"cidrs": []
},
"scheduler_cluster_id": 2,
"seed_peer_cluster_id": 2,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-10-31T17:48:35Z",
"updated_at": "2023-10-31T17:48:35Z",
"is_default": false
},
{
"id": 3,
"name": "cluster-3",
"bio": "Cluster-3 is a high-performance computing cluster located in Korea, specifically in Seoul data centers.",
"scopes": {
"idc": "Korea",
"location": "Seoul|Korea",
"cidrs": ["192.168.0.0/16", "172.16.0.0/12"]
},
"scheduler_cluster_id": 3,
"seed_peer_cluster_id": 3,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-08T11:19:36Z",
"updated_at": "2023-11-08T11:19:36Z",
"is_default": true
},
{
"id": 4,
"name": "cluster-4",
"bio": "Cluster-4 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|dl",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 4,
"seed_peer_cluster_id": 4,
"scheduler_cluster_config": {
"candidate_parent_limit": 5,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T18:19:36Z",
"updated_at": "2023-11-09T18:19:36Z",
"is_default": true
},
{
"id": 5,
"name": "cluster-5",
"bio": "Cluster-5 is a high-performance computing cluster located in China, specifically in Chongqing data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Qing",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 5,
"seed_peer_cluster_id": 5,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 6,
"name": "cluster-6",
"bio": "Cluster-6 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Du",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 6,
"seed_peer_cluster_id": 6,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-09T20:12:36Z",
"updated_at": "2023-11-09T20:12:36Z",
"is_default": true
},
{
"id": 7,
"name": "cluster-7",
"bio": "Cluster-7 is a high-performance computing cluster located in China, specifically in Chongdu data centers.",
"scopes": {
"idc": "cd",
"location": "China|Cheng|Du",
"cidrs": ["10.0.0.0/8", "172.16.0.0/19"]
},
"scheduler_cluster_id": 7,
"seed_peer_cluster_id": 7,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:19:36Z",
"updated_at": "2023-11-11T10:19:36Z",
"is_default": true
},
{
"id": 8,
"name": "cluster-8",
"bio": "Cluster-8 is a high-performance computing cluster located in China, specifically in Jiangsu data centers.",
"scopes": {
"idc": "js",
"location": "China|Jiang|Su",
"cidrs": ["10.0.0.0/5", "172.16.0.0/19"]
},
"scheduler_cluster_id": 8,
"seed_peer_cluster_id": 8,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T13:19:36Z",
"updated_at": "2023-11-11T13:19:36Z",
"is_default": false
},
{
"id": 9,
"name": "cluster-9",
"bio": "Cluster-9 is a high-performance computing cluster located in China, specifically in Hangzhou data centers.",
"scopes": {
"idc": "hz|hf",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
},
"scheduler_cluster_id": 9,
"seed_peer_cluster_id": 9,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-11T10:29:36Z",
"updated_at": "2023-11-11T10:29:36Z",
"is_default": true
},
{
"id": 10,
"name": "cluster-10",
"bio": "Cluster-10 is a high-performance computing cluster located in England, specifically in London data centers.",
"scopes": {
"idc": "London",
"location": "London|England",
"cidrs": ["192.168.255.255"]
},
"scheduler_cluster_id": 10,
"seed_peer_cluster_id": 10,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-15T05:19:36Z",
"updated_at": "2023-11-15T05:19:36Z",
"is_default": true
},
{
"id": 11,
"name": "cluster-11",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 11,
"seed_peer_cluster_id": 11,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-11-01T10:19:36Z",
"updated_at": "2023-11-01T10:19:36Z",
"is_default": false
},
{
"id": 12,
"name": "cluster-12",
"bio": "Cluster-12 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 12,
"seed_peer_cluster_id": 12,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-01T10:19:36Z",
"updated_at": "2023-12-01T10:19:36Z",
"is_default": false
},
{
"id": 13,
"name": "cluster-13",
"bio": "Cluster-13 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 13,
"seed_peer_cluster_id": 13,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-03T10:19:36Z",
"updated_at": "2023-12-03T10:19:36Z",
"is_default": false
},
{
"id": 14,
"name": "cluster-14",
"bio": "Cluster-14 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 14,
"seed_peer_cluster_id": 14,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-04T10:19:36Z",
"updated_at": "2023-12-04T10:19:36Z",
"is_default": false
},
{
"id": 15,
"name": "cluster-15",
"bio": "Cluster-15 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 15,
"seed_peer_cluster_id": 15,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-05T10:19:36Z",
"updated_at": "2023-12-05T10:19:36Z",
"is_default": false
},
{
"id": 16,
"name": "cluster-16",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 16,
"seed_peer_cluster_id": 16,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 17,
"name": "cluster-17",
"bio": "Add new cluster case",
"scopes": {
"idc": "hz|sh",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
"hostnames": []
},
"scheduler_cluster_id": 17,
"seed_peer_cluster_id": 17,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 18,
"name": "cluster-18",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.168.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 18,
"seed_peer_cluster_id": 18,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 19,
"name": "cluster-19",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.198.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 19,
"seed_peer_cluster_id": 19,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 20,
"name": "cluster-20",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.208.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 20,
"seed_peer_cluster_id": 20,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 21,
"name": "cluster-21",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.218.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 21,
"seed_peer_cluster_id": 21,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 22,
"name": "cluster-22",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.228.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 22,
"seed_peer_cluster_id": 22,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 23,
"name": "cluster-23",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.238.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 23,
"seed_peer_cluster_id": 23,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 24,
"name": "cluster-24",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.248.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 24,
"seed_peer_cluster_id": 24,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 25,
"name": "cluster-25",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.258.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 25,
"seed_peer_cluster_id": 25,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 26,
"name": "cluster-26",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.268.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 26,
"seed_peer_cluster_id": 26,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 27,
"name": "cluster-27",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.278.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 27,
"seed_peer_cluster_id": 27,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 28,
"name": "cluster-28",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.288.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 28,
"seed_peer_cluster_id": 28,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 29,
"name": "cluster-29",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.298.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 29,
"seed_peer_cluster_id": 29,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 30,
"name": "cluster-30",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.308.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 30,
"seed_peer_cluster_id": 30,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 31,
"name": "cluster-31",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.318.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 31,
"seed_peer_cluster_id": 31,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
},
{
"id": 32,
"name": "cluster-32",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.328.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 32,
"seed_peer_cluster_id": 32,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 33,
"name": "cluster-33",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.338.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 33,
"seed_peer_cluster_id": 33,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 34,
"name": "cluster-34",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.348.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 34,
"seed_peer_cluster_id": 34,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 35,
"name": "cluster-35",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.358.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 35,
"seed_peer_cluster_id": 35,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 36,
"name": "cluster-36",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.368.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 36,
"seed_peer_cluster_id": 36,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 37,
"name": "cluster-37",
"bio": "Cluster-10 is a high-performance computing cluster located in France, specifically in Paris data centers.",
"scopes": {
"idc": "Paris",
"location": "Paris|France",
"cidrs": ["192.378.0.0", "10.0.0.0"]
},
"scheduler_cluster_id": 37,
"seed_peer_cluster_id": 37,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": false
},
{
"id": 38,
"name": "cluster-38",
"bio": "Add new cluster case",
"scopes": {
"idc": "hz|sh",
"location": "China|Hang|Zhou",
"cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
"hostnames": []
},
"scheduler_cluster_id": 17,
"seed_peer_cluster_id": 17,
"scheduler_cluster_config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40,
"job_rate_limit": 10
},
"seed_peer_cluster_config": {
"load_limit": 300
},
"peer_cluster_config": {
"load_limit": 50
},
"created_at": "2023-12-06T10:19:36Z",
"updated_at": "2023-12-06T10:19:36Z",
"is_default": true
}
]

View File

@ -0,0 +1,326 @@
[
{
"id": 1,
"created_at": "2023-12-04T10:27:17Z",
"updated_at": "2023-12-04T10:34:12Z",
"is_del": 0,
"name": "root-1",
"bio": "root-1 token, used to control the cluster.",
"token": "MTk3OTY5NTMtZjlkZi00YWVhLWI5OGEtZTc0YWVhMWZmYmQz",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 2,
"created_at": "2023-12-04T10:39:31Z",
"updated_at": "2023-12-04T10:39:31Z",
"is_del": 0,
"name": "root-2",
"bio": "root-2 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2024-08-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 3,
"created_at": "2023-12-04T10:41:31Z",
"updated_at": "2023-12-04T10:41:31Z",
"is_del": 0,
"name": "root-3",
"bio": "root-3 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-02-21T11:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 4,
"created_at": "2023-12-04T10:42:31Z",
"updated_at": "2023-12-04T10:42:31Z",
"is_del": 0,
"name": "root-4",
"bio": "root-4 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-02-11T10:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 5,
"created_at": "2023-12-04T10:43:31Z",
"updated_at": "2023-12-04T10:43:31Z",
"is_del": 0,
"name": "root-5",
"bio": "root-5 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2027-09-14T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 6,
"created_at": "2023-12-04T10:45:31Z",
"updated_at": "2023-12-04T10:45:31Z",
"is_del": 0,
"name": "root-6",
"bio": "root-6 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 7,
"created_at": "2023-12-04T11:41:31Z",
"updated_at": "2023-12-04T11:41:31Z",
"is_del": 0,
"name": "root-7",
"bio": "root-7 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-06-11T10:37:53Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 8,
"created_at": "2023-12-04T11:49:31Z",
"updated_at": "2023-12-04T11:49:31Z",
"is_del": 0,
"name": "root-8",
"bio": "root-8 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 9,
"created_at": "2023-12-05T10:41:31Z",
"updated_at": "2023-12-05T10:41:31Z",
"is_del": 0,
"name": "root-9",
"bio": "root-9 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 10,
"created_at": "2023-12-05T18:41:31Z",
"updated_at": "2023-12-05T18:41:31Z",
"is_del": 0,
"name": "root-10",
"bio": "root-10 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-12-1T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 11,
"created_at": "2023-12-06T10:41:31Z",
"updated_at": "2023-12-06T10:41:31Z",
"is_del": 0,
"name": "root-11",
"bio": "root-11 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-12-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 12,
"created_at": "2023-12-06T11:41:31Z",
"updated_at": "2023-12-06T11:41:31Z",
"is_del": 0,
"name": "root-12",
"bio": "root-12 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": [],
"state": "active",
"expired_at": "2024-02-03T11:36:05Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}
]

View File

@ -0,0 +1,272 @@
[
{
"id": 2,
"created_at": "2023-12-04T10:39:31Z",
"updated_at": "2023-12-04T10:39:31Z",
"is_del": 0,
"name": "root-2",
"bio": "root-2 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2024-08-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 3,
"created_at": "2023-12-04T10:41:31Z",
"updated_at": "2023-12-04T10:41:31Z",
"is_del": 0,
"name": "root-3",
"bio": "root-3 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-02-21T11:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 4,
"created_at": "2023-12-04T10:42:31Z",
"updated_at": "2023-12-04T10:42:31Z",
"is_del": 0,
"name": "root-4",
"bio": "root-4 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-02-11T10:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 5,
"created_at": "2023-12-04T10:43:31Z",
"updated_at": "2023-12-04T10:43:31Z",
"is_del": 0,
"name": "root-5",
"bio": "root-5 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2027-09-14T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 6,
"created_at": "2023-12-04T10:45:31Z",
"updated_at": "2023-12-04T10:45:31Z",
"is_del": 0,
"name": "root-6",
"bio": "root-6 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 7,
"created_at": "2023-12-04T11:41:31Z",
"updated_at": "2023-12-04T11:41:31Z",
"is_del": 0,
"name": "root-7",
"bio": "root-7 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-06-11T10:37:53Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 8,
"created_at": "2023-12-04T11:49:31Z",
"updated_at": "2023-12-04T11:49:31Z",
"is_del": 0,
"name": "root-8",
"bio": "root-8 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 9,
"created_at": "2023-12-05T10:41:31Z",
"updated_at": "2023-12-05T10:41:31Z",
"is_del": 0,
"name": "root-9",
"bio": "root-9 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 10,
"created_at": "2023-12-05T18:41:31Z",
"updated_at": "2023-12-05T18:41:31Z",
"is_del": 0,
"name": "root-10",
"bio": "root-10 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-12-1T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 11,
"created_at": "2023-12-06T10:41:31Z",
"updated_at": "2023-12-06T10:41:31Z",
"is_del": 0,
"name": "root-11",
"bio": "root-11 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2023-12-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}
]

View File

@ -0,0 +1,272 @@
[
{
"id": 1,
"created_at": "2023-12-04T10:27:17Z",
"updated_at": "2023-12-04T10:34:12Z",
"is_del": 0,
"name": "root-1",
"bio": "root-1 token, used to control the cluster.",
"token": "MTk3OTY5NTMtZjlkZi00YWVhLWI5OGEtZTc0YWVhMWZmYmQz",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 2,
"created_at": "2023-12-04T10:39:31Z",
"updated_at": "2023-12-04T10:39:31Z",
"is_del": 0,
"name": "root-2",
"bio": "root-2 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2024-08-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 3,
"created_at": "2023-12-04T10:41:31Z",
"updated_at": "2023-12-04T10:41:31Z",
"is_del": 0,
"name": "root-3",
"bio": "root-3 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-02-21T11:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 4,
"created_at": "2023-12-04T10:42:31Z",
"updated_at": "2023-12-04T10:42:31Z",
"is_del": 0,
"name": "root-4",
"bio": "root-4 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-02-11T10:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 5,
"created_at": "2023-12-04T10:43:31Z",
"updated_at": "2023-12-04T10:43:31Z",
"is_del": 0,
"name": "root-5",
"bio": "root-5 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2027-09-14T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 6,
"created_at": "2023-12-04T10:45:31Z",
"updated_at": "2023-12-04T10:45:31Z",
"is_del": 0,
"name": "root-6",
"bio": "root-6 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 7,
"created_at": "2023-12-04T11:41:31Z",
"updated_at": "2023-12-04T11:41:31Z",
"is_del": 0,
"name": "root-7",
"bio": "root-7 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-06-11T10:37:53Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 8,
"created_at": "2023-12-04T11:49:31Z",
"updated_at": "2023-12-04T11:49:31Z",
"is_del": 0,
"name": "root-8",
"bio": "root-8 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 9,
"created_at": "2023-12-05T10:41:31Z",
"updated_at": "2023-12-05T10:41:31Z",
"is_del": 0,
"name": "root-9",
"bio": "root-9 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 10,
"created_at": "2023-12-05T18:41:31Z",
"updated_at": "2023-12-05T18:41:31Z",
"is_del": 0,
"name": "root-10",
"bio": "root-10 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-12-1T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}
]

View File

@ -0,0 +1,27 @@
{
"id": 11,
"created_at": "2023-12-06T10:41:31Z",
"updated_at": "2023-12-06T10:41:31Z",
"is_del": 0,
"name": "root-11",
"bio": "root-11 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2023-12-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}

View File

@ -0,0 +1,299 @@
[
{
"id": 1,
"created_at": "2023-12-04T10:27:17Z",
"updated_at": "2023-12-04T10:34:12Z",
"is_del": 0,
"name": "root-1",
"bio": "root-1 token, used to control the cluster.",
"token": "MTk3OTY5NTMtZjlkZi00YWVhLWI5OGEtZTc0YWVhMWZmYmQz",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 2,
"created_at": "2023-12-04T10:39:31Z",
"updated_at": "2023-12-04T10:39:31Z",
"is_del": 0,
"name": "root-2",
"bio": "root-2 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2024-08-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 3,
"created_at": "2023-12-04T10:41:31Z",
"updated_at": "2023-12-04T10:41:31Z",
"is_del": 0,
"name": "root-3",
"bio": "root-3 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-02-21T11:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 4,
"created_at": "2023-12-04T10:42:31Z",
"updated_at": "2023-12-04T10:42:31Z",
"is_del": 0,
"name": "root-4",
"bio": "root-4 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-02-11T10:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 5,
"created_at": "2023-12-04T10:43:31Z",
"updated_at": "2023-12-04T10:43:31Z",
"is_del": 0,
"name": "root-5",
"bio": "root-5 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2027-09-14T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 6,
"created_at": "2023-12-04T10:45:31Z",
"updated_at": "2023-12-04T10:45:31Z",
"is_del": 0,
"name": "root-6",
"bio": "root-6 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 7,
"created_at": "2023-12-04T11:41:31Z",
"updated_at": "2023-12-04T11:41:31Z",
"is_del": 0,
"name": "root-7",
"bio": "root-7 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-06-11T10:37:53Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 8,
"created_at": "2023-12-04T11:49:31Z",
"updated_at": "2023-12-04T11:49:31Z",
"is_del": 0,
"name": "root-8",
"bio": "root-8 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 9,
"created_at": "2023-12-05T10:41:31Z",
"updated_at": "2023-12-05T10:41:31Z",
"is_del": 0,
"name": "root-9",
"bio": "root-9 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 10,
"created_at": "2023-12-05T18:41:31Z",
"updated_at": "2023-12-05T18:41:31Z",
"is_del": 0,
"name": "root-10",
"bio": "root-10 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2023-12-12T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 11,
"created_at": "2023-12-06T10:41:31Z",
"updated_at": "2023-12-06T10:41:31Z",
"is_del": 0,
"name": "root-11",
"bio": "root-11 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2023-12-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}
]

View File

@ -0,0 +1,299 @@
[
{
"id": 1,
"created_at": "2023-12-04T10:27:17Z",
"updated_at": "2023-12-04T10:34:12Z",
"is_del": 0,
"name": "root-1",
"bio": "root-1 token, used to control the cluster.",
"token": "MTk3OTY5NTMtZjlkZi00YWVhLWI5OGEtZTc0YWVhMWZmYmQz",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 2,
"created_at": "2023-12-04T10:39:31Z",
"updated_at": "2023-12-04T10:39:31Z",
"is_del": 0,
"name": "root-2",
"bio": "root-2 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2024-08-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 3,
"created_at": "2023-12-04T10:41:31Z",
"updated_at": "2023-12-04T10:41:31Z",
"is_del": 0,
"name": "root-3",
"bio": "root-3 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-02-21T11:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 4,
"created_at": "2023-12-04T10:42:31Z",
"updated_at": "2023-12-04T10:42:31Z",
"is_del": 0,
"name": "root-4",
"bio": "root-4 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-02-11T10:37:53Z",
"user_id": 1,
"user": {
"id": 1,
"created_at": "2023-11-06T06:09:04Z",
"updated_at": "2023-11-06T06:09:04Z",
"is_del": 0,
"email": "lucy@example.com",
"name": "lucy",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Hangzhou",
"bio": "I am lucy",
"configs": null
}
},
{
"id": 5,
"created_at": "2023-12-04T10:43:31Z",
"updated_at": "2023-12-04T10:43:31Z",
"is_del": 0,
"name": "root-5",
"bio": "root-5 token, used to open API call warm-up job.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["job"],
"state": "active",
"expired_at": "2027-09-14T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 6,
"created_at": "2023-12-04T10:45:31Z",
"updated_at": "2023-12-04T10:45:31Z",
"is_del": 0,
"name": "root-6",
"bio": "root-6 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 7,
"created_at": "2023-12-04T11:41:31Z",
"updated_at": "2023-12-04T11:41:31Z",
"is_del": 0,
"name": "root-7",
"bio": "root-7 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-06-11T10:37:53Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 8,
"created_at": "2023-12-04T11:49:31Z",
"updated_at": "2023-12-04T11:49:31Z",
"is_del": 0,
"name": "root-8",
"bio": "root-8 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2025-01-11T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 9,
"created_at": "2023-12-05T10:41:31Z",
"updated_at": "2023-12-05T10:41:31Z",
"is_del": 0,
"name": "root-9",
"bio": "root-9 token, used to control the cluster.",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-01T10:34:08Z",
"user_id": 2,
"user": {
"id": 2,
"created_at": "2023-11-07T06:09:04Z",
"updated_at": "2023-11-07T06:09:04Z",
"is_del": 0,
"email": "jack@example.com",
"name": "jack",
"avatar": "https://example.com/avatar.png",
"phone": "1234567890",
"state": "enable",
"location": "Shanghai",
"bio": "I am jack",
"configs": null
}
},
{
"id": 10,
"created_at": "2023-12-05T18:41:31Z",
"updated_at": "2023-12-05T18:41:31Z",
"is_del": 0,
"name": "root-10",
"bio": "root-10 token, used to control of cluster",
"token": "YmVmYjA1Y2MtMmFkYy00OTJjLTg4OWUtYzg3MjE0ZWEyOWY4",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2024-12-1T10:37:53Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
},
{
"id": 11,
"created_at": "2023-12-06T10:41:31Z",
"updated_at": "2023-12-06T10:41:31Z",
"is_del": 0,
"name": "root-11",
"bio": "root-11 token, used to control of cluster",
"token": "ODhlMjFkY2UtM2Y1ZS00ZTVmLThkMzYtMzE2MzhiNmQxODlj",
"scopes": ["cluster"],
"state": "active",
"expired_at": "2033-12-03T06:37:38.712Z",
"user_id": 3,
"user": {
"id": 3,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"email": "root@example.com",
"name": "root",
"avatar": "",
"phone": "1234567890",
"state": "enable",
"location": "Guangzhou",
"bio": "This is root",
"configs": null
}
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": 1,
"created_at": "2025-06-18T07:53:26.189Z",
"updated_at": "2025-06-23T03:17:49.49Z",
"is_del": 0,
"name": "gc",
"value": "{\"audit\":{\"ttl\":259200000000000},\"job\":{\"ttl\":1123200000000000}}",
"bio": "",
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
}
}
]

View File

@ -0,0 +1,35 @@
{
"id": 24,
"created_at": "2025-06-25T09:29:25.297Z",
"updated_at": "2025-06-25T09:29:25.327Z",
"is_del": 0,
"task_id": "f060ab6b-16a7-4ff9-80ed-d135bd53b4fa",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1814400000000000,
"type": "audit"
},
"result": {
"purged": 10
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
}

View File

@ -0,0 +1,842 @@
[
{
"id": 119,
"created_at": "2025-06-23T05:12:15.991Z",
"updated_at": "2025-06-23T05:12:16.09Z",
"is_del": 0,
"task_id": "e1949b29-4bca-4591-8b54-d619373ae750",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 172800000000000,
"type": "audit"
},
"result": {
"purged": 10
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 118,
"created_at": "2025-06-23T05:12:15.991Z",
"updated_at": "2025-06-23T05:12:16.09Z",
"is_del": 0,
"task_id": "e1949b29-4bca-4591-8b54-d619373ae750",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 172800000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 117,
"created_at": "2025-06-23T05:12:15.991Z",
"updated_at": "2025-06-23T05:12:16.09Z",
"is_del": 0,
"task_id": "e1949b29-4bca-4591-8b54-d619373ae750",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 172800000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 117,
"created_at": "2025-06-23T06:06:47.959Z",
"updated_at": "2025-06-23T06:06:47.997Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 116,
"created_at": "2025-06-23T05:12:15.991Z",
"updated_at": "2025-06-23T05:12:16.09Z",
"is_del": 0,
"task_id": "e1949b29-4bca-4591-8b54-d619373ae750",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 172800000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 115,
"created_at": "2025-06-23T04:34:36.417Z",
"updated_at": "2025-06-23T04:34:36.484Z",
"is_del": 0,
"task_id": "15a3dc57-14eb-4623-8d99-d2021647efb2",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 114,
"created_at": "2025-06-23T04:34:24.244Z",
"updated_at": "2025-06-23T04:34:24.4Z",
"is_del": 0,
"task_id": "8f2c5507-450e-45e2-bc52-ff3fcfae5bd4",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 113,
"created_at": "2025-06-23T03:17:40.93Z",
"updated_at": "2025-06-23T03:17:40.937Z",
"is_del": 0,
"task_id": "cdf743c3-ae45-4526-b8a9-574d17532491",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 112,
"created_at": "2025-06-23T03:17:32.362Z",
"updated_at": "2025-06-23T03:17:32.405Z",
"is_del": 0,
"task_id": "e68e1914-e2d2-447a-b6e9-c03a0032de7b",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 1,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 111,
"created_at": "2025-06-23T02:18:20.238Z",
"updated_at": "2025-06-23T02:18:20.249Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 110,
"created_at": "2025-06-23T02:18:19.755Z",
"updated_at": "2025-06-23T02:18:19.872Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 109,
"created_at": "2025-06-22T22:44:24.566Z",
"updated_at": "2025-06-22T22:44:24.643Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 108,
"created_at": "2025-06-22T22:44:24.445Z",
"updated_at": "2025-06-22T22:44:24.565Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 107,
"created_at": "2025-06-22T17:35:36.808Z",
"updated_at": "2025-06-22T17:35:36.815Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 106,
"created_at": "2025-06-22T17:35:36.807Z",
"updated_at": "2025-06-22T17:35:36.828Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 105,
"created_at": "2025-06-22T17:35:36.332Z",
"updated_at": "2025-06-22T17:35:36.436Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 104,
"created_at": "2025-06-22T17:35:36.33Z",
"updated_at": "2025-06-22T17:35:36.439Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 103,
"created_at": "2025-06-22T14:26:39.289Z",
"updated_at": "2025-06-22T14:26:39.356Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 102,
"created_at": "2025-06-22T11:17:59.604Z",
"updated_at": "2025-06-22T11:17:59.613Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 101,
"created_at": "2025-06-22T11:17:59.169Z",
"updated_at": "2025-06-22T11:17:59.559Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 100,
"created_at": "2025-06-22T07:27:00.54Z",
"updated_at": "2025-06-22T07:27:00.612Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 99,
"created_at": "2025-06-22T07:27:00.539Z",
"updated_at": "2025-06-22T07:27:00.578Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 98,
"created_at": "2025-06-22T04:22:46.333Z",
"updated_at": "2025-06-22T04:22:46.386Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 1123200000000000,
"type": "job"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 97,
"created_at": "2025-06-22T04:22:46.332Z",
"updated_at": "2025-06-22T04:22:46.376Z",
"is_del": 0,
"task_id": "audit",
"bio": "",
"type": "gc",
"state": "SUCCESS",
"args": {
"batch_size": 5000,
"ttl": 7200000000000,
"type": "audit"
},
"result": {
"purged": 0
},
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
},
"seed_peer_clusters": null,
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,26 @@
[
{
"id": 1,
"created_at": "2025-06-18T07:53:26.189Z",
"updated_at": "2025-06-23T03:17:49.49Z",
"is_del": 0,
"name": "gc",
"value": "{\"audit\":{\"ttl\":1814400000000000},\"job\":{\"ttl\":1814400000000000}}",
"bio": "",
"user_id": 0,
"user": {
"id": 0,
"created_at": "0001-01-01T00:00:00Z",
"updated_at": "0001-01-01T00:00:00Z",
"is_del": 0,
"email": "",
"name": "",
"avatar": "",
"phone": "",
"state": "",
"location": "",
"bio": "",
"configs": null
}
}
]

View File

@ -0,0 +1,42 @@
{
"id": 12,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_2d9ef907-744e-40c9-9943-3d14fd8cb389",
"bio": "create preheat",
"type": "preheat",
"state": "PENDING",
"args": {
"application": "application-1",
"concurrent_count": 50,
"content_for_calculating_task_id": null,
"count": null,
"filtered_query_params": "X-Amz-Algorithm\u0026X-Amz-Credential\u0026X-Amz-Date\u0026X-Amz-Expires\u0026X-Amz-SignedHeaders\u0026X-Amz-Signature\u0026X-Amz-Security-Token\u0026X-Amz-User-Agent\u0026X-Goog-Algorithm\u0026X-Goog-Credential\u0026X-Goog-Date\u0026X-Goog-Expires\u0026X-Goog-SignedHeaders\u0026X-Goog-Signature\u0026OSSAccessKeyId\u0026Expires\u0026Signature\u0026SecurityToken\u0026AccessKeyId\u0026Signature\u0026Expires\u0026X-Obs-Date\u0026X-Obs-Security-Token\u0026q-sign-algorithm\u0026q-ak\u0026q-sign-time\u0026q-key-time\u0026q-header-list\u0026q-url-param-list\u0026q-signature\u0026x-cos-security-token\u0026ns",
"headers": {},
"load_to_cache": false,
"password": "",
"percentage": null,
"piece_length": 5242880,
"platform": "",
"scope": "all_seed_peers",
"tag": "tag-1",
"timeout": 1800000000000,
"type": "file",
"url": "",
"urls": ["https://example.com/path/to/file/url-1", "https://example.com/path/to/file"]
},
"result": {
"created_at": "2025-05-28T08:43:48.634389458Z",
"group_uuid": "group_2d9ef907-744e-40c9-9943-3d14fd8cb389",
"job_states": null,
"state": "PENDING",
"updated_at": "2025-05-28T08:45:52.849258668Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": [
{
"id": 1
}
]
}

View File

@ -0,0 +1,56 @@
{
"id": 13,
"created_at": "2025-07-08T12:22:42.892Z",
"updated_at": "2025-07-08T12:22:42.892Z",
"is_del": 0,
"task_id": "group_152f6ada-efea-4cd6-a269-5ebb784a633a",
"bio": "create preheat",
"type": "preheat",
"state": "PENDING",
"args": {
"application": "application-1",
"concurrent_count": 1000,
"count": null,
"filtered_query_params": "X-Amz-Algorithm\u0026X-Amz-Credential\u0026X-Amz-Date\u0026X-Amz-Expires\u0026X-Amz-SignedHeaders\u0026X-Amz-Signature\u0026X-Amz-Security-Token\u0026X-Amz-User-Agent\u0026X-Goog-Algorithm\u0026X-Goog-Credential\u0026X-Goog-Date\u0026X-Goog-Expires\u0026X-Goog-SignedHeaders\u0026X-Goog-Signature\u0026OSSAccessKeyId\u0026Expires\u0026Signature\u0026SecurityToken\u0026AccessKeyId\u0026Signature\u0026Expires\u0026X-Obs-Date\u0026X-Obs-Security-Token\u0026q-sign-algorithm\u0026q-ak\u0026q-sign-time\u0026q-key-time\u0026q-header-list\u0026q-url-param-list\u0026q-signature\u0026x-cos-security-token\u0026ns",
"headers": {},
"ips": [
"10.244.4.5",
"10.244.4.3",
"10.244.4.61",
"10.244.4.62",
"10.244.4.63",
"10.244.4.64",
"10.244.4.65",
"10.244.4.66",
"10.244.4.67",
"10.244.4.68",
"10.244.4.69",
"10.244.4.70",
"10.244.4.71"
],
"load_to_cache": false,
"password": "root",
"percentage": null,
"piece_length": null,
"platform": "linux/amd64",
"scope": "single_seed_peer",
"tag": "tag-1",
"timeout": 3600000000000,
"type": "image",
"url": "https://example.com/manifests/v2.1.0",
"urls": null,
"username": ""
},
"result": {
"created_at": "2025-05-28T08:43:48.634389458Z",
"group_uuid": "group_2d9ef907-744e-40c9-9943-3d14fd8cb389",
"job_states": null,
"state": "PENDING",
"updated_at": "2025-05-28T08:45:52.849258668Z"
},
"scheduler_clusters": [
{
"id": 1
}
]
}

View File

@ -0,0 +1,74 @@
{
"id": 10,
"created_at": "2023-12-13T11:58:53Z",
"updated_at": "2023-12-13T11:58:53Z",
"is_del": 0,
"task_id": "group_01f9f92f-02c7-477e-8360-a387407b73dd",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"application": "application-1",
"concurrent_count": 50,
"content_for_calculating_task_id": null,
"count": 100,
"filtered_query_params": "X-Amz-Algorithm\u0026X-Amz-Credential\u0026X-Amz-Date\u0026X-Amz-Expires\u0026X-Amz-SignedHeaders\u0026X-Amz-Signature\u0026X-Amz-Security-Token\u0026X-Amz-User-Agent\u0026X-Goog-Algorithm\u0026X-Goog-Credential\u0026X-Goog-Date\u0026X-Goog-Expires\u0026X-Goog-SignedHeaders\u0026X-Goog-Signature\u0026OSSAccessKeyId\u0026Expires\u0026Signature\u0026SecurityToken\u0026AccessKeyId\u0026Signature\u0026Expires\u0026X-Obs-Date\u0026X-Obs-Security-Token\u0026q-sign-algorithm\u0026q-ak\u0026q-sign-time\u0026q-key-time\u0026q-header-list\u0026q-url-param-list\u0026q-signature\u0026x-cos-security-token\u0026ns",
"headers": { "Connection": "keep-alive" },
"load_to_cache": false,
"password": "",
"percentage": null,
"piece_length": 4194304,
"platform": "",
"scope": "all_peers",
"tag": "prheat tag",
"timeout": 1800000000000,
"type": "file",
"url": "",
"urls": [
"https://example.com/path/to/file",
"https://example.com/path/to/file/url-1",
"https://example.com/path/to/file/url-2"
],
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
},
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "rpc error: code = Aborted desc = source response 401/401 Unauthorized is not valid",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
},
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": [
{
"id": 1
}
]
}

View File

@ -0,0 +1,178 @@
[
{
"id": 10,
"created_at": "2023-03-23T15:55:41+08:00",
"updated_at": "2023-03-23T15:55:41+08:00",
"is_del": 0,
"task_id": "group_01f9f92f-02c7-477e-8360-a387407b73dd",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "Expires&Signature",
"headers": {
"Connection": "keep-alive"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "prheat tag",
"timeout": 1800000000000,
"type": "file",
"url": "http://dock.io/preheat/test",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": [
{
"id": 1
}
]
},
{
"id": 9,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 7,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 3,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,45 @@
[
{
"id": 1,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,53 @@
{
"id": 11,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status pending",
"type": "preheat",
"state": "PENDING",
"args": {
"application": "application-1",
"concurrent_count": 50,
"content_for_calculating_task_id": null,
"count": null,
"filtered_query_params": "X-Amz-Algorithm\u0026X-Amz-Credential\u0026X-Amz-Date\u0026X-Amz-Expires\u0026X-Amz-SignedHeaders\u0026X-Amz-Signature\u0026X-Amz-Security-Token\u0026X-Amz-User-Agent\u0026X-Goog-Algorithm\u0026X-Goog-Credential\u0026X-Goog-Date\u0026X-Goog-Expires\u0026X-Goog-SignedHeaders\u0026X-Goog-Signature\u0026OSSAccessKeyId\u0026Expires\u0026Signature\u0026SecurityToken\u0026AccessKeyId\u0026Signature\u0026Expires\u0026X-Obs-Date\u0026X-Obs-Security-Token\u0026q-sign-algorithm\u0026q-ak\u0026q-sign-time\u0026q-key-time\u0026q-header-list\u0026q-url-param-list\u0026q-signature\u0026x-cos-security-token\u0026ns",
"headers": { "Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT" },
"load_to_cache": false,
"password": "",
"percentage": 100,
"piece_length": null,
"platform": "",
"scope": "all_seed_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "",
"urls": ["https://example.com/path/to/file"],
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "PENDING",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "PENDING",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": [
{
"id": 1
}
]
}

View File

@ -0,0 +1,46 @@
[
{
"id": 11,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status pending",
"type": "preheat",
"state": "PENDING",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "PENDING",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "PENDING",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,442 @@
[
{
"id": 11,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status pending",
"type": "preheat",
"state": "PENDING",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_seed_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": null
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "PENDING",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "PENDING",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 10,
"created_at": "2023-03-23T15:55:41+08:00",
"updated_at": "2023-03-23T15:55:41+08:00",
"is_del": 0,
"task_id": "group_01f9f92f-02c7-477e-8360-a387407b73dd",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_seed_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "http://dock.io/preheat/test",
"username": "",
"piece_length": null
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 9,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_seed_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 8,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_seed_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 7,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_seed_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 6,
"created_at": "2023-03-23T15:55:41+08:00",
"updated_at": "2023-03-23T15:55:41+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_seed_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 5,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 4,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": null
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 3,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status failure",
"type": "preheat",
"state": "FAILURE",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "all_peers",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "FAILURE",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "FAILURE",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
},
{
"id": 2,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_seed_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": "",
"piece_length": 4194304
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,62 @@
{
"id": 8,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"application": "application-1",
"concurrent_count": 1000,
"count": null,
"filtered_query_params": "X-Amz-Algorithm\u0026X-Amz-Credential\u0026X-Amz-Date\u0026X-Amz-Expires\u0026X-Amz-SignedHeaders\u0026X-Amz-Signature\u0026X-Amz-Security-Token\u0026X-Amz-User-Agent\u0026X-Goog-Algorithm\u0026X-Goog-Credential\u0026X-Goog-Date\u0026X-Goog-Expires\u0026X-Goog-SignedHeaders\u0026X-Goog-Signature\u0026OSSAccessKeyId\u0026Expires\u0026Signature\u0026SecurityToken\u0026AccessKeyId\u0026Signature\u0026Expires\u0026X-Obs-Date\u0026X-Obs-Security-Token\u0026q-sign-algorithm\u0026q-ak\u0026q-sign-time\u0026q-key-time\u0026q-header-list\u0026q-url-param-list\u0026q-signature\u0026x-cos-security-token\u0026ns",
"headers": { "Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT", "Connection": "keep-alive" },
"load_to_cache": false,
"password": "root",
"percentage": null,
"piece_length": 4194304,
"platform": "linux/amd64",
"scope": "single_seed_peer",
"tag": "tag-1",
"timeout": 3600000000000,
"type": "image",
"url": "https://example.com/manifests/v2.1.0",
"urls": null,
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"scheduler_clusters": [
{
"id": 102133,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1"
},
{
"id": 203023,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-2"
}
]
}

View File

@ -0,0 +1,266 @@
[
{
"id": 8,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 6,
"created_at": "2023-03-23T15:55:41+08:00",
"updated_at": "2023-03-23T15:55:41+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 5,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 4,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 2,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
},
{
"id": 1,
"created_at": "2023-03-23T16:29:18+08:00",
"updated_at": "2023-03-23T16:29:18+08:00",
"is_del": 0,
"task_id": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"bio": "This is a preheat task with status success",
"type": "preheat",
"state": "SUCCESS",
"args": {
"concurrent_count": 50,
"filtered_query_params": "",
"headers": {
"Authorization": "Bearer yJhbGciOiJSUzI1NiIsImtpZCI6IjNEWT"
},
"password": "",
"platform": "",
"scope": "single_peer",
"tag": "",
"timeout": 1800000000000,
"type": "file",
"url": "https://example.com/path/to/file",
"username": ""
},
"result": {
"created_at": "2023-03-23T08:29:18.204923418Z",
"group_uuid": "group_7d8fec4c-6b8f-4240-9f56-71845d21d6a7",
"job_states": [
{
"created_at": "2023-03-23T08:29:18.204923418Z",
"error": "",
"results": null,
"state": "SUCCESS",
"task_name": "preheat",
"task_uuid": "task_d44f42d9-5b01-4f4a-a8dd-34331eefa84a",
"ttl": 0
}
],
"state": "SUCCESS",
"updated_at": "2024-09-14T10:39:16.549159043Z"
},
"seed_peer_clusters": null,
"scheduler_clusters": null
}
]

View File

@ -0,0 +1,462 @@
[
{
"id": 1,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-1",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "inactive",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-1",
"git_commit": "commit-1",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 2,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-2",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-2",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 3,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-3",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-2",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 4,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-4",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-3",
"git_commit": "git-commit-2",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-3",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 5,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-5",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "inactive",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-3",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-3",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 6,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-6",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-4",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-4",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 7,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-7",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-1",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 8,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-8",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 9,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-9",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 10,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-10",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-5",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
}
]

View File

@ -0,0 +1,646 @@
[
{
"id": 1,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-1",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "inactive",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-1",
"git_commit": "commit-1",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 2,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-2",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-2",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 3,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-3",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-2",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 4,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-4",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-3",
"git_commit": "git-commit-2",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-3",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 5,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-5",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "inactive",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-3",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-3",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 6,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-6",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-4",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-4",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 7,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-7",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-1",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 8,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-8",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-4",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 9,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-9",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-3",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 10,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-10",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-2",
"git_commit": "git-commit-5",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 11,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-10",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-5",
"git_commit": "git-commit-5",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 12,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-12",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-5",
"git_commit": "git-commit-1",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 13,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-13",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-6",
"git_commit": "git-commit-2",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
},
{
"id": 14,
"created_at": "2023-12-18T09:36:14Z",
"updated_at": "2023-12-18T09:36:14Z",
"is_del": 0,
"host_name": "peer-14",
"type": "super",
"idc": "sdfsd",
"location": "Hangzhou",
"ip": "30.44.96.255",
"port": 34001,
"download_port": 34201,
"object_storage_port": 0,
"state": "active",
"os": "linux",
"platform": "example",
"platform_family": "",
"platform_version": "7.2",
"kernel_version": "5.23.23",
"git_version": "git-version-3",
"git_commit": "git-commit-6",
"build_platform": "linux",
"scheduler_cluster_id": 1,
"scheduler_cluster": {
"id": 1,
"created_at": "2023-11-27T07:31:23Z",
"updated_at": "2023-11-27T07:31:23Z",
"is_del": 0,
"name": "cluster-1",
"bio": "",
"config": {
"candidate_parent_limit": 4,
"filter_parent_limit": 40
},
"client_config": {
"concurrent_piece_count": 4,
"load_limit": 50
},
"scopes": {},
"is_default": true,
"seed_peer_clusters": null,
"schedulers": null,
"peers": null,
"jobs": null
}
}
]

Some files were not shown because too many files have changed in this diff Show More