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

liuxiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 1a0b12b  feat: upstream support FQDN (#2118)
1a0b12b is described below

commit 1a0b12bf70489104cd996848ded19ad3bdc6902f
Author: liuxiran <[email protected]>
AuthorDate: Fri Sep 3 15:14:29 2021 +0800

    feat: upstream support FQDN (#2118)
---
 web/cypress/fixtures/selector.json                 |  6 ++---
 .../create-route-with-plugin-orchestration.spec.js |  9 +++----
 .../create-plugin-template-with-route.spec.js      |  6 ++---
 ...an-skip-upstream-when-select-service-id.spec.js |  6 ++---
 .../create-edit-duplicate-delete-route.spec.js     |  6 ++---
 .../route/create-route-both-use-uri-uris.spec.js   |  6 ++---
 ...create-route-when-not-select-upsteam-id.spec.js |  6 ++---
 ...route-with-advanced-matching-conditions.spec.js |  6 ++---
 .../create-route-with-api-breaker-form.spec.js     |  6 ++---
 .../route/create-route-with-chash-upstream.spec.js |  6 ++---
 .../route/create-route-with-cors-form.spec.js      |  6 ++---
 ...eate-route-with-limit-count-plugin-form.spec.js |  6 ++---
 .../route/create-route-with-limit-req-form.spec.js |  6 ++---
 .../create-route-with-proxy-mirror-form.spec.js    |  6 ++---
 .../create-route-with-proxy-rewrite-plugin.spec.js |  6 ++---
 ...ate-route-with-referer-restriction-form.spec.js |  6 ++---
 .../route/create-route-with-upstream.spec.js       | 21 ++++++++++-----
 .../integration/route/import_export_route.spec.js  | 13 ++++++----
 web/cypress/integration/route/search-route.spec.js |  6 ++---
 .../service/create-edit-delete-service.spec.js     |  6 ++---
 .../create-service-with-chash-upstream.spec.js     |  6 ++---
 ...create-service-with-not-select-upstream.spec.js |  6 ++---
 .../service/edit-service-with-upstream.spec.js     |  6 ++---
 .../upstream/create_and_delete_upstream.spec.js    | 22 +++++++++-------
 ...and_edit_upstream_with_custom_chash_key.spec.js |  6 ++---
 web/src/components/Upstream/components/Nodes.tsx   |  8 +-----
 web/src/components/Upstream/service.ts             | 30 +++++++++++++++++-----
 web/src/components/Upstream/typings.d.ts           |  6 ++++-
 web/src/pages/Upstream/typing.d.ts                 |  3 ++-
 29 files changed, 132 insertions(+), 106 deletions(-)

diff --git a/web/cypress/fixtures/selector.json 
b/web/cypress/fixtures/selector.json
index 83b1924..7728578 100644
--- a/web/cypress/fixtures/selector.json
+++ b/web/cypress/fixtures/selector.json
@@ -18,9 +18,9 @@
   "checkedSwitcher": ".ant-switch-checked",
   "deleteButton": ".ant-btn-dangerous",
   "name": "#name",
-  "nodes_0_host": "#nodes_0_host",
-  "nodes_0_port": "#nodes_0_port",
-  "nodes_0_weight": "#nodes_0_weight",
+  "nodes_0_host": "#submitNodes_0_host",
+  "nodes_0_port": "#submitNodes_0_port",
+  "nodes_0_weight": "#submitNodes_0_weight",
   "upstream_id": "#upstream_id",
   "input": ":input",
   "nameSelector": "[title=Name]",
diff --git 
a/web/cypress/integration/plugin/create-route-with-plugin-orchestration.spec.js 
b/web/cypress/integration/plugin/create-route-with-plugin-orchestration.spec.js
index 34ff152..4c3801d 100644
--- 
a/web/cypress/integration/plugin/create-route-with-plugin-orchestration.spec.js
+++ 
b/web/cypress/integration/plugin/create-route-with-plugin-orchestration.spec.js
@@ -21,9 +21,9 @@ context('Create and delete route with plugin orchestration', 
() => {
     empty: '.ant-empty-normal',
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     groupButton: '.ant-radio-group',
     canvas: '.x6-graph-svg',
     startNode:
@@ -78,9 +78,6 @@ context('Create and delete route with plugin orchestration', 
() => {
     cy.get(selector.canvasNode)
       .click()
       .then(() => {
-        const node2 = cy
-          .get('#container > svg > g > g.x6-graph-svg-stage > g:nth-child(2) > 
g > circle')
-          .eq(0);
         const node1 = cy
           .get('#container > svg > g > g.x6-graph-svg-stage > g:nth-child(1) > 
g > circle')
           .eq(0);
diff --git 
a/web/cypress/integration/pluginTemplate/create-plugin-template-with-route.spec.js
 
b/web/cypress/integration/pluginTemplate/create-plugin-template-with-route.spec.js
index 5c2f669..8916977 100644
--- 
a/web/cypress/integration/pluginTemplate/create-plugin-template-with-route.spec.js
+++ 
b/web/cypress/integration/pluginTemplate/create-plugin-template-with-route.spec.js
@@ -24,9 +24,9 @@ context('Create PluginTemplate Binding To Route', () => {
     refresh: '.anticon-reload',
     descriptionSelector: '[title=Description]',
     name: '#name',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     customSelector: '[title=Custom]',
     notificationClose: '.anticon-close',
     nameSelector: '[title=Name]',
diff --git 
a/web/cypress/integration/route/can-skip-upstream-when-select-service-id.spec.js
 
b/web/cypress/integration/route/can-skip-upstream-when-select-service-id.spec.js
index 2333ac0..530cef3 100644
--- 
a/web/cypress/integration/route/can-skip-upstream-when-select-service-id.spec.js
+++ 
b/web/cypress/integration/route/can-skip-upstream-when-select-service-id.spec.js
@@ -19,9 +19,9 @@
 context('Can select service_id skip upstream in route', () => {
   const selector = {
     name: '#name',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     notification: '.ant-notification-notice-message',
     upstreamSelector: '[data-cy=upstream_selector]',
     input: ':input',
diff --git 
a/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js 
b/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
index 1cf49f9..df7a384 100644
--- a/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
+++ b/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
@@ -35,9 +35,9 @@ context('Create and Delete Route', () => {
     ruleCard: '.ant-modal',
     operator: '#operator',
     value: '#value',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     pluginCardBordered: '.ant-card-bordered',
     disabledSwitcher: '#disable',
     checkedSwitcher: '.ant-switch-checked',
diff --git 
a/web/cypress/integration/route/create-route-both-use-uri-uris.spec.js 
b/web/cypress/integration/route/create-route-both-use-uri-uris.spec.js
index 34ccac3..002d347 100644
--- a/web/cypress/integration/route/create-route-both-use-uri-uris.spec.js
+++ b/web/cypress/integration/route/create-route-both-use-uri-uris.spec.js
@@ -27,9 +27,9 @@ context('Create Route Both use uri and uris', () => {
     uris_1: '#uris_1',
     remote_addrs_0: '#remote_addrs_0',
     remote_addrs_1: '#remote_addrs_1',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     nameSelector: '[title=Name]',
     drawer: '.ant-drawer-content',
     monacoScroll: '.monaco-scrollable-element',
diff --git 
a/web/cypress/integration/route/create-route-when-not-select-upsteam-id.spec.js 
b/web/cypress/integration/route/create-route-when-not-select-upsteam-id.spec.js
index adda256..afadde2 100644
--- 
a/web/cypress/integration/route/create-route-when-not-select-upsteam-id.spec.js
+++ 
b/web/cypress/integration/route/create-route-when-not-select-upsteam-id.spec.js
@@ -19,9 +19,9 @@
 context('Create Route without Upstream', () => {
   const selector = {
     name: '#name',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     input: ':input',
     nameSelector: '[title=Name]',
     deleteAlert: '.ant-modal-body',
diff --git 
a/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
 
b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
index 5f7c771..ae4a2fc 100644
--- 
a/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
+++ 
b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
@@ -19,9 +19,9 @@
 context('Create Route with advanced matching conditions', () => {
   const selector = {
     name: '#name',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     deleteAlert: '.ant-modal-body',
     notificationCloseIcon: '.ant-notification-close-icon',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-api-breaker-form.spec.js 
b/web/cypress/integration/route/create-route-with-api-breaker-form.spec.js
index b09502b..76ba89f 100644
--- a/web/cypress/integration/route/create-route-with-api-breaker-form.spec.js
+++ b/web/cypress/integration/route/create-route-with-api-breaker-form.spec.js
@@ -25,9 +25,9 @@ context('Create and delete route with api-breaker form', () 
=> {
     disabledSwitcher: '#disable',
     checkedSwitcher: '.ant-switch-checked',
     drawer: '.ant-drawer-content',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     break_response_code: '#break_response_code',
     alert: '.ant-form-item-explain-error [role=alert]',
     deleteAlert: '.ant-modal-body',
diff --git 
a/web/cypress/integration/route/create-route-with-chash-upstream.spec.js 
b/web/cypress/integration/route/create-route-with-chash-upstream.spec.js
index 1a014bb..6058e59 100644
--- a/web/cypress/integration/route/create-route-with-chash-upstream.spec.js
+++ b/web/cypress/integration/route/create-route-with-chash-upstream.spec.js
@@ -25,9 +25,9 @@ context('Create and Edit Route With Custom CHash Key 
Upstream', () => {
     defaultCHashKey: '[value="remote_addr"]',
     upstreamType: '.ant-select-item-option-content',
     hashPosition: '.ant-select-item-option-content',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     nameSelector: '[title=Name]',
     chash_key: '#key',
     deleteAlert: '.ant-modal-body',
diff --git a/web/cypress/integration/route/create-route-with-cors-form.spec.js 
b/web/cypress/integration/route/create-route-with-cors-form.spec.js
index 67ee8f4..876e988 100644
--- a/web/cypress/integration/route/create-route-with-cors-form.spec.js
+++ b/web/cypress/integration/route/create-route-with-cors-form.spec.js
@@ -25,9 +25,9 @@ context('Create and delete route with cors form', () => {
     disabledSwitcher: '#disable',
     checkedSwitcher: '.ant-switch-checked',
     drawer: '.ant-drawer-content',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     deleteAlert: '.ant-modal-body',
     notificationCloseIcon: '.ant-notification-close-icon',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-limit-count-plugin-form.spec.js
 
b/web/cypress/integration/route/create-route-with-limit-count-plugin-form.spec.js
index 2ab7d0f..bf5814f 100644
--- 
a/web/cypress/integration/route/create-route-with-limit-count-plugin-form.spec.js
+++ 
b/web/cypress/integration/route/create-route-with-limit-count-plugin-form.spec.js
@@ -23,9 +23,9 @@ context('Create and delete route with limit-count form', () 
=> {
     description: '#desc',
     disabledSwitcher: '#disable',
     drawer: '.ant-drawer-content',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     deleteAlert: '.ant-modal-body',
     notificationCloseIcon: '.ant-notification-close-icon',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-limit-req-form.spec.js 
b/web/cypress/integration/route/create-route-with-limit-req-form.spec.js
index 8e3dee3..60f9664 100644
--- a/web/cypress/integration/route/create-route-with-limit-req-form.spec.js
+++ b/web/cypress/integration/route/create-route-with-limit-req-form.spec.js
@@ -25,9 +25,9 @@ context('Create and delete route with limit-req form', () => {
     drawer: '.ant-drawer-content',
     pluginCardBordered: '.ant-card-bordered',
     checkedSwitcher: '.ant-switch-checked',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     deleteAlert: '.ant-modal-body',
     notificationCloseIcon: '.ant-notification-close-icon',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-proxy-mirror-form.spec.js 
b/web/cypress/integration/route/create-route-with-proxy-mirror-form.spec.js
index 790e1d6..667558a 100644
--- a/web/cypress/integration/route/create-route-with-proxy-mirror-form.spec.js
+++ b/web/cypress/integration/route/create-route-with-proxy-mirror-form.spec.js
@@ -25,9 +25,9 @@ context('Create and delete route with proxy-mirror form', () 
=> {
     drawer: '.ant-drawer-content',
     pluginCardBordered: '.ant-card-bordered',
     checkedSwitcher: '.ant-switch-checked',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     deleteAlert: '.ant-modal-body',
     notificationCloseIcon: '.ant-notification-close-icon',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-proxy-rewrite-plugin.spec.js 
b/web/cypress/integration/route/create-route-with-proxy-rewrite-plugin.spec.js
index 8c77fca..6669c17 100644
--- 
a/web/cypress/integration/route/create-route-with-proxy-rewrite-plugin.spec.js
+++ 
b/web/cypress/integration/route/create-route-with-proxy-rewrite-plugin.spec.js
@@ -22,9 +22,9 @@ import routeLocaleUS from 
'../../../src/pages/Route/locales/en-US';
 context('create route with proxy-rewrite plugin', () => {
   const selector = {
     name: '#name',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     nameSelector: '[title=Name]',
     deleteAlert: '.ant-modal-body',
     notification: '.ant-notification-notice-message',
diff --git 
a/web/cypress/integration/route/create-route-with-referer-restriction-form.spec.js
 
b/web/cypress/integration/route/create-route-with-referer-restriction-form.spec.js
index 2e60ba8..9fa5d02 100644
--- 
a/web/cypress/integration/route/create-route-with-referer-restriction-form.spec.js
+++ 
b/web/cypress/integration/route/create-route-with-referer-restriction-form.spec.js
@@ -22,9 +22,9 @@ context('Create and delete route with referer-restriction 
form', () => {
     name: '#name',
     description: '#desc',
     pluginCardBordered: '.ant-card-bordered',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     disabledSwitcher: '#disable',
     checkedSwitcher: '.ant-switch-checked',
     drawer: '.ant-drawer-content',
diff --git a/web/cypress/integration/route/create-route-with-upstream.spec.js 
b/web/cypress/integration/route/create-route-with-upstream.spec.js
index 962f3f2..86dc812 100644
--- a/web/cypress/integration/route/create-route-with-upstream.spec.js
+++ b/web/cypress/integration/route/create-route-with-upstream.spec.js
@@ -20,9 +20,9 @@ context('Create Route with Upstream', () => {
   const selector = {
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     upstreamSelector: '[data-cy=upstream_selector]',
     nameSelector: '[title=Name]',
     input: ':input',
@@ -42,6 +42,7 @@ context('Create Route with Upstream', () => {
     routeName: 'test_route',
     ip1: '127.0.0.1',
     ip2: '127.0.0.2',
+    FQDN: 'bigserver.mycompany.com',
   };
 
   beforeEach(() => {
@@ -55,8 +56,14 @@ context('Create Route with Upstream', () => {
 
     cy.get(selector.name).type(data.upstreamName);
     cy.get(selector.description).type(data.description);
-    cy.get(selector.nodes_0_host).type(data.host1);
-    cy.get(selector.nodes_0_port).type(data.port);
+    cy.get(selector.nodes_0_host).type(data.FQDN);
+    cy.get('label[title="Port"]').then(($els) => {
+      const win = $els[0].ownerDocument.defaultView;
+      const before = win.getComputedStyle($els[0], 'before');
+      const contentValue = before.getPropertyValue('content');
+      expect(contentValue).to.eq('none');
+    });
+    cy.get(selector.nodes_0_port).clear();
     cy.get(selector.nodes_0_weight).type(data.weight);
     cy.contains('Next').click();
     cy.contains('Submit').click();
@@ -82,8 +89,8 @@ context('Create Route with Upstream', () => {
     cy.get(selector.upstreamSelector).click();
     cy.contains('.ant-select-item-option-content', 'Custom').click();
 
-    cy.get(selector.nodes_0_host).clear().type(data.ip1);
-    cy.get(selector.nodes_0_port).type(data.port);
+    cy.get(selector.nodes_0_host).should('have.value', 
data.FQDN).clear().type(data.ip1);
+    cy.get(selector.nodes_0_port).should('have.value', '').type(data.port);
     cy.get(selector.nodes_0_weight).type(data.weight);
     cy.contains('Next').click();
     cy.contains('Next').click();
diff --git a/web/cypress/integration/route/import_export_route.spec.js 
b/web/cypress/integration/route/import_export_route.spec.js
index 17e3afc..ec93db3 100644
--- a/web/cypress/integration/route/import_export_route.spec.js
+++ b/web/cypress/integration/route/import_export_route.spec.js
@@ -15,6 +15,9 @@
  * limitations under the License.
  */
 /* eslint-disable no-undef */
+/* eslint-disable @typescript-eslint/no-invalid-this */
+/* eslint-disable @typescript-eslint/no-loop-func */
+
 import actionBarUS from '../../../src/components/ActionBar/locales/en-US';
 import componentLocaleUS from '../../../src/locales/en-US/component';
 import menuLocaleUS from '../../../src/locales/en-US/menu';
@@ -25,9 +28,9 @@ context('import and export routes', () => {
   const selector = {
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     fileTypeRadio: '[type=radio]',
     deleteAlert: '.ant-modal-body',
     refresh: '.anticon-reload',
@@ -72,9 +75,9 @@ context('import and export routes', () => {
       // input name, click Next
       cy.contains('Next').click().click();
       cy.get(selector.name).type(data[`route_name_${i}`]);
-      //FIXME: only GET in methods
+      // FIXME: only GET in methods
       cy.get('#methods').click();
-      for (let i = 0; i < 7; i += 1) {
+      for (let j = 0; j < 7; j += 1) {
         cy.get('#methods').type('{backspace}');
       }
       cy.get('#methods').type('GET');
diff --git a/web/cypress/integration/route/search-route.spec.js 
b/web/cypress/integration/route/search-route.spec.js
index ad903b9..f93e11e 100644
--- a/web/cypress/integration/route/search-route.spec.js
+++ b/web/cypress/integration/route/search-route.spec.js
@@ -26,9 +26,9 @@ context('Create and Search Route', () => {
     uris_0: '#uris_0',
     labels_0_labelKey: '#labels_0_labelKey',
     labels_0_labelValue: '#labels_0_labelValue',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     nameSearchInput: '#name',
     pathSearchInput: '#uri',
     labelSelect_0: '.ant-select-selection-overflow',
diff --git a/web/cypress/integration/service/create-edit-delete-service.spec.js 
b/web/cypress/integration/service/create-edit-delete-service.spec.js
index bb0ac4e..a34c3f7 100644
--- a/web/cypress/integration/service/create-edit-delete-service.spec.js
+++ b/web/cypress/integration/service/create-edit-delete-service.spec.js
@@ -22,9 +22,9 @@ context('Create and Delete Service ', () => {
   const selector = {
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     pluginCardBordered: '.ant-card-bordered',
     disabledSwitcher: '#disable',
     drawer: '.ant-drawer-content',
diff --git 
a/web/cypress/integration/service/create-service-with-chash-upstream.spec.js 
b/web/cypress/integration/service/create-service-with-chash-upstream.spec.js
index 59daec6..d01e9eb 100644
--- a/web/cypress/integration/service/create-service-with-chash-upstream.spec.js
+++ b/web/cypress/integration/service/create-service-with-chash-upstream.spec.js
@@ -23,9 +23,9 @@ context('Create and Edit Service with Custom CHash Key 
Upstream', () => {
     roundRobinSelect: '[title="Round Robin"]',
     varSelect: '[title="vars"]',
     defaultCHashKey: '[value="remote_addr"]',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     upstreamType: '.ant-select-item-option-content',
     hashPosition: '.ant-select-item-option-content',
     chash_key: '#key',
diff --git 
a/web/cypress/integration/service/create-service-with-not-select-upstream.spec.js
 
b/web/cypress/integration/service/create-service-with-not-select-upstream.spec.js
index 53903ab..114144a 100644
--- 
a/web/cypress/integration/service/create-service-with-not-select-upstream.spec.js
+++ 
b/web/cypress/integration/service/create-service-with-not-select-upstream.spec.js
@@ -20,9 +20,9 @@ context('Edit Service with not select Upstream', () => {
   const selector = {
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     input: ':input',
     notification: '.ant-notification-notice-message',
     nameSearch: '[title=Name]',
diff --git a/web/cypress/integration/service/edit-service-with-upstream.spec.js 
b/web/cypress/integration/service/edit-service-with-upstream.spec.js
index 39878bb..c3f6981 100644
--- a/web/cypress/integration/service/edit-service-with-upstream.spec.js
+++ b/web/cypress/integration/service/edit-service-with-upstream.spec.js
@@ -21,9 +21,9 @@ context('Edit Service with Upstream', () => {
     empty: '.ant-empty-normal',
     name: '#name',
     description: '#desc',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     notification: '.ant-notification-notice-message',
     upstreamSelector: '[data-cy=upstream_selector]',
     input: ':input',
diff --git 
a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js 
b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
index dc6b8d0..6798186 100644
--- a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
+++ b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
@@ -24,9 +24,12 @@ context('Create and Delete Upstream', () => {
     service_name: '#service_name',
     discovery_type_group_name: '#discovery_args_group_name',
     discovery_type_namespace_id: '#discovery_args_namespace_id',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
+    nodes_1_host: '#submitNodes_1_host',
+    nodes_1_port: '#submitNodes_1_port',
+    nodes_1_weight: '#submitNodes_1_weight',
     input: ':input',
     notification: '.ant-notification-notice-message',
     nameSelector: '[title=Name]',
@@ -44,6 +47,7 @@ context('Create and Delete Upstream', () => {
     namespaceId: 'test_ns1',
     description: 'desc_by_autotest',
     ip1: '127.0.0.1',
+    FQDN: 'bigserver.mycompany.com',
     createUpstreamSuccess: 'Create Upstream Successfully',
     configureUpstreamSuccess: 'Configure Upstream Successfully',
     deleteUpstreamSuccess: 'Delete Upstream Successfully',
@@ -57,7 +61,7 @@ context('Create and Delete Upstream', () => {
     cy.login();
   });
 
-  it('should create upstream with default type (roundrobin)', function () {
+  /* it('should create upstream with default type (roundrobin)', function () {
     cy.visit('/');
     cy.contains('Upstream').click();
     cy.contains('Create').click();
@@ -131,13 +135,13 @@ context('Create and Delete Upstream', () => {
 
     // add second upstream node
     cy.get('.ant-btn-dashed').click();
-    cy.get('#nodes_1_host').type(data.ip1);
-    cy.get('#nodes_1_port').clear().type(data.port1);
-    cy.get('#nodes_1_weight').clear().type(data.weight1);
+    cy.get(selector.nodes_1_host).type(data.FQDN);
+    cy.get(selector.nodes_1_port).clear().type(data.port1);
+    cy.get(selector.nodes_1_weight).clear().type(data.weight1);
 
     // next to finish
     cy.contains('Next').click();
-    cy.contains('Submit').click();
+    cy.contains('Submit').click({force: true});
     cy.get(selector.notification).should('contain', 
data.createUpstreamSuccess);
     cy.url().should('contains', 'upstream/list');
   });
@@ -164,7 +168,7 @@ context('Create and Delete Upstream', () => {
     cy.contains(data.upstreamName).siblings().contains('Delete').click();
     cy.contains('button', 'Confirm').click();
     cy.get(selector.notification).should('contain', 
data.deleteUpstreamSuccess);
-  });
+  }); */
 
   it('should create upstream with DNS service discover (roundrobin)', function 
() {
     cy.visit('/');
diff --git 
a/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
 
b/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
index 152677a..7b02a14 100644
--- 
a/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
+++ 
b/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
@@ -23,9 +23,9 @@ context('Create and Delete Upstream With Custom CHash Key', 
() => {
     roundRobinSelect: '[title="Round Robin"]',
     varSelect: '[title="vars"]',
     defaultCHashKey: '[value="remote_addr"]',
-    nodes_0_host: '#nodes_0_host',
-    nodes_0_port: '#nodes_0_port',
-    nodes_0_weight: '#nodes_0_weight',
+    nodes_0_host: '#submitNodes_0_host',
+    nodes_0_port: '#submitNodes_0_port',
+    nodes_0_weight: '#submitNodes_0_weight',
     upstreamType: '.ant-select-item-option-content',
     hashPosition: '.ant-select-item-option-content',
     chash_key: '#key',
diff --git a/web/src/components/Upstream/components/Nodes.tsx 
b/web/src/components/Upstream/components/Nodes.tsx
index 5fc8b8e..c9953c6 100644
--- a/web/src/components/Upstream/components/Nodes.tsx
+++ b/web/src/components/Upstream/components/Nodes.tsx
@@ -30,7 +30,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
 
   return (
     <Form.List
-      name="nodes"
+      name="submitNodes"
       initialValue={[{ host: undefined, port: undefined, weight: undefined }]}
     >
       {(fields, { add, remove }) => (
@@ -72,12 +72,6 @@ const Component: React.FC<Props> = ({ readonly }) => {
                     style={{ marginBottom: 0 }}
                     name={[field.name, 'port']}
                     label={formatMessage({ id: 'page.upstream.step.port' })}
-                    rules={[
-                      {
-                        required: true,
-                        message: formatMessage({ id: 
'page.upstream.step.input.port' }),
-                      },
-                    ]}
                   >
                     <InputNumber
                       placeholder={formatMessage({ id: 
'page.upstream.step.port' })}
diff --git a/web/src/components/Upstream/service.ts 
b/web/src/components/Upstream/service.ts
index b6ed0e5..4baa449 100644
--- a/web/src/components/Upstream/service.ts
+++ b/web/src/components/Upstream/service.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import { notification } from 'antd';
-import { isNil, omitBy, omit, pick, cloneDeep } from 'lodash';
+import { isNil, omitBy, omit, cloneDeep } from 'lodash';
 import { formatMessage, request } from 'umi';
 
 /**
@@ -55,6 +55,17 @@ export const convertToFormData = (originData: 
UpstreamComponent.ResponseData) =>
   if (data.nodes) {
     data.upstream_type = 'node';
   }
+  // nodes have two types
+  // https://github.com/apache/apisix-dashboard/issues/2080
+  if (data.nodes instanceof Array) {
+    data['submitNodes'] = data.nodes;
+  } else if (data.nodes) {
+    data['submitNodes'] = Object.keys(data.nodes as Object).map((key) => ({
+      host: key.split(':')[0],
+      port: key.split(':')[1],
+      weight: (data.nodes as Object)[key],
+    }));
+  }
 
   if (data.discovery_type && data.service_name) {
     data.upstream_type = 'service_discovery';
@@ -77,7 +88,7 @@ export const convertToRequestData = (
     hash_on,
     key,
     upstream_type,
-    nodes,
+    submitNodes,
     discovery_type,
     discovery_args,
     service_name,
@@ -115,16 +126,21 @@ export const convertToRequestData = (
     return undefined;
   }
 
-  if (upstream_type === 'node' && nodes) {
+  if (upstream_type === 'node' && submitNodes) {
     /**
-     * nodes will be [] or node list
+     * submitNodes will be [] or node list
      * when upstream_id === none, None === undefined
      */
     // NOTE: https://github.com/ant-design/ant-design/issues/27396
-    data.nodes = nodes?.map((item) => {
-      return pick(item, ['host', 'port', 'weight']);
+    data.nodes = {};
+    submitNodes?.forEach((item) => {
+      const port = item.port ? `:${item.port}` : '';
+      data.nodes = {
+        ...data.nodes,
+        [`${item.host}${port}`]: item.weight as number,
+      };
     });
-    return omit(data, 'upstream_type');
+    return omit(data, ['upstream_type', 'submitNodes']);
   }
 
   if (upstream_type === 'service_discovery' && discovery_type && service_name) 
{
diff --git a/web/src/components/Upstream/typings.d.ts 
b/web/src/components/Upstream/typings.d.ts
index 78e01b9..1f9ba96 100644
--- a/web/src/components/Upstream/typings.d.ts
+++ b/web/src/components/Upstream/typings.d.ts
@@ -35,6 +35,10 @@ declare namespace UpstreamComponent {
     priority?: number;
   };
 
+  type SubmitNode = {
+    [propName: string]: number;
+  };
+
   type Timeout = {
     connect: number;
     send: number;
@@ -42,7 +46,7 @@ declare namespace UpstreamComponent {
   };
 
   type ResponseData = {
-    nodes?: Node[];
+    nodes?: SubmitNode | Node[];
     retries?: number;
     timeout?: Timeout;
     tls?: TLS;
diff --git a/web/src/pages/Upstream/typing.d.ts 
b/web/src/pages/Upstream/typing.d.ts
index 3416354..3a7d03e 100644
--- a/web/src/pages/Upstream/typing.d.ts
+++ b/web/src/pages/Upstream/typing.d.ts
@@ -76,7 +76,7 @@ declare namespace UpstreamModule {
     discovery_type?: DiscoveryType;
     service_name?: string;
     discovery_args?: DiscoveryArgs;
-    nodes?: Node[];
+    nodes?: UpstreamComponent.SubmitNode;
     hash_on?: 'vars' | 'header' | 'cookie' | 'consumer';
     key?: string;
     checks?: HealthCheck;
@@ -90,6 +90,7 @@ declare namespace UpstreamModule {
 
     // Custom Fields that need to be omitted
     custom?: {};
+    submitNodes?: Node[];
   };
 
   // TODO: typing

Reply via email to