From 8bee0cf4a22d18a0d3524ab6743b3abf5b0e6bb4 Mon Sep 17 00:00:00 2001
From: Zhaoxinxin <107842350+Liam-Zhao@users.noreply.github.com>
Date: Wed, 21 Feb 2024 21:54:32 +0800
Subject: [PATCH] feat: cluster scope adds hostnames (#356)
Signed-off-by: zhaoxinxin <1186037180@qq.com>
---
cypress/e2e/clusters/cluster.cy.ts | 8 +
cypress/e2e/clusters/create-cluster.cy.ts | 17 ++
cypress/e2e/clusters/update-cluster.cy.ts | 21 ++
cypress/e2e/job/preheats/create-preheat.cy.ts | 4 +-
cypress/e2e/seed-peers/seed-peers.cy.ts | 6 +-
.../fixtures/clusters/cluster/cluster.json | 3 +-
.../clusters/cluster/update-cluster.json | 3 +-
cypress/fixtures/clusters/create-cluster.json | 33 ++-
public/icons/cluster/cidrs.svg | 9 +-
public/icons/cluster/hostname.svg | 9 +-
public/icons/cluster/hostnames.svg | 6 +
src/components/clusters/edit.tsx | 190 +++++++++++-------
.../clusters/information.module.css | 37 +++-
src/components/clusters/information.tsx | 104 +++++++++-
src/components/clusters/new.tsx | 185 +++++++++++------
src/components/clusters/show.tsx | 1 +
src/lib/api.ts | 6 +
17 files changed, 477 insertions(+), 165 deletions(-)
create mode 100644 public/icons/cluster/hostnames.svg
diff --git a/cypress/e2e/clusters/cluster.cy.ts b/cypress/e2e/clusters/cluster.cy.ts
index 59a8a27b..18e10c8c 100644
--- a/cypress/e2e/clusters/cluster.cy.ts
+++ b/cypress/e2e/clusters/cluster.cy.ts
@@ -171,6 +171,10 @@ describe('Cluster', () => {
cy.get('.MuiDialogContent-root').should('be.visible').and('contain', '10.0.0.0/8');
cy.get('body').click('topLeft');
+
+ cy.get(':nth-child(4) > .MuiPaper-root > .information_cidrsTags__4sKxa')
+ .should('be.visible')
+ .and('contain', 'cluster-1');
});
it('can display config', () => {
@@ -373,6 +377,7 @@ describe('Cluster', () => {
).click();
cy.get('.information_clusterContainer__l8H8p > :nth-child(1) > .MuiTypography-subtitle1')
+ .scrollIntoView()
.should('be.visible')
.and('contain', 'cluster-10');
@@ -444,6 +449,7 @@ describe('Cluster', () => {
).click();
cy.get('.information_clusterContainer__l8H8p > :nth-child(1) > .MuiTypography-subtitle1')
+ .scrollIntoView()
.should('be.visible')
.and('contain', 'cluster-1');
@@ -516,6 +522,7 @@ describe('Cluster', () => {
).click();
cy.get('.information_clusterContainer__l8H8p > :nth-child(1) > .MuiTypography-subtitle1')
+ .scrollIntoView()
.should('be.visible')
.and('contain', 'cluster-10');
@@ -565,6 +572,7 @@ describe('Cluster', () => {
).click();
cy.get('.information_clusterContainer__l8H8p > :nth-child(1) > .MuiTypography-subtitle1')
+ .scrollIntoView()
.should('be.visible')
.and('contain', 'cluster-10');
diff --git a/cypress/e2e/clusters/create-cluster.cy.ts b/cypress/e2e/clusters/create-cluster.cy.ts
index 60434ca6..1a9d249a 100644
--- a/cypress/e2e/clusters/create-cluster.cy.ts
+++ b/cypress/e2e/clusters/create-cluster.cy.ts
@@ -280,6 +280,7 @@ describe('Create cluster', () => {
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');
@@ -323,6 +324,22 @@ describe('Create cluster', () => {
// Verification passed.
cy.get('#cidrs-helper-text').should('not.exist');
+
+ // Should display cidrs the validation error message.
+ cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').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(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
+ 'hostname{enter}',
+ );
+ cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').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', () => {
diff --git a/cypress/e2e/clusters/update-cluster.cy.ts b/cypress/e2e/clusters/update-cluster.cy.ts
index f522b29c..7f25ba25 100644
--- a/cypress/e2e/clusters/update-cluster.cy.ts
+++ b/cypress/e2e/clusters/update-cluster.cy.ts
@@ -66,6 +66,11 @@ describe('Update cluster', () => {
.and('contain', '192.168.0.0/16')
.and('contain', '172.16.0.0/12');
+ cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root')
+ .should('contain', 'cluster-1')
+ .and('contain', 'cluster-2')
+ .and('contain', 'cluster-3');
+
// Show config.
cy.get('#seedPeerLoadLimit').should('have.value', 300);
cy.get('#peerLoadLimit').should('have.value', 51);
@@ -332,6 +337,22 @@ describe('Update cluster', () => {
'192.168.40.0/24{enter}',
);
cy.get('#cidrs-helper-text').should('not.exist');
+
+ // Should display hostnames the validation error message.
+ cy.get(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').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(':nth-child(4) > .MuiAutocomplete-root > .MuiFormControl-root > .MuiInputBase-root').type(
+ 'cluster-1{enter}',
+ );
+ cy.get('#hostnames-helper-text').should('not.exist');
});
it('try to verify config', () => {
diff --git a/cypress/e2e/job/preheats/create-preheat.cy.ts b/cypress/e2e/job/preheats/create-preheat.cy.ts
index 4ce3d86a..0e508c98 100644
--- a/cypress/e2e/job/preheats/create-preheat.cy.ts
+++ b/cypress/e2e/job/preheats/create-preheat.cy.ts
@@ -359,12 +359,12 @@ describe('Create preheat', () => {
// Incorrect header value entered.
cy.get('.new_headersValueInput__zn-9E > .MuiInputBase-root').type(value);
- // Show header value verification error message.
+ // Show header value verification error message.
cy.get('.new_headersValueInput__zn-9E > .MuiFormHelperText-root')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-1000.');
- // Show header value verification error message.
+ // Show header value verification error message.
cy.get('.new_headersValueInput__zn-9E > .MuiFormHelperText-root')
.should('be.visible')
.and('have.text', 'Fill in the characters, the length is 1-1000.');
diff --git a/cypress/e2e/seed-peers/seed-peers.cy.ts b/cypress/e2e/seed-peers/seed-peers.cy.ts
index 06771d51..36b17be5 100644
--- a/cypress/e2e/seed-peers/seed-peers.cy.ts
+++ b/cypress/e2e/seed-peers/seed-peers.cy.ts
@@ -183,7 +183,7 @@ describe('Seed peers', () => {
describe('pagination', () => {
it('pagination updates results and page number', () => {
- cy.get('#seed-peer-table').should('be.visible');
+ cy.get('#seed-peer-table').scrollIntoView().should('be.visible');
// Check number of pagination.
cy.get('#seed-peer-pagination > .MuiPagination-ul').children().should('have.length', 5);
@@ -470,6 +470,8 @@ describe('Seed peers', () => {
.should('be.visible')
.and('contain', 'Inactive');
+ cy.get(':nth-child(5) > :nth-child(9) > .MuiButtonBase-root').click();
+
cy.intercept({ method: 'DELETE', url: '/api/v1/seed-peers/9' }, (req) => {
req.reply({
statusCode: 200,
@@ -488,8 +490,6 @@ describe('Seed peers', () => {
},
);
- cy.get(':nth-child(5) > :nth-child(9) > .MuiButtonBase-root').click();
-
cy.get('#deleteSeedPeer').click();
// Delete success message.
diff --git a/cypress/fixtures/clusters/cluster/cluster.json b/cypress/fixtures/clusters/cluster/cluster.json
index 2b258e58..16d81894 100644
--- a/cypress/fixtures/clusters/cluster/cluster.json
+++ b/cypress/fixtures/clusters/cluster/cluster.json
@@ -5,7 +5,8 @@
"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"]
+ "cidrs": ["10.0.0.0/8", "192.168.0.0/16", "172.16.0.0/12"],
+ "hostnames": ["cluster-1", "cluster-2", "cluster-3"]
},
"scheduler_cluster_id": 1,
"seed_peer_cluster_id": 1,
diff --git a/cypress/fixtures/clusters/cluster/update-cluster.json b/cypress/fixtures/clusters/cluster/update-cluster.json
index 3e7abdec..11114aae 100644
--- a/cypress/fixtures/clusters/cluster/update-cluster.json
+++ b/cypress/fixtures/clusters/cluster/update-cluster.json
@@ -5,7 +5,8 @@
"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"]
+ "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,
diff --git a/cypress/fixtures/clusters/create-cluster.json b/cypress/fixtures/clusters/create-cluster.json
index 4e0c1b3d..d2dc033a 100644
--- a/cypress/fixtures/clusters/create-cluster.json
+++ b/cypress/fixtures/clusters/create-cluster.json
@@ -31,7 +31,8 @@
"scopes": {
"idc": "",
"location": "",
- "cidrs": []
+ "cidrs": [],
+ "hostnames": []
},
"scheduler_cluster_id": 2,
"seed_peer_cluster_id": 2,
@@ -56,7 +57,8 @@
"scopes": {
"idc": "Korea",
"location": "Seoul|Korea",
- "cidrs": ["192.168.0.0/16", "172.16.0.0/12"]
+ "cidrs": ["192.168.0.0/16", "172.16.0.0/12"],
+ "hostnames": []
},
"scheduler_cluster_id": 3,
"seed_peer_cluster_id": 3,
@@ -81,7 +83,8 @@
"scopes": {
"idc": "hz|dl",
"location": "China|Hang|Zhou",
- "cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
+ "cidrs": ["10.0.0.0/8", "192.168.0.0/16"],
+ "hostnames": []
},
"scheduler_cluster_id": 4,
"seed_peer_cluster_id": 4,
@@ -106,7 +109,8 @@
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Qing",
- "cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
+ "cidrs": ["10.0.0.0/8", "192.168.0.0/16"],
+ "hostnames": []
},
"scheduler_cluster_id": 5,
"seed_peer_cluster_id": 5,
@@ -131,7 +135,8 @@
"scopes": {
"idc": "cq|cd",
"location": "China|Chong|Du",
- "cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
+ "cidrs": ["10.0.0.0/8", "192.168.0.0/16"],
+ "hostnames": []
},
"scheduler_cluster_id": 6,
"seed_peer_cluster_id": 6,
@@ -156,7 +161,8 @@
"scopes": {
"idc": "cd",
"location": "China|Cheng|Du",
- "cidrs": ["10.0.0.0/8", "172.16.0.0/19"]
+ "cidrs": ["10.0.0.0/8", "172.16.0.0/19"],
+ "hostnames": []
},
"scheduler_cluster_id": 7,
"seed_peer_cluster_id": 7,
@@ -181,7 +187,8 @@
"scopes": {
"idc": "js",
"location": "China|Jiang|Su",
- "cidrs": ["10.0.0.0/5", "172.16.0.0/19"]
+ "cidrs": ["10.0.0.0/5", "172.16.0.0/19"],
+ "hostnames": []
},
"scheduler_cluster_id": 8,
"seed_peer_cluster_id": 8,
@@ -206,7 +213,8 @@
"scopes": {
"idc": "hz|hf",
"location": "China|Hang|Zhou",
- "cidrs": ["10.0.0.0/8", "192.168.0.0/16"]
+ "cidrs": ["10.0.0.0/8", "192.168.0.0/16"],
+ "hostnames": []
},
"scheduler_cluster_id": 9,
"seed_peer_cluster_id": 9,
@@ -231,7 +239,8 @@
"scopes": {
"idc": "London",
"location": "London|England",
- "cidrs": ["192.168.255.255"]
+ "cidrs": ["192.168.255.255"],
+ "hostnames": []
},
"scheduler_cluster_id": 10,
"seed_peer_cluster_id": 10,
@@ -256,7 +265,8 @@
"scopes": {
"idc": "Paris",
"location": "Paris|France",
- "cidrs": ["192.168.0.0", "10.0.0.0"]
+ "cidrs": ["192.168.0.0", "10.0.0.0"],
+ "hostnames": []
},
"scheduler_cluster_id": 11,
"seed_peer_cluster_id": 11,
@@ -281,7 +291,8 @@
"scopes": {
"idc": "hz|sh",
"location": "China|Hang|Zhou",
- "cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
+ "cidrs": ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"],
+ "hostnames": []
},
"scheduler_cluster_id": 12,
"seed_peer_cluster_id": 12,
diff --git a/public/icons/cluster/cidrs.svg b/public/icons/cluster/cidrs.svg
index ecdff45b..8c1312a1 100644
--- a/public/icons/cluster/cidrs.svg
+++ b/public/icons/cluster/cidrs.svg
@@ -1 +1,8 @@
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/public/icons/cluster/hostname.svg b/public/icons/cluster/hostname.svg
index 5b584edb..807ca332 100644
--- a/public/icons/cluster/hostname.svg
+++ b/public/icons/cluster/hostname.svg
@@ -1 +1,8 @@
-
\ No newline at end of file
+
+
\ No newline at end of file
diff --git a/public/icons/cluster/hostnames.svg b/public/icons/cluster/hostnames.svg
new file mode 100644
index 00000000..7940c6a3
--- /dev/null
+++ b/public/icons/cluster/hostnames.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/src/components/clusters/edit.tsx b/src/components/clusters/edit.tsx
index 656c453e..6631a31e 100644
--- a/src/components/clusters/edit.tsx
+++ b/src/components/clusters/edit.tsx
@@ -34,7 +34,12 @@ export default function EditCluster() {
const [locationError, setLocationError] = useState(false);
const [idcError, setIDCError] = useState(false);
const [cidrsError, setCIDRsError] = useState(false);
+ const [hostnamesError, setHostnamesError] = useState(false);
const [loadingButton, setLoadingButton] = useState(false);
+ const cidrsOptions = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'];
+ const [idcHelperText, setIDCHelperText] = useState('Fill in the characters, the length is 0-100.');
+ const [cidrsHelperText, setCIDRsHelperText] = useState('Fill in the characters, the length is 0-1000.');
+ const [hostnamesHelperText, setHostnamesHelperText] = useState('Fill in the characters, the length is 1-30.');
const [cluster, setCluster] = useState({
id: 0,
name: '',
@@ -43,6 +48,7 @@ export default function EditCluster() {
idc: '',
location: '',
cidrs: [],
+ hostnames: [],
},
scheduler_cluster_id: 0,
seed_peer_cluster_id: 0,
@@ -60,10 +66,6 @@ export default function EditCluster() {
updated_at: '',
is_default: false,
});
- const cidrsOptions = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'];
- const [idcHelperText, setIDCHelperText] = useState('Fill in the characters, the length is 0-100.');
- const [cidrsHelperText, setCIDRsHelperText] = useState('Fill in the characters, the length is 0-1000.');
-
const navigate = useNavigate();
const params = useParams();
@@ -73,7 +75,7 @@ export default function EditCluster() {
id,
peer_cluster_config: { load_limit },
scheduler_cluster_config: { candidate_parent_limit, filter_parent_limit },
- scopes: { idc, location, cidrs },
+ scopes: { idc, location, cidrs, hostnames },
seed_peer_cluster_config,
} = cluster;
@@ -162,6 +164,7 @@ export default function EditCluster() {
{
name: 'idc',
label: 'IDC',
+ enterMultiple: true,
scopesFormProps: {
value: cluster?.scopes?.idc ? cluster?.scopes?.idc.split('|') : [] || [],
options: [],
@@ -189,7 +192,22 @@ export default function EditCluster() {
placeholder: 'Please enter IDC',
error: idcError,
helperText: idcError ? idcHelperText : '',
-
+ endadornment: (
+
+
+
+ ),
onKeyDown: (e: any) => {
if (e.keyCode === 13) {
e.preventDefault();
@@ -207,6 +225,7 @@ export default function EditCluster() {
{
name: 'cidrs',
label: 'CIDRs',
+ enterMultiple: true,
scopesFormProps: {
value: cidrs || [],
options: cidrsOptions,
@@ -234,7 +253,24 @@ export default function EditCluster() {
placeholder: 'Please enter CIDRs',
error: cidrsError,
helperText: cidrsError ? cidrsHelperText : '',
-
+ endadornment: (
+
+
+
+ ),
onKeyDown: (e: any) => {
if (e.keyCode === 13) {
e.preventDefault();
@@ -249,6 +285,71 @@ export default function EditCluster() {
return reg.test(value);
},
},
+ {
+ name: 'hostnames',
+ label: 'Hostnames',
+ enterMultiple: true,
+ scopesFormProps: {
+ value: hostnames,
+ options: [],
+
+ onChange: (_e: any, newValue: any) => {
+ if (!scopesForm[3].formProps.error) {
+ setCluster({ ...cluster, scopes: { ...cluster.scopes, hostnames: newValue } });
+ }
+ },
+
+ onInputChange: (e: any) => {
+ setHostnamesHelperText('Fill in the characters, the length is 0-1000.');
+ changeValidate(e.target.value, scopesForm[3]);
+ },
+
+ renderTags: (value: any, getTagProps: any) =>
+ value.map((option: any, index: any) => (
+
+ )),
+ },
+
+ formProps: {
+ id: 'hostnames',
+ label: 'Hostnames',
+ name: 'hostnames',
+ placeholder: 'Please enter Hostnames',
+ error: hostnamesError,
+ helperText: hostnamesError ? hostnamesHelperText : '',
+ endadornment: (
+
+
+
+ ),
+ onKeyDown: (e: any) => {
+ if (e.keyCode === 13) {
+ e.preventDefault();
+ }
+ },
+ },
+
+ syncError: false,
+ setError: setHostnamesError,
+
+ validate: (value: string) => {
+ const reg = /^(.{1,30})$/;
+ return reg.test(value);
+ },
+ },
];
const configForm = [
@@ -435,6 +536,7 @@ export default function EditCluster() {
const data = new FormData(event.currentTarget);
const idcText = event.currentTarget.elements.idc.value;
const cidrsText = event.currentTarget.elements.cidrs.value;
+ const hostnamesText = event.currentTarget.elements.hostnames.value;
if (idcText) {
setIDCHelperText('Please press ENTER to end the IDC creation.');
@@ -452,6 +554,14 @@ export default function EditCluster() {
setCIDRsHelperText('Fill in the characters, the length is 0-100.');
}
+ if (hostnamesText) {
+ setHostnamesHelperText('Please press ENTER to end the Hostnames creation.');
+ setHostnamesError(true);
+ } else {
+ setHostnamesError(false);
+ setHostnamesHelperText('Fill in the characters, the length is 1-30.');
+ }
+
informationForm.forEach((item) => {
const value = data.get(item.formProps.name);
item.setError(!item.validate(value as string));
@@ -477,7 +587,8 @@ export default function EditCluster() {
!scopesForm.filter((item) => item.syncError).length &&
!configForm.filter((item) => item.syncError).length &&
Boolean(!idcText) &&
- Boolean(!cidrsText),
+ Boolean(!cidrsText) &&
+ Boolean(!hostnamesText),
);
const formdata = {
@@ -494,6 +605,7 @@ export default function EditCluster() {
cidrs: cidrs,
idc: String(idc),
location: String(location),
+ hostnames: hostnames,
},
seed_peer_cluster_config: {
load_limit: Number(seed_peer_cluster_config.load_limit),
@@ -612,7 +724,7 @@ export default function EditCluster() {
{scopesForm.map((item) => {
return (
- {item.label === 'CIDRs' ? (
+ {item.enterMultiple ? (
- {params.InputProps.endAdornment}
-
-
-
- >
- ),
- }}
- color="success"
- {...item.formProps}
- />
- )}
- />
- ) : item.label === 'IDC' ? (
- (
-
- {params.InputProps.endAdornment}
-
-
-
- >
- ),
+ endAdornment: item.formProps.endadornment,
}}
color="success"
{...item.formProps}
diff --git a/src/components/clusters/information.module.css b/src/components/clusters/information.module.css
index ad18f889..a7e98934 100644
--- a/src/components/clusters/information.module.css
+++ b/src/components/clusters/information.module.css
@@ -35,12 +35,26 @@
display: flex;
flex-direction: column;
justify-content: space-between;
- width: 65%;
+ width: 60%;
align-items: stretch;
}
+.scopesCard {
+ width: 50%;
+ padding-right: 0.6rem;
+}
+
+.scopesCard:nth-child(1) {
+ padding-bottom: 0.6rem !important;
+}
+
+.scopesCard:nth-child(2) {
+ padding-bottom: 0.6rem !important;
+}
+
.scopesContentContainer {
display: flex;
+ flex-wrap: wrap;
height: 100%;
}
@@ -86,12 +100,16 @@
.cidrsContainer {
height: 100%;
- padding: 1.4rem;
+ padding: 1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
}
+.cidrsTitleWrapper {
+ padding-bottom: 1rem;
+}
+
.cidrsTitle {
display: flex;
align-items: center;
@@ -122,26 +140,29 @@
}
.configRightContainer {
- width: 35%;
+ width: 40%;
max-width: 55rem;
+ display: flex;
+ flex-direction: column;
}
.configContainer {
display: flex;
align-items: center;
- margin-bottom: 0.6rem;
+ margin-bottom: 1rem;
}
.configListContainer {
- padding-left: 1rem;
- padding-right: 1rem;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ justify-content: space-around;
}
.configContent {
+ padding: 1rem;
display: flex;
justify-content: space-between;
- margin-top: 0.6rem;
- margin-bottom: 0.6rem;
}
.idcDialogContainer {
diff --git a/src/components/clusters/information.tsx b/src/components/clusters/information.tsx
index 428c74d6..929cc3f4 100644
--- a/src/components/clusters/information.tsx
+++ b/src/components/clusters/information.tsx
@@ -12,6 +12,7 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
const { cluster, isLoading } = props;
const [openCIDRs, setOpenCIDRs] = useState(false);
const [openIDC, setOpenIDC] = useState(false);
+ const [openHostnames, setOpenHostnames] = useState(false);
const [showSchedulerClusterIDCopyIcon, setShowSchedulerClusterIDCopyIcon] = useState(false);
const [showSeedPeerClusterIDCopyIcon, setShowSeedPeerClusterIDCopyIcon] = useState(false);
const [, setCopyToClipboard] = useCopyToClipboard();
@@ -220,7 +221,7 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
-
+
Scopes
@@ -235,8 +236,8 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
-
-
+
+
@@ -262,7 +263,7 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
-
+
@@ -355,7 +356,7 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
-
+
@@ -363,7 +364,7 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
CIDRs
@@ -444,6 +445,97 @@ export default function Information(props: { cluster: getClusterResponse; isLoad
+
+
+
+
+
+ Hostnames
+
+
+
+
+
+
+
+
+
+ {isLoading ? (
+
+ ) : (
+
+ {cluster?.scopes?.hostnames?.length > 0 ? (
+ <>
+
+
+
+
+ {cluster?.scopes?.hostnames[0]}
+
+
+
+ {cluster?.scopes?.hostnames?.length > 1 ? (
+
+
+
+ {cluster?.scopes?.hostnames[1]}
+
+
+
+ ) : (
+ <>>
+ )}
+
+ {cluster?.scopes?.hostnames?.length > 2 ? (
+ {
+ setOpenHostnames(true);
+ }}
+ >
+
+
+ ) : (
+ <>>
+ )}
+ >
+ ) : (
+
+ -
+
+ )}
+
+ )}
+
+
+
diff --git a/src/components/clusters/new.tsx b/src/components/clusters/new.tsx
index df0b8ba6..50c57c58 100644
--- a/src/components/clusters/new.tsx
+++ b/src/components/clusters/new.tsx
@@ -20,6 +20,7 @@ import CancelIcon from '@mui/icons-material/Cancel';
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import { useNavigate } from 'react-router-dom';
import { createCluster } from '../../lib/api';
+import { hostname } from 'os';
export default function NewCluster() {
const [successMessage, setSuccessMessage] = useState(false);
@@ -34,12 +35,15 @@ export default function NewCluster() {
const [locationError, setLocationError] = useState(false);
const [idcError, setIDCError] = useState(false);
const [cidrsError, setCIDRsError] = useState(false);
+ const [hostnamesError, setHostnamesError] = useState(false);
const [cidrs, setCIDRs] = useState([]);
const [idc, setIDC] = useState([]);
+ const [hostnames, setHostnames] = useState([]);
const [loadingButton, setLoadingButton] = useState(false);
const cidrsOptions = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'];
const [idcHelperText, setIDCHelperText] = useState('Fill in the characters, the length is 0-100.');
const [cidrsHelperText, setCIDRsHelperText] = useState('Fill in the characters, the length is 0-1000.');
+ const [hostnamesHelperText, setHostnamesHelperText] = useState('Fill in the characters, the length is 1-30.');
const navigate = useNavigate();
const informationForm = [
@@ -129,6 +133,7 @@ export default function NewCluster() {
{
name: 'idc',
label: 'IDC',
+ enterMultiple: true,
scopesFormProps: {
value: idc,
options: [],
@@ -156,7 +161,24 @@ export default function NewCluster() {
placeholder: 'Please enter IDC',
error: idcError,
helperText: idcError ? idcHelperText : '',
-
+ endadornment: (
+ <>
+
+
+
+ >
+ ),
onKeyDown: (e: any) => {
if (e.keyCode === 13) {
e.preventDefault();
@@ -175,6 +197,7 @@ export default function NewCluster() {
{
name: 'cidrs',
label: 'CIDRs',
+ enterMultiple: true,
scopesFormProps: {
value: cidrs,
options: cidrsOptions,
@@ -204,6 +227,24 @@ export default function NewCluster() {
error: cidrsError,
helperText: cidrsError ? cidrsHelperText : '',
+ endadornment: (
+
+
+
+ ),
onKeyDown: (e: any) => {
if (e.keyCode === 13) {
e.preventDefault();
@@ -219,6 +260,71 @@ export default function NewCluster() {
return reg.test(value);
},
},
+ {
+ name: 'hostnames',
+ label: 'Hostnames',
+ enterMultiple: true,
+ scopesFormProps: {
+ value: hostnames,
+ options: [],
+
+ onChange: (_e: any, newValue: any) => {
+ if (!scopesForm[3].formProps.error) {
+ setHostnames(newValue);
+ }
+ },
+
+ onInputChange: (e: any) => {
+ setHostnamesHelperText('Fill in the characters, the length is 1-30.');
+ changeValidate(e.target.value, scopesForm[3]);
+ },
+
+ renderTags: (value: any, getTagProps: any) =>
+ value.map((option: any, index: any) => (
+
+ )),
+ },
+
+ formProps: {
+ id: 'hostnames',
+ label: 'Hostnames',
+ name: 'hostnames',
+ placeholder: 'Please enter Hostnames',
+ error: hostnamesError,
+ helperText: hostnamesError ? hostnamesHelperText : '',
+ endadornment: (
+
+
+
+ ),
+ onKeyDown: (e: any) => {
+ if (e.keyCode === 13) {
+ e.preventDefault();
+ }
+ },
+ },
+
+ syncError: false,
+ setError: setHostnamesError,
+
+ validate: (value: string) => {
+ const reg = /^(.{1,30})$/;
+ return reg.test(value);
+ },
+ },
];
const configForm = [
@@ -383,6 +489,7 @@ export default function NewCluster() {
const filterParentLimit = event.currentTarget.elements.filterParentLimit.value;
const idcText = event.currentTarget.elements.idc.value;
const cidrsText = event.currentTarget.elements.cidrs.value;
+ const hostnamesText = event.currentTarget.elements.hostnames.value;
if (idcText) {
setIDCHelperText('Please press ENTER to end the IDC creation.');
@@ -397,7 +504,15 @@ export default function NewCluster() {
setCIDRsError(true);
} else {
setCIDRsError(false);
- setCIDRsHelperText('Fill in the characters, the length is 0-100.');
+ setCIDRsHelperText('Fill in the characters, the length is 0-1000.');
+ }
+
+ if (hostnamesText) {
+ setHostnamesHelperText('Please press ENTER to end the Hostnames creation.');
+ setHostnamesError(true);
+ } else {
+ setHostnamesError(false);
+ setHostnamesHelperText('Fill in the characters, the length is 1-30.');
}
informationForm.forEach((item) => {
@@ -427,7 +542,8 @@ export default function NewCluster() {
!scopesForm.filter((item) => item.syncError).length &&
!configForm.filter((item) => item.syncError).length &&
Boolean(!idcText) &&
- Boolean(!cidrsText),
+ Boolean(!cidrsText) &&
+ Boolean(!hostnamesText),
);
const formData = {
@@ -448,6 +564,7 @@ export default function NewCluster() {
cidrs: cidrs,
idc: idcs,
location: location,
+ hostnames: hostnames,
},
};
@@ -560,47 +677,7 @@ export default function NewCluster() {
{scopesForm.map((item) => {
return (
- {item.label === 'CIDRs' ? (
- (
-
- {params.InputProps.endAdornment}
-
-
-
- >
- ),
- }}
- color="success"
- {...item.formProps}
- />
- )}
- />
- ) : item.label === 'IDC' ? (
+ {item.enterMultiple ? (
- {params.InputProps.endAdornment}
-
-
-
- >
- ),
+ endAdornment: item.formProps.endadornment,
}}
color="success"
{...item.formProps}
diff --git a/src/components/clusters/show.tsx b/src/components/clusters/show.tsx
index a6350e2c..632eb038 100644
--- a/src/components/clusters/show.tsx
+++ b/src/components/clusters/show.tsx
@@ -86,6 +86,7 @@ export default function ShowCluster() {
idc: '',
location: '',
cidrs: [],
+ hostnames: [],
},
scheduler_cluster_id: 0,
seed_peer_cluster_id: 0,
diff --git a/src/lib/api.ts b/src/lib/api.ts
index 373c7e1e..3636d9b7 100644
--- a/src/lib/api.ts
+++ b/src/lib/api.ts
@@ -175,6 +175,7 @@ export interface getClustersResponse {
idc: string;
location: string;
cidrs: Array;
+ hostnames: Array;
};
created_at: string;
is_default: boolean;
@@ -197,6 +198,7 @@ export interface getClusterResponse {
idc: string;
location: string;
cidrs: Array;
+ hostnames: Array;
};
scheduler_cluster_id: number;
seed_peer_cluster_id: number;
@@ -239,6 +241,7 @@ interface createClusterRequest {
cidrs: Array;
idc: string;
location: string;
+ hostnames: Array;
};
}
@@ -263,6 +266,7 @@ interface createClusterResponse {
cidrs: Array;
idc: string;
location: string;
+ hostnames: Array;
};
}
@@ -286,6 +290,7 @@ interface updateClusterRequset {
cidrs: Array;
idc: string;
location: string;
+ hostnames: Array;
};
seed_peer_cluster_config: {
load_limit: number;
@@ -313,6 +318,7 @@ interface updateClusterResponse {
cidrs: Array;
idc: string;
location: string;
+ hostnames: Array;
};
}