You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by we...@apache.org on 2021/04/15 04:29:45 UTC
[apisix-dashboard] branch master updated: feat: added default
values & missing fields to Upstream (#1764)
This is an automated email from the ASF dual-hosted git repository.
wenming 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 4b86ef2 feat: added default values & missing fields to Upstream (#1764)
4b86ef2 is described below
commit 4b86ef2ae8841fda6386cd24a071030dc5a43db9
Author: 琚致远 <ju...@apache.org>
AuthorDate: Thu Apr 15 12:29:39 2021 +0800
feat: added default values & missing fields to Upstream (#1764)
---
web/cypress/fixtures/data.json | 2 +
web/cypress/fixtures/selector.json | 18 +--
.../create-plugin-template-with-route.spec.js | 2 +
...an-skip-upstream-when-select-service-id.spec.js | 2 +
.../create-edit-duplicate-delete-route.spec.js | 2 +
.../create-route-with-api-breaker-form.spec.js | 2 +
.../route/create-route-with-cors-form.spec.js | 2 +
.../route/create-route-with-limit-req-form.spec.js | 2 +
.../create-route-with-proxy-mirror-form.spec.js | 4 +-
.../create-route-with-proxy-rewrite-plugin.spec.js | 2 +
...ate-route-with-referer-restriction-form.spec.js | 2 +
.../route/create-route-with-upstream.spec.js | 6 +
.../integration/route/import_export_route.spec.js | 2 +
web/cypress/integration/route/search-route.spec.js | 2 +
.../service/create-edit-delete-service.spec.js | 2 +
.../service/edit-service-with-upstream.spec.js | 4 +
.../upstream/create_and_delete_upstream.spec.js | 6 +-
web/src/components/Upstream/UpstreamForm.tsx | 129 +++++++++++++--------
.../components/{Retries.tsx => DiscoveryType.tsx} | 17 +--
web/src/components/Upstream/components/Nodes.tsx | 2 +-
.../components/Upstream/components/PassHost.tsx | 1 +
web/src/components/Upstream/components/Retries.tsx | 3 +-
web/src/components/Upstream/components/Scheme.tsx | 5 +-
.../components/{Retries.tsx => ServiceName.tsx} | 17 +--
web/src/components/Upstream/components/TLS.tsx | 93 +++++++++++++++
web/src/components/Upstream/components/Timeout.tsx | 5 +-
web/src/components/Upstream/components/Type.tsx | 80 +++++--------
.../active-check/{Timeout.tsx => Concurrency.tsx} | 10 +-
.../{Unhealthy => Healthy}/HttpStatuses.tsx | 5 +-
.../components/active-check/Healthy/Interval.tsx | 5 +-
.../components/active-check/Healthy/Successes.tsx | 7 +-
.../components/active-check/Healthy/index.ts | 4 +-
.../Upstream/components/active-check/Host.tsx | 14 +--
.../Upstream/components/active-check/HttpPath.tsx | 9 +-
.../HttpsVerifyCertificate.tsx} | 17 +--
.../Upstream/components/active-check/Port.tsx | 6 +-
.../components/active-check/ReqHeaders.tsx | 5 +-
.../Upstream/components/active-check/Timeout.tsx | 2 +-
.../Upstream/components/active-check/Type.tsx | 38 +++---
.../active-check/Unhealthy/HttpFailures.tsx | 7 +-
.../active-check/Unhealthy/HttpStatuses.tsx | 2 +-
.../components/active-check/Unhealthy/Interval.tsx | 5 +-
.../Unhealthy/TCPFailures.tsx} | 17 ++-
.../components/active-check/Unhealthy/Timeouts.tsx | 26 +++--
.../components/active-check/Unhealthy/index.ts | 4 +-
.../Upstream/components/active-check/index.ts | 6 +-
.../passive-check/Healthy/HttpStatuses.tsx | 4 +-
.../components/passive-check/Healthy/Successes.tsx | 7 +-
.../Upstream/components/passive-check/Type.tsx | 66 ++++++-----
.../passive-check/Unhealthy/HttpFailures.tsx | 5 +-
.../passive-check/Unhealthy/HttpStatuses.tsx | 2 +-
.../passive-check/Unhealthy/TcpFailures.tsx | 1 +
.../passive-check/Unhealthy/Timeouts.tsx | 26 +++--
web/src/components/Upstream/constant.ts | 109 +++++++----------
web/src/components/Upstream/locales/en-US.ts | 91 +++++++++++++++
web/src/components/Upstream/locales/zh-CN.ts | 96 +++++++++++++++
.../Unhealthy/Timeouts.tsx => service.ts} | 44 ++++---
web/src/components/Upstream/typings.d.ts | 67 +++++++++++
web/src/locales/en-US.ts | 4 +-
web/src/locales/en-US/component.ts | 1 +
web/src/locales/zh-CN.ts | 4 +-
web/src/locales/zh-CN/component.ts | 1 +
web/src/pages/Route/Create.tsx | 9 +-
web/src/pages/Service/Create.tsx | 8 +-
web/src/pages/Upstream/Create.tsx | 5 +-
web/src/pages/Upstream/components/Step1.tsx | 4 +-
web/src/pages/Upstream/locales/en-US.ts | 22 +---
web/src/pages/Upstream/locales/zh-CN.ts | 32 +----
web/src/pages/Upstream/transform.ts | 4 +
web/src/pages/Upstream/typing.d.ts | 3 +
70 files changed, 795 insertions(+), 423 deletions(-)
diff --git a/web/cypress/fixtures/data.json b/web/cypress/fixtures/data.json
index 1ea7bcd..9c14e98 100644
--- a/web/cypress/fixtures/data.json
+++ b/web/cypress/fixtures/data.json
@@ -20,6 +20,8 @@
"host1": "11.11.11.11",
"host2": "12.12.12.12",
"host3": "10.10.10.10",
+ "port": "80",
+ "weight": 1,
"description": "desc_by_autotest",
"description2": "description2",
"grafanaAddress": "Grafana Address",
diff --git a/web/cypress/fixtures/selector.json b/web/cypress/fixtures/selector.json
index b903e0f..f075bc0 100644
--- a/web/cypress/fixtures/selector.json
+++ b/web/cypress/fixtures/selector.json
@@ -1,7 +1,6 @@
{
"codeMirror": ".CodeMirror",
"username": "#username",
-
"languageSwitcher": ".ant-space-align-center",
"dropdown": ".rc-virtual-list",
"notification": ".ant-notification-notice-message",
@@ -9,12 +8,10 @@
"notificationCloseIcon": ".ant-notification-close-icon",
"notificationDesc": ".ant-notification-notice-description",
"errorNotification:": ".ant-notification-notice-error",
-
"pluginCard": ".ant-card",
"pluginCardBordered": ".ant-card-bordered",
"pageContent": ".ant-pro-page-container",
-
- "tableBody":".ant-table-tbody",
+ "tableBody": ".ant-table-tbody",
"tableCell": ".ant-table-cell",
"empty": ".ant-empty-normal",
"refresh": ".anticon-reload",
@@ -22,16 +19,15 @@
"disabledSwitcher": "#disable",
"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",
"upstream_id": "#upstream_id",
"input": ":input",
"nameSelector": "[title=Name]",
"serviceSelector": "[title=test_service]",
"nameSearch": "[title=Name]",
-
"description": "#desc",
"upstreamSelector": "[data-cy=upstream_selector]",
"addHost": "[data-cy=addHost]",
@@ -43,27 +39,21 @@
"ruleCard": ".ant-modal",
"operator": "#operator",
"value": "#value",
-
"fileSelector": "[type=file]",
"fileTypeRadio": "[type=radio]",
"fileSelectorClose": ".ant-modal-close",
-
"debugUri": "#debugUri",
-
"hosts_0": "#hosts_0",
"labels_0_labelKey": "#labels_0_labelKey",
"labels_0_labelValue": "#labels_0_labelValue",
"labelSelector": "[title=Labels]",
"labelSelect_0": ".ant-select-selection-overflow",
-
"pageContainer": ".ant-pro-page-container",
"notificationMessage": ".ant-notification-notice-message",
"avatar": ".ant-space-align-center",
"grafanaURL": "#grafanaURL",
"explain": ".ant-form-item-explain",
-
"upstreamType": ".ant-select-item-option-content",
-
"errorExplain": ".ant-form-item-explain",
"usernameInput": "#control-ref_username",
"passwordInput": "#control-ref_password",
@@ -76,7 +66,6 @@
"notificationClose": ".anticon-close",
"redirectURIInput": "#redirectURI",
"redirectCodeSelector": "#ret_code",
-
"paginationOptions": ".ant-pagination-options",
"fiftyPerPage": "[title=\"50 / page\"]",
"twentyPerPage": "[title=\"20 / page\"]",
@@ -85,7 +74,6 @@
"pageTwoActived": ".ant-pagination-item-2.ant-pagination-item-active",
"selectDropdown": ".ant-select-dropdown",
"codeMirrorMode": "[data-cy='code-mirror-mode']",
- "selectJSON":".ant-select-dropdown [label=JSON]",
-
+ "selectJSON": ".ant-select-dropdown [label=JSON]",
"deleteAlert": ".ant-modal-body"
}
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 8be0f49..4a3b703 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
@@ -46,6 +46,8 @@ context('Create PluginTemplate Binding To Route', () => {
cy.get(this.domSelector.name).type(this.data.routeName);
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
cy.contains('Custom').should('be.visible');
cy.get(this.domSelector.customSelector).click();
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 0ca5d28..d62cd87 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
@@ -31,6 +31,8 @@ context('Can select service_id skip upstream in route', () => {
cy.get(this.domSelector.name).type(this.data.upstreamName);
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
+ cy.get(this.domSelector.nodes_0_port).clear().type('7000');
+ cy.get(this.domSelector.nodes_0_weight).clear().type(1);
cy.contains('Next').click();
cy.contains('Submit').click();
cy.get(this.domSelector.notification).should('contain', this.data.createUpstreamSuccess);
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 6e16a7e..5919048 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
@@ -65,6 +65,8 @@ context('Create and Delete Route', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type(this.data.host2);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
// redirect plugin should not display in route step3
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 8437d9d..93e3e2a 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
@@ -40,6 +40,8 @@ context('Create and delete route with api-breaker form', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type('127.0.0.1');
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
// config api-breaker plugin
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 915effb..beabccc 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
@@ -40,6 +40,8 @@ context('Create and delete route with cors form', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type('127.0.0.1');
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
// config cors plugin
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 8609d04..e215163 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
@@ -42,6 +42,8 @@ context('Create and delete route with limit-req form', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type('127.0.0.1');
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
// config limit-req plugin
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 7637568..87ac24d 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
@@ -40,6 +40,8 @@ context('Create and delete route with proxy-mirror form', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type('127.0.0.1');
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
// config proxy-mirror plugin
@@ -100,6 +102,6 @@ context('Create and delete route with proxy-mirror form', () => {
cy.contains('OK').click();
});
cy.get(domSelector.notification).should('contain', data.deleteRouteSuccess);
- cy.get(domSelector.notificationCloseIcon).click();
+ cy.get(domSelector.notificationCloseIcon).click({ multiple: true });
});
});
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 1d8173d..5ce18fd 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
@@ -90,6 +90,8 @@ context('create route with proxy-rewrite plugin', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type(this.data.host2);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
// should not see proxy-rewrite plugin in the step3
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 39e13a3..4987d16 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
@@ -40,6 +40,8 @@ context('Create and delete route with referer-restriction form', () => {
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type('127.0.0.1');
+ cy.get(this.domSelector.nodes_0_port).clear().type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).clear().type(this.data.weight);
cy.contains('Next').click();
// config referer-restriction plugin
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 a6cf351..2a976b8 100644
--- a/web/cypress/integration/route/create-route-with-upstream.spec.js
+++ b/web/cypress/integration/route/create-route-with-upstream.spec.js
@@ -32,6 +32,8 @@ context('Create Route with Upstream', () => {
cy.get(this.domSelector.name).type(this.data.upstreamName);
cy.get(this.domSelector.description).type(this.data.description);
cy.get(this.domSelector.nodes_0_host).type(this.data.host1);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
cy.contains('Submit').click();
});
@@ -56,6 +58,8 @@ context('Create Route with Upstream', () => {
cy.get(this.domSelector.input).should('not.be.disabled');
cy.get(this.domSelector.nodes_0_host).clear().type(this.data.ip1);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();
@@ -87,6 +91,8 @@ context('Create Route with Upstream', () => {
cy.get(this.domSelector.input).should('not.be.disabled');
cy.get(this.domSelector.nodes_0_host).clear().type(this.data.ip2);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();
diff --git a/web/cypress/integration/route/import_export_route.spec.js b/web/cypress/integration/route/import_export_route.spec.js
index c327c58..ea877f3 100644
--- a/web/cypress/integration/route/import_export_route.spec.js
+++ b/web/cypress/integration/route/import_export_route.spec.js
@@ -66,6 +66,8 @@ context('import and export routes', () => {
cy.contains(actionBarUS['component.actionbar.button.nextStep']).click();
// input nodes_0_host, click Next
cy.get(this.domSelector.nodes_0_host).type(data[`upstream_node0_host_${i}`]);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains(actionBarUS['component.actionbar.button.nextStep']).click();
// do not config plugins, click Next
cy.contains(actionBarUS['component.actionbar.button.nextStep']).click();
diff --git a/web/cypress/integration/route/search-route.spec.js b/web/cypress/integration/route/search-route.spec.js
index 381b9fe..37bae68 100644
--- a/web/cypress/integration/route/search-route.spec.js
+++ b/web/cypress/integration/route/search-route.spec.js
@@ -63,6 +63,8 @@ context('Create and Search Route', () => {
cy.get(this.domSelector.nodes_0_host).type(this.data.host2, {
timeout,
});
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();
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 8c7fa0a..5551629 100644
--- a/web/cypress/integration/service/create-edit-delete-service.spec.js
+++ b/web/cypress/integration/service/create-edit-delete-service.spec.js
@@ -35,6 +35,8 @@ context('Create and Delete Service ', () => {
cy.get(this.domSelector.description).type(this.data.description);
cy.get(this.domSelector.nodes_0_host).click();
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
+ cy.get(this.domSelector.nodes_0_port).clear().type('7000');
+ cy.get(this.domSelector.nodes_0_weight).clear().type(1);
cy.contains('Next').click();
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 1d89ee3..87be509 100644
--- a/web/cypress/integration/service/edit-service-with-upstream.spec.js
+++ b/web/cypress/integration/service/edit-service-with-upstream.spec.js
@@ -30,6 +30,8 @@ context('Edit Service with Upstream', () => {
cy.contains('Create').click();
cy.get(this.domSelector.name).type(this.data.upstreamName);
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
+ cy.get(this.domSelector.nodes_0_port).clear().type('7000');
+ cy.get(this.domSelector.nodes_0_weight).clear().type(1);
cy.contains('Next').click();
cy.contains('Submit').click();
cy.get(this.domSelector.notification).should('contain', this.data.createUpstreamSuccess);
@@ -66,6 +68,8 @@ context('Edit Service with Upstream', () => {
cy.get(this.domSelector.upstreamSelector).click();
cy.contains('Custom').click();
cy.get(this.domSelector.nodes_0_host).should('not.be.disabled').clear().type(this.data.ip2);
+ cy.get(this.domSelector.nodes_0_port).type(this.data.port);
+ cy.get(this.domSelector.nodes_0_weight).type(this.data.weight);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();
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 a8063eb..4f2c0fa 100644
--- a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
+++ b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
@@ -34,6 +34,7 @@ context('Create and Delete Upstream', () => {
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
cy.get(this.domSelector.nodes_0_port).clear().type('7000');
+ cy.get(this.domSelector.nodes_0_weight).clear().type(1);
cy.contains('Next').click();
cy.contains('Submit').click();
cy.get(this.domSelector.notification).should('contain', this.data.createUpstreamSuccess);
@@ -78,11 +79,11 @@ context('Create and Delete Upstream', () => {
cy.get(this.domSelector.upstreamType).within(() => {
cy.contains('CHash').click();
});
- cy.get('#hash_on').click();
+ cy.get('#hash_on').click({ force: true });
cy.get(this.domSelector.upstreamType).within(() => {
cy.contains('vars').click();
});
- cy.get('#key').click();
+ cy.get('#key').click({ force: true });
cy.get(this.domSelector.upstreamType).within(() => {
cy.contains('remote_addr').click();
});
@@ -90,6 +91,7 @@ context('Create and Delete Upstream', () => {
// add first upstream node
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
cy.get(this.domSelector.nodes_0_port).clear().type('7000');
+ cy.get(this.domSelector.nodes_0_weight).clear().type(1);
// add second upstream node
cy.get('.ant-btn-dashed').click();
diff --git a/web/src/components/Upstream/UpstreamForm.tsx b/web/src/components/Upstream/UpstreamForm.tsx
index 7fade14..42d7144 100644
--- a/web/src/components/Upstream/UpstreamForm.tsx
+++ b/web/src/components/Upstream/UpstreamForm.tsx
@@ -21,7 +21,6 @@ import type { FormInstance } from 'antd/es/form';
import { PanelSection } from '@api7-dashboard/ui';
import { transformRequest } from '@/pages/Upstream/transform';
-import { DEFAULT_UPSTREAM } from './constant';
import PassiveCheck from './components/passive-check';
import ActiveCheck from './components/active-check'
import Nodes from './components/Nodes'
@@ -31,6 +30,8 @@ import Type from './components/Type';
import UpstreamSelector from './components/UpstreamSelector';
import Retries from './components/Retries';
import PassHost from './components/PassHost';
+import TLSComponent from './components/TLS';
+import { transformUpstreamDataFromRequest } from './service';
type Upstream = {
name?: string;
@@ -86,14 +87,18 @@ const UpstreamForm: React.FC<Props> = forwardRef(
if (required) {
requestAnimationFrame(() => {
form.resetFields();
- form.setFieldsValue(DEFAULT_UPSTREAM);
setHiddenForm(false);
});
}
} else {
if (upstream_id) {
requestAnimationFrame(() => {
- form.setFieldsValue(list.find((item) => item.id === upstream_id));
+ const targetData = list.find((item) => item.id === upstream_id) as UpstreamComponent.ResponseData
+ if (targetData) {
+ form.setFieldsValue(transformUpstreamDataFromRequest(targetData));
+ } else {
+ // TODO: 提示 upstream_id 找不到想要的数据
+ }
});
}
if (!required && !Object.keys(formData).length) {
@@ -106,15 +111,24 @@ const UpstreamForm: React.FC<Props> = forwardRef(
setReadonly(Boolean(upstream_id) || disabled);
}, [list]);
-
-
const ActiveHealthCheck = () => (
<React.Fragment>
<ActiveCheck.Type readonly={readonly} />
+ <Form.Item noStyle shouldUpdate={(prev, next) => prev.checks.active.type !== next.checks.active.type}>
+ {() => {
+ const type = form.getFieldValue(['checks', 'active', 'type'])
+ if (['https'].includes(type)) {
+ return <ActiveCheck.HttpsVerifyCertificate readonly={readonly} />
+ }
+ return null
+ }}
+ </Form.Item>
<ActiveCheck.Timeout readonly={readonly} />
+ <ActiveCheck.Concurrency readonly={readonly} />
<ActiveCheck.Host readonly={readonly} />
<ActiveCheck.Port readonly={readonly} />
<ActiveCheck.HttpPath readonly={readonly} />
+ <ActiveCheck.ReqHeaders readonly={readonly} />
<Divider orientation="left" plain>
{formatMessage({ id: 'page.upstream.step.healthyCheck.healthy.status' })}
@@ -122,6 +136,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
<ActiveCheck.Healthy.Interval readonly={readonly} />
<ActiveCheck.Healthy.Successes readonly={readonly} />
+ <ActiveCheck.Healthy.HttpStatuses readonly={readonly} />
<Divider orientation="left" plain>
{formatMessage({ id: 'page.upstream.step.healthyCheck.unhealthyStatus' })}
@@ -131,14 +146,11 @@ const UpstreamForm: React.FC<Props> = forwardRef(
<ActiveCheck.Unhealthy.Interval readonly={readonly} />
<ActiveCheck.Unhealthy.HttpStatuses readonly={readonly} />
<ActiveCheck.Unhealthy.HttpFailures readonly={readonly} />
-
- <Divider orientation="left" plain>Others</Divider>
-
- <ActiveCheck.ReqHeaders readonly={readonly} />
+ <ActiveCheck.Unhealthy.TCPFailures readonly={readonly} />
</React.Fragment>
);
- const InActiveHealthCheck = () => (
+ const PassiveHealthCheck = () => (
<React.Fragment>
<PassiveCheck.Type readonly={readonly} />
@@ -161,55 +173,54 @@ const UpstreamForm: React.FC<Props> = forwardRef(
);
const HealthCheckComponent = () => {
- const options = [
- {
- label: formatMessage({ id: 'page.upstream.step.healthyCheck.active' }),
- name: ['checks', 'active'],
- component: (
- <>
- <ActiveHealthCheck />
- <Divider orientation="left" plain />
- </>
- ),
- },
- {
- label: formatMessage({ id: 'page.upstream.step.healthyCheck.passive' }),
- name: ['checks', 'passive'],
- component: <InActiveHealthCheck />,
- },
- ]
-
return (
<PanelSection
title={formatMessage({ id: 'page.upstream.step.healthyCheck.healthy.check' })}
>
- {options.map(({ label, name, component }) => (
- <div key={label}>
- <Form.Item label={label} name={name} valuePropName="checked" key={label}>
- <Switch disabled={readonly} />
- </Form.Item>
- <Form.Item shouldUpdate noStyle>
- {() => {
- if (form.getFieldValue(name)) {
- return component;
- }
- return null;
- }}
- </Form.Item>
- </div>
- ))}
+ <Form.Item label={formatMessage({ id: 'page.upstream.step.healthyCheck.active' })} name={['custom', 'checks', 'active']} valuePropName="checked">
+ <Switch disabled={readonly} />
+ </Form.Item>
+ <Form.Item shouldUpdate noStyle>
+ {
+ () => {
+ const active = form.getFieldValue(['custom', 'checks', 'active'])
+ if (active) {
+ return (
+ <ActiveHealthCheck />
+ )
+ }
+ return null
+ }
+ }
+ </Form.Item>
+ <Divider orientation="left" plain />
+ <Form.Item label={formatMessage({ id: 'page.upstream.step.healthyCheck.passive' })} name={['custom', 'checks', 'passive']} valuePropName="checked">
+ <Switch disabled={readonly} />
+ </Form.Item>
+ <Form.Item shouldUpdate noStyle>
+ {
+ () => {
+ const passive = form.getFieldValue(['custom', 'checks', 'passive'])
+ if (passive) {
+ /*
+ * When enable passive check, we should enable active check, too.
+ * When we use form.setFieldsValue to enable active check, error throws.
+ * We choose to alert users first, and need users to enable active check manually.
+ */
+ return <PassiveHealthCheck />
+ }
+ return null
+ }
+ }
+ </Form.Item>
</PanelSection>
)
}
-
return (
<Form
form={form}
labelCol={{ span: 3 }}
- initialValues={{
- pass_host: 'pass',
- }}
>
{showSelector && (
<UpstreamSelector
@@ -221,7 +232,10 @@ const UpstreamForm: React.FC<Props> = forwardRef(
if (prev.upstream_id !== next.upstream_id) {
const id = next.upstream_id;
if (id) {
- form.setFieldsValue(list.find((item) => item.id === id));
+ const targetData = list.find((item) => item.id === id) as UpstreamComponent.ResponseData
+ if (targetData) {
+ form.setFieldsValue(transformUpstreamDataFromRequest(targetData));
+ }
form.setFieldsValue({
upstream_id: id,
});
@@ -232,10 +246,12 @@ const UpstreamForm: React.FC<Props> = forwardRef(
onChange={(upstream_id) => {
setReadonly(Boolean(upstream_id));
setHiddenForm(Boolean(upstream_id === 'None'));
- form.setFieldsValue(list.find((item) => item.id === upstream_id));
+ const targetData = list.find((item) => item.id === upstream_id) as UpstreamComponent.ResponseData
+ if (targetData) {
+ form.setFieldsValue(transformUpstreamDataFromRequest(targetData));
+ }
if (upstream_id === '') {
form.resetFields();
- form.setFieldsValue(DEFAULT_UPSTREAM);
}
}}
/>
@@ -248,7 +264,20 @@ const UpstreamForm: React.FC<Props> = forwardRef(
<PassHost form={form} readonly={readonly} />
<Retries readonly={readonly} />
+
<Scheme readonly={readonly} />
+ <Form.Item noStyle shouldUpdate={(prev, next) => prev.scheme !== next.scheme}>
+ {
+ () => {
+ const scheme = form.getFieldValue("scheme") as string
+ if (["https", "grpcs"].includes(scheme)) {
+ return <TLSComponent form={form} readonly={readonly} />
+ }
+ return null
+ }
+ }
+ </Form.Item>
+
{timeoutFields.map((item, index) => (
<Timeout key={index} {...item} readonly={readonly} />
))}
diff --git a/web/src/components/Upstream/components/Retries.tsx b/web/src/components/Upstream/components/DiscoveryType.tsx
similarity index 66%
copy from web/src/components/Upstream/components/Retries.tsx
copy to web/src/components/Upstream/components/DiscoveryType.tsx
index a77ecef..031de33 100644
--- a/web/src/components/Upstream/components/Retries.tsx
+++ b/web/src/components/Upstream/components/DiscoveryType.tsx
@@ -15,25 +15,20 @@
* limitations under the License.
*/
import React from 'react'
-import { Form, InputNumber } from 'antd'
+import { Form, Input } from 'antd'
import { useIntl } from 'umi'
type Props = {
- readonly?: boolean
+ readonly?: boolean;
}
-const Component: React.FC<Props> = ({ readonly }) => {
+const DiscoveryType: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.Item
- label={formatMessage({ id: 'page.upstream.retries' })}
- name="retries"
- >
- <InputNumber
- disabled={readonly}
- />
+ <Form.Item name="discovery_type" label={formatMessage({ id: 'component.upstream.fields.discovery_type' })} tooltip={formatMessage({ id: 'component.upstream.fields.discovery_type.tooltip' })}>
+ <Input disabled={readonly} placeholder={formatMessage({ id: 'component.upstream.fields.discovery_type.placeholder' })} />
</Form.Item>
)
}
-export default Component
+export default DiscoveryType
diff --git a/web/src/components/Upstream/components/Nodes.tsx b/web/src/components/Upstream/components/Nodes.tsx
index 2a92d48..eaaa3a4 100644
--- a/web/src/components/Upstream/components/Nodes.tsx
+++ b/web/src/components/Upstream/components/Nodes.tsx
@@ -29,7 +29,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.List name="nodes">
+ <Form.List name="nodes" initialValue={[{ host: undefined, port: undefined, weight: undefined }]}>
{(fields, { add, remove }) => (
<>
<Form.Item label={formatMessage({ id: 'page.upstream.form.item-label.node.domain.or.ip' })} style={{ marginBottom: 0 }}>
diff --git a/web/src/components/Upstream/components/PassHost.tsx b/web/src/components/Upstream/components/PassHost.tsx
index 6102076..a2f7e45 100644
--- a/web/src/components/Upstream/components/PassHost.tsx
+++ b/web/src/components/Upstream/components/PassHost.tsx
@@ -46,6 +46,7 @@ const Component: React.FC<Props> = ({ form, readonly }) => {
<Form.Item
label={formatMessage({ id: 'page.upstream.step.pass-host' })}
name="pass_host"
+ initialValue="pass"
>
<Select disabled={readonly}>
{options.map(item => (
diff --git a/web/src/components/Upstream/components/Retries.tsx b/web/src/components/Upstream/components/Retries.tsx
index a77ecef..51d346e 100644
--- a/web/src/components/Upstream/components/Retries.tsx
+++ b/web/src/components/Upstream/components/Retries.tsx
@@ -26,7 +26,8 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.retries' })}
+ label={formatMessage({ id: 'component.upstream.fields.retries' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.retries.tooltip' })}
name="retries"
>
<InputNumber
diff --git a/web/src/components/Upstream/components/Scheme.tsx b/web/src/components/Upstream/components/Scheme.tsx
index 840d5e6..c289e28 100644
--- a/web/src/components/Upstream/components/Scheme.tsx
+++ b/web/src/components/Upstream/components/Scheme.tsx
@@ -38,13 +38,14 @@ type Props = {
readonly?: boolean
}
-const Component: React.FC<Props> = ({ readonly }) => {
+const Scheme: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
label={formatMessage({ id: 'page.upstream.scheme' })}
name="scheme"
rules={[{ required: true }]}
+ initialValue="http"
>
<Select disabled={readonly}>
{options.map(item => {
@@ -59,4 +60,4 @@ const Component: React.FC<Props> = ({ readonly }) => {
)
}
-export default Component
+export default Scheme
diff --git a/web/src/components/Upstream/components/Retries.tsx b/web/src/components/Upstream/components/ServiceName.tsx
similarity index 67%
copy from web/src/components/Upstream/components/Retries.tsx
copy to web/src/components/Upstream/components/ServiceName.tsx
index a77ecef..b0ef62c 100644
--- a/web/src/components/Upstream/components/Retries.tsx
+++ b/web/src/components/Upstream/components/ServiceName.tsx
@@ -15,25 +15,20 @@
* limitations under the License.
*/
import React from 'react'
-import { Form, InputNumber } from 'antd'
+import { Form, Input } from 'antd'
import { useIntl } from 'umi'
type Props = {
- readonly?: boolean
+ readonly?: boolean;
}
-const Component: React.FC<Props> = ({ readonly }) => {
+const ServiceName: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.Item
- label={formatMessage({ id: 'page.upstream.retries' })}
- name="retries"
- >
- <InputNumber
- disabled={readonly}
- />
+ <Form.Item name="service_name" label={formatMessage({ id: 'component.upstream.fields.service_name' })} tooltip={formatMessage({ id: 'component.upstream.fields.service_name.tooltip' })}>
+ <Input disabled={readonly} placeholder={formatMessage({ id: 'component.upstream.fields.service_name.placeholder' })} />
</Form.Item>
)
}
-export default Component
+export default ServiceName
diff --git a/web/src/components/Upstream/components/TLS.tsx b/web/src/components/Upstream/components/TLS.tsx
new file mode 100644
index 0000000..2d4feee
--- /dev/null
+++ b/web/src/components/Upstream/components/TLS.tsx
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react'
+import { Form, Row, Col, Select, FormInstance, Input } from 'antd'
+import { useIntl } from 'umi'
+
+type Props = {
+ form: FormInstance;
+ readonly?: boolean;
+}
+
+const TLSComponent: React.FC<Props> = ({ form, readonly }) => {
+ const { formatMessage } = useIntl()
+
+ return (
+ <React.Fragment>
+ <Form.Item
+ label={formatMessage({ id: 'component.upstream.fields.tls' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.tls.tooltip' })}
+ style={{ marginBottom: 0 }}
+ >
+ <Row>
+ <Col span={5}>
+ <Form.Item
+ name={["custom", "tls"]}
+ initialValue="disable"
+ >
+ <Select disabled={readonly}>
+ {
+ ["disable", "enable"].map(item => (
+ <Select.Option value={item} key={item}>
+ {formatMessage({ id: `component.global.${item}` })}
+ </Select.Option>
+ ))
+ }
+ </Select>
+ </Form.Item>
+ </Col>
+ </Row>
+ </Form.Item>
+ <Form.Item
+ noStyle
+ shouldUpdate={(prev, next) => {
+ return prev.custom.tls !== next.custom.tls
+ }}
+ >
+ {
+ () => {
+ if (form.getFieldValue(["custom", "tls"]) === 'enable') {
+ return (
+ <React.Fragment>
+ <Form.Item
+ label={formatMessage({ id: 'component.upstream.fields.tls.client_cert' })}
+ name={["tls", "client_cert"]}
+ required
+ rules={[{ required: true, message: "" }, { max: 64 * 1024 }, { min: 128 }]}
+ >
+ <Input.TextArea disabled={readonly} minLength={128} maxLength={64 * 1024} rows={5} placeholder="请输入客户端证书" />
+ </Form.Item>
+ <Form.Item
+ label={formatMessage({ id: 'component.upstream.fields.tls.client_key' })}
+ name={["tls", "client_key"]}
+ required
+ rules={[{ required: true, message: "" }, { max: 64 * 1024 }, { min: 128 }]}
+ >
+ <Input.TextArea disabled={readonly} minLength={128} maxLength={64 * 1024} rows={5} placeholder="请输入客户端私钥" />
+ </Form.Item>
+ </React.Fragment>
+ )
+ }
+ return null
+ }
+ }
+ </Form.Item>
+ </React.Fragment>
+ )
+}
+
+export default TLSComponent
diff --git a/web/src/components/Upstream/components/Timeout.tsx b/web/src/components/Upstream/components/Timeout.tsx
index 059b63a..8eefdf0 100644
--- a/web/src/components/Upstream/components/Timeout.tsx
+++ b/web/src/components/Upstream/components/Timeout.tsx
@@ -20,7 +20,7 @@ import { useIntl } from 'umi'
import TimeUnit from './TimeUnit'
-const Component: React.FC<{
+const Timeout: React.FC<{
label: string;
desc: string;
name: string[];
@@ -38,6 +38,7 @@ const Component: React.FC<{
message: formatMessage({ id: `page.upstream.step.input.${name[1]}.timeout` }),
},
]}
+ initialValue={6}
>
<InputNumber disabled={readonly} />
</Form.Item>
@@ -46,4 +47,4 @@ const Component: React.FC<{
)
}
-export default Component
+export default Timeout
diff --git a/web/src/components/Upstream/components/Type.tsx b/web/src/components/Upstream/components/Type.tsx
index 0a7ce25..8788ebb 100644
--- a/web/src/components/Upstream/components/Type.tsx
+++ b/web/src/components/Upstream/components/Type.tsx
@@ -19,63 +19,38 @@ import { Form, Select } from 'antd'
import { useIntl } from 'umi'
import type { FormInstance } from 'antd/es/form'
-enum Type {
- roundrobin = 'roundrobin',
- chash = 'chash',
- ewma = 'ewma',
- // TODO: new type
- // least_conn = 'least_conn'
-}
-
-enum HashOn {
- vars = 'vars',
- header = 'header',
- cookie = 'cookie',
- consumer = 'consumer',
- // TODO: new hash_on key
- // vars_combinations = 'vars_combinations'
-}
-
-enum HashKey {
- remote_addr = 'remote_addr',
- host = 'host',
- uri = 'uri',
- server_name = 'server_name',
- server_addr = 'server_addr',
- request_uri = 'request_uri',
- query_string = 'query_string',
- remote_port = 'remote_port',
- hostname = 'hostname',
- arg_id = 'arg_id',
-}
+import { HashOnEnum, CommonHashKeyEnum, AlgorithmEnum } from '../constant'
type Props = {
readonly?: boolean
form: FormInstance
}
-const CHash: React.FC<Pick<Props, 'readonly'>> = ({ readonly }) => (
- <>
- <Form.Item label="Hash On" name="hash_on" rules={[{ required: true }]}>
- <Select disabled={readonly}>
- {Object.entries(HashOn).map(([label, value]) => (
- <Select.Option value={value} key={value}>
- {label}
- </Select.Option>
- ))}
- </Select>
- </Form.Item>
- <Form.Item label="Key" name="key" rules={[{ required: true }]}>
- <Select disabled={readonly}>
- {Object.entries(HashKey).map(([label, value]) => (
- <Select.Option value={value} key={value}>
- {label}
- </Select.Option>
- ))}
- </Select>
- </Form.Item>
- </>
-);
+const CHash: React.FC<Pick<Props, 'readonly'>> = ({ readonly }) => {
+ const { formatMessage } = useIntl()
+ return (
+ <React.Fragment>
+ <Form.Item name="hash_on" rules={[{ required: true }]} label={formatMessage({ id: 'component.upstream.fields.hash_on' })} tooltip={formatMessage({ id: 'component.upstream.fields.hash_on.tooltip' })} initialValue="vars">
+ <Select disabled={readonly}>
+ {Object.entries(HashOnEnum).map(([label, value]) => (
+ <Select.Option value={value} key={value}>
+ {label}
+ </Select.Option>
+ ))}
+ </Select>
+ </Form.Item>
+ <Form.Item name="key" rules={[{ required: true }]} label={formatMessage({ id: 'component.upstream.fields.key' })} tooltip={formatMessage({ id: 'component.upstream.fields.key.tooltip' })} initialValue="remote_addr">
+ <Select disabled={readonly}>
+ {Object.entries(CommonHashKeyEnum).map(([label, value]) => (
+ <Select.Option value={value} key={value}>
+ {label}
+ </Select.Option>
+ ))}
+ </Select>
+ </Form.Item>
+ </React.Fragment>
+ )
+};
const Component: React.FC<Props> = ({ readonly, form }) => {
const { formatMessage } = useIntl()
@@ -86,9 +61,10 @@ const Component: React.FC<Props> = ({ readonly, form }) => {
label={formatMessage({ id: 'page.upstream.step.type' })}
name="type"
rules={[{ required: true }]}
+ initialValue="roundrobin"
>
<Select disabled={readonly}>
- {Object.entries(Type).map(([label, value]) => {
+ {Object.entries(AlgorithmEnum).map(([label, value]) => {
return (
<Select.Option value={value} key={value}>
{formatMessage({ id: `page.upstream.type.${label}` })}
diff --git a/web/src/components/Upstream/components/active-check/Timeout.tsx b/web/src/components/Upstream/components/active-check/Concurrency.tsx
similarity index 72%
copy from web/src/components/Upstream/components/active-check/Timeout.tsx
copy to web/src/components/Upstream/components/active-check/Concurrency.tsx
index 4d294b7..8ef19d3 100644
--- a/web/src/components/Upstream/components/active-check/Timeout.tsx
+++ b/web/src/components/Upstream/components/active-check/Concurrency.tsx
@@ -17,23 +17,21 @@
import React from 'react'
import { Form, InputNumber } from 'antd'
import { useIntl } from 'umi'
-import TimeUnit from '../TimeUnit'
type Props = {
readonly?: boolean
}
-const ActiveCheckTimeoutComponent: React.FC<Props> = ({ readonly }) => {
+const ConcurrencyComponent: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.Item label={formatMessage({ id: 'page.upstream.step.healthyCheck.active.timeout' })} tooltip={formatMessage({ id: 'page.upstream.checks.active.timeout.description' })}>
- <Form.Item name={['checks', 'active', 'timeout']} noStyle>
+ <Form.Item label={formatMessage({ id: 'component.upstream.fields.checks.active.concurrency' })} tooltip={formatMessage({ id: "component.upstream.fields.checks.active.concurrency.tooltip" })}>
+ <Form.Item name={['checks', 'active', 'concurrency']} noStyle initialValue={10}>
<InputNumber disabled={readonly} min={0} />
</Form.Item>
- <TimeUnit />
</Form.Item>
)
}
-export default ActiveCheckTimeoutComponent
+export default ConcurrencyComponent
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx b/web/src/components/Upstream/components/active-check/Healthy/HttpStatuses.tsx
similarity index 88%
copy from web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx
copy to web/src/components/Upstream/components/active-check/Healthy/HttpStatuses.tsx
index 0cdad52..5357ef7 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx
+++ b/web/src/components/Upstream/components/active-check/Healthy/HttpStatuses.tsx
@@ -29,13 +29,14 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.List name={['checks', 'active', 'unhealthy', 'http_statuses']}>
+ <Form.List name={['checks', 'active', 'healthy', 'http_statuses']} initialValue={[200, 302]}>
{(fields, { add, remove }) => (
<>
<Form.Item
required
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.passive.http_statuses' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.http_statuses' })}
style={{ marginBottom: 0 }}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.http_statuses.tooltip' })}
>
{fields.map((field, index) => (
<Row style={{ marginBottom: 10 }} key={index}>
diff --git a/web/src/components/Upstream/components/active-check/Healthy/Interval.tsx b/web/src/components/Upstream/components/active-check/Healthy/Interval.tsx
index 47ca56e..0a4e3c8 100644
--- a/web/src/components/Upstream/components/active-check/Healthy/Interval.tsx
+++ b/web/src/components/Upstream/components/active-check/Healthy/Interval.tsx
@@ -27,9 +27,9 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.activeInterval' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.interval' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.active.healthy.interval.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.interval.tooltip' })}
>
<Form.Item
noStyle
@@ -43,6 +43,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
}),
},
]}
+ initialValue={1}
>
<InputNumber disabled={readonly} min={1} />
</Form.Item>
diff --git a/web/src/components/Upstream/components/active-check/Healthy/Successes.tsx b/web/src/components/Upstream/components/active-check/Healthy/Successes.tsx
index 84fbccf..a096cdf 100644
--- a/web/src/components/Upstream/components/active-check/Healthy/Successes.tsx
+++ b/web/src/components/Upstream/components/active-check/Healthy/Successes.tsx
@@ -27,9 +27,9 @@ const Component: React.FC<Props> = ({ readonly }) => {
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.successes' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.successes' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.active.healthy.successes.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.healthy.successes.tooltip' })}
>
<Form.Item
name={['checks', 'active', 'healthy', 'successes']}
@@ -37,9 +37,10 @@ const Component: React.FC<Props> = ({ readonly }) => {
rules={[
{
required: true,
- message: formatMessage({ id: 'page.upstream.step.input.healthyCheck.successes' }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.active.healthy.successes.required' }),
},
]}
+ initialValue={2}
>
<InputNumber disabled={readonly} min={1} max={254} />
</Form.Item>
diff --git a/web/src/components/Upstream/components/active-check/Healthy/index.ts b/web/src/components/Upstream/components/active-check/Healthy/index.ts
index cef27c1..f803f58 100644
--- a/web/src/components/Upstream/components/active-check/Healthy/index.ts
+++ b/web/src/components/Upstream/components/active-check/Healthy/index.ts
@@ -16,8 +16,10 @@
*/
import Interval from './Interval'
import Successes from './Successes'
+import HttpStatuses from './HttpStatuses'
export default {
Interval,
- Successes
+ Successes,
+ HttpStatuses
}
diff --git a/web/src/components/Upstream/components/active-check/Host.tsx b/web/src/components/Upstream/components/active-check/Host.tsx
index 871000b..f21a76b 100644
--- a/web/src/components/Upstream/components/active-check/Host.tsx
+++ b/web/src/components/Upstream/components/active-check/Host.tsx
@@ -26,30 +26,30 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.activeHost' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.host' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.active.host.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.host.tooltip' })}
+ style={{ marginBottom: 0 }}
>
<Form.Item
- style={{ marginBottom: 0 }}
name={['checks', 'active', 'host']}
rules={[
{
required: true,
- message: formatMessage({ id: 'page.upstream.step.input.healthyCheck.activeHost' }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.active.host.required' }),
},
{
pattern: new RegExp(
- /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/,
+ /^\\*?[0-9a-zA-Z-._]+$/,
'g',
),
- message: formatMessage({ id: 'page.upstream.step.domain.name.or.ip.rule' }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.active.host.scope' }),
},
]}
>
<Input
placeholder={formatMessage({
- id: 'page.upstream.step.input.healthyCheck.activeHost',
+ id: 'component.upstream.fields.checks.active.host.required',
})}
disabled={readonly}
/>
diff --git a/web/src/components/Upstream/components/active-check/HttpPath.tsx b/web/src/components/Upstream/components/active-check/HttpPath.tsx
index 4914a49..db5c2b6 100644
--- a/web/src/components/Upstream/components/active-check/HttpPath.tsx
+++ b/web/src/components/Upstream/components/active-check/HttpPath.tsx
@@ -27,10 +27,10 @@ const Component: React.FC<Props> = ({ readonly }) => {
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.active.http_path' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.http_path' })}
required
tooltip={formatMessage({
- id: 'page.upstream.step.input.healthyCheck.active.http_path',
+ id: 'component.upstream.fields.checks.active.http_path.tooltip',
})}
>
<Form.Item
@@ -39,13 +39,14 @@ const Component: React.FC<Props> = ({ readonly }) => {
rules={[
{
required: true,
- message: formatMessage({ id: 'page.upstream.checks.active.http_path.placeholder' }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.active.http_path.placeholder' }),
},
]}
+ initialValue="/"
>
<Input
disabled={readonly}
- placeholder={formatMessage({ id: 'page.upstream.checks.active.http_path.placeholder' })}
+ placeholder={formatMessage({ id: 'component.upstream.fields.checks.active.http_path.placeholder' })}
/>
</Form.Item>
</Form.Item>
diff --git a/web/src/components/Upstream/components/Retries.tsx b/web/src/components/Upstream/components/active-check/HttpsVerifyCertificate.tsx
similarity index 66%
copy from web/src/components/Upstream/components/Retries.tsx
copy to web/src/components/Upstream/components/active-check/HttpsVerifyCertificate.tsx
index a77ecef..901c509 100644
--- a/web/src/components/Upstream/components/Retries.tsx
+++ b/web/src/components/Upstream/components/active-check/HttpsVerifyCertificate.tsx
@@ -15,25 +15,26 @@
* limitations under the License.
*/
import React from 'react'
-import { Form, InputNumber } from 'antd'
+import { Form, Switch } from 'antd'
import { useIntl } from 'umi'
type Props = {
readonly?: boolean
}
-const Component: React.FC<Props> = ({ readonly }) => {
+const HttpsVerifyCertificateComponent: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.retries' })}
- name="retries"
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.https_verify_certificate' })}
+ name="https_verify_certificate"
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.https_verify_certificate.tooltip' })}
+ initialValue={true}
+ valuePropName="checked"
>
- <InputNumber
- disabled={readonly}
- />
+ <Switch disabled={readonly} />
</Form.Item>
)
}
-export default Component
+export default HttpsVerifyCertificateComponent
diff --git a/web/src/components/Upstream/components/active-check/Port.tsx b/web/src/components/Upstream/components/active-check/Port.tsx
index 3d04e07..8ca857b 100644
--- a/web/src/components/Upstream/components/active-check/Port.tsx
+++ b/web/src/components/Upstream/components/active-check/Port.tsx
@@ -25,11 +25,11 @@ type Props = {
const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.Item label={formatMessage({ id: 'page.upstream.step.healthyCheck.activePort' })}>
- <Form.Item name={['checks', 'active', 'port']} noStyle>
+ <Form.Item label={formatMessage({ id: 'component.upstream.fields.checks.active.port' })} required>
+ <Form.Item name={['checks', 'active', 'port']} noStyle initialValue={80} rules={[{ required: true, message: formatMessage({ id: "component.upstream.fields.checks.active.port.required" }) }]}>
<InputNumber
placeholder={formatMessage({
- id: 'page.upstream.step.input.healthyCheck.activePort',
+ id: 'component.upstream.fields.checks.active.port',
})}
disabled={readonly}
min={1}
diff --git a/web/src/components/Upstream/components/active-check/ReqHeaders.tsx b/web/src/components/Upstream/components/active-check/ReqHeaders.tsx
index 25fb8d6..9280ed4 100644
--- a/web/src/components/Upstream/components/active-check/ReqHeaders.tsx
+++ b/web/src/components/Upstream/components/active-check/ReqHeaders.tsx
@@ -34,8 +34,9 @@ const Component: React.FC<Props> = ({ readonly }) => {
<>
<Form.Item
label={
- formatMessage({ id: 'page.upstream.step.healthyCheck.active.req_headers' })
+ formatMessage({ id: 'component.upstream.fields.checks.active.req_headers' })
}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.req_headers.tooltip' })}
style={{ marginBottom: 0 }}
>
{fields.map((field, index) => (
@@ -51,7 +52,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
</Form.Item>
</Col>
<Col style={{ ...removeBtnStyle, marginLeft: 0 }}>
- {!readonly && fields.length > 1 && (
+ {!readonly && fields.length > 0 && (
<MinusCircleOutlined
onClick={() => {
remove(field.name);
diff --git a/web/src/components/Upstream/components/active-check/Timeout.tsx b/web/src/components/Upstream/components/active-check/Timeout.tsx
index 4d294b7..f2b6bdc 100644
--- a/web/src/components/Upstream/components/active-check/Timeout.tsx
+++ b/web/src/components/Upstream/components/active-check/Timeout.tsx
@@ -28,7 +28,7 @@ const ActiveCheckTimeoutComponent: React.FC<Props> = ({ readonly }) => {
return (
<Form.Item label={formatMessage({ id: 'page.upstream.step.healthyCheck.active.timeout' })} tooltip={formatMessage({ id: 'page.upstream.checks.active.timeout.description' })}>
- <Form.Item name={['checks', 'active', 'timeout']} noStyle>
+ <Form.Item name={['checks', 'active', 'timeout']} noStyle initialValue={1}>
<InputNumber disabled={readonly} min={0} />
</Form.Item>
<TimeUnit />
diff --git a/web/src/components/Upstream/components/active-check/Type.tsx b/web/src/components/Upstream/components/active-check/Type.tsx
index e8b95c6..067bf96 100644
--- a/web/src/components/Upstream/components/active-check/Type.tsx
+++ b/web/src/components/Upstream/components/active-check/Type.tsx
@@ -15,7 +15,8 @@
* limitations under the License.
*/
import React from 'react'
-import { Form, Select } from 'antd'
+import { Form, Select, Row, Col } from 'antd'
+import { useIntl } from 'umi'
type Props = {
readonly?: boolean
@@ -35,21 +36,32 @@ const options = [
]
const ActiveCheckTypeComponent: React.FC<Props> = ({ readonly }) => {
+ const { formatMessage } = useIntl()
+
return (
<Form.Item
- label="Type"
- name={['checks', 'active', 'type']}
- rules={[{ required: true }]}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.type' })}
+ style={{ marginBottom: 0 }}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.type.tooltip' })}
>
- <Select disabled={readonly}>
- {options.map(item => {
- return (
- <Select.Option value={item.value} key={item.value}>
- {item.label}
- </Select.Option>
- );
- })}
- </Select>
+ <Row>
+ <Col span={5}>
+ <Form.Item
+ name={['checks', 'active', 'type']}
+ initialValue="http"
+ >
+ <Select disabled={readonly}>
+ {options.map(item => {
+ return (
+ <Select.Option value={item.value} key={item.value}>
+ {item.label}
+ </Select.Option>
+ );
+ })}
+ </Select>
+ </Form.Item>
+ </Col>
+ </Row>
</Form.Item>
)
}
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/HttpFailures.tsx b/web/src/components/Upstream/components/active-check/Unhealthy/HttpFailures.tsx
index dbd4118..953e785 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/HttpFailures.tsx
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/HttpFailures.tsx
@@ -27,9 +27,9 @@ const Component: React.FC<Props> = ({ readonly }) => {
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.http_failures' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.http_failures' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.active.unhealthy.http_failures.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.http_failures.tooltip' })}
>
<Form.Item
name={['checks', 'active', 'unhealthy', 'http_failures']}
@@ -38,10 +38,11 @@ const Component: React.FC<Props> = ({ readonly }) => {
{
required: true,
message: formatMessage({
- id: 'page.upstream.step.input.healthyCheck.http_failures',
+ id: 'component.upstream.fields.checks.active.unhealthy.http_failures.required',
}),
},
]}
+ initialValue={5}
>
<InputNumber disabled={readonly} min={1} max={254} />
</Form.Item>
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx b/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx
index 0cdad52..3e5830c 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/HttpStatuses.tsx
@@ -29,7 +29,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.List name={['checks', 'active', 'unhealthy', 'http_statuses']}>
+ <Form.List name={['checks', 'active', 'unhealthy', 'http_statuses']} initialValue={[429, 404, 500, 501, 502, 503, 504, 505]}>
{(fields, { add, remove }) => (
<>
<Form.Item
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/Interval.tsx b/web/src/components/Upstream/components/active-check/Unhealthy/Interval.tsx
index 8052808..5b41aa0 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/Interval.tsx
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/Interval.tsx
@@ -28,13 +28,14 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.activeInterval' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.interval' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.active.unhealthy.interval.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.interval.tooltip' })}
>
<Form.Item
name={['checks', 'active', 'unhealthy', 'interval']}
noStyle
+ initialValue={1}
rules={[
{
required: true,
diff --git a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx b/web/src/components/Upstream/components/active-check/Unhealthy/TCPFailures.tsx
similarity index 71%
copy from web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx
copy to web/src/components/Upstream/components/active-check/Unhealthy/TCPFailures.tsx
index 3ba6154..20011b7 100644
--- a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/TCPFailures.tsx
@@ -14,34 +14,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react'
import { Form, InputNumber } from 'antd'
+import React from 'react'
import { useIntl } from 'umi'
type Props = {
readonly?: boolean
}
-const Component: React.FC<Props> = ({ readonly }) => {
+const TCPFailures: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.http_failures' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.tcp_failures' })}
required
- tooltip={formatMessage({ id: 'page.upstream.checks.passive.unhealthy.http_failures.description' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.tcp_failures.tooltip' })}
>
<Form.Item
- name={['checks', 'passive', 'unhealthy', 'http_failures']}
+ name={['checks', 'active', 'unhealthy', 'tcp_Failures']}
noStyle
rules={[
{
required: true,
- message: formatMessage({
- id: 'page.upstream.step.input.healthyCheck.http_failures',
- }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.tcp_failures.required' }),
},
]}
+ initialValue={2}
>
<InputNumber disabled={readonly} min={1} max={254} />
</Form.Item>
@@ -49,4 +48,4 @@ const Component: React.FC<Props> = ({ readonly }) => {
)
}
-export default Component
+export default TCPFailures
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx b/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx
index 2f5af5f..c1faa1e 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx
@@ -16,23 +16,29 @@
*/
import React from 'react'
import { Form, InputNumber } from 'antd'
+import { useIntl } from 'umi'
type Props = {
readonly?: boolean
}
-const Component: React.FC<Props> = ({ readonly }) => (
- <Form.Item
- label="Timeouts"
- required
- >
+const Component: React.FC<Props> = ({ readonly }) => {
+ const { formatMessage } = useIntl()
+ return (
<Form.Item
- name={['checks', 'active', 'unhealthy', 'timeouts']}
- noStyle
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.timeouts' })}
+ required
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.timeouts.tooltip' })}
>
- <InputNumber disabled={readonly} min={1} max={254} />
+ <Form.Item
+ name={['checks', 'active', 'unhealthy', 'timeouts']}
+ noStyle
+ initialValue={3}
+ >
+ <InputNumber disabled={readonly} min={1} max={254} />
+ </Form.Item>
</Form.Item>
- </Form.Item>
-)
+ )
+}
export default Component
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/index.ts b/web/src/components/Upstream/components/active-check/Unhealthy/index.ts
index bb9b869..6dde012 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/index.ts
+++ b/web/src/components/Upstream/components/active-check/Unhealthy/index.ts
@@ -18,10 +18,12 @@ import Timeouts from './Timeouts'
import Interval from './Interval'
import HttpStatuses from './HttpStatuses'
import HttpFailures from './HttpFailures'
+import TCPFailures from './TCPFailures'
export default {
Timeouts,
Interval,
HttpStatuses,
- HttpFailures
+ HttpFailures,
+ TCPFailures
}
diff --git a/web/src/components/Upstream/components/active-check/index.ts b/web/src/components/Upstream/components/active-check/index.ts
index efc3046..0a99290 100644
--- a/web/src/components/Upstream/components/active-check/index.ts
+++ b/web/src/components/Upstream/components/active-check/index.ts
@@ -23,6 +23,8 @@ import ReqHeaders from './ReqHeaders'
import Host from './Host'
import Port from './Port'
import HttpPath from './HttpPath'
+import Concurrency from './Concurrency'
+import HttpsVerifyCertificate from './HttpsVerifyCertificate'
export default {
Unhealthy,
@@ -32,5 +34,7 @@ export default {
ReqHeaders,
Host,
Port,
- HttpPath
+ HttpPath,
+ Concurrency,
+ HttpsVerifyCertificate
}
diff --git a/web/src/components/Upstream/components/passive-check/Healthy/HttpStatuses.tsx b/web/src/components/Upstream/components/passive-check/Healthy/HttpStatuses.tsx
index f1b06d2..8ac8ecb 100644
--- a/web/src/components/Upstream/components/passive-check/Healthy/HttpStatuses.tsx
+++ b/web/src/components/Upstream/components/passive-check/Healthy/HttpStatuses.tsx
@@ -29,7 +29,9 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.List name={['checks', 'passive', 'healthy', 'http_statuses']}>
+ <Form.List name={['checks', 'passive', 'healthy', 'http_statuses']} initialValue={[200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 226, 300, 301, 302, 303, 304, 305,
+ 306, 307, 308]}>
{(fields, { add, remove }) => (
<>
<Form.Item
diff --git a/web/src/components/Upstream/components/passive-check/Healthy/Successes.tsx b/web/src/components/Upstream/components/passive-check/Healthy/Successes.tsx
index 2ee3590..a85a69f 100644
--- a/web/src/components/Upstream/components/passive-check/Healthy/Successes.tsx
+++ b/web/src/components/Upstream/components/passive-check/Healthy/Successes.tsx
@@ -26,17 +26,18 @@ const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.successes' })}
- tooltip={formatMessage({ id: 'page.upstream.checks.passive.healthy.successes.description' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.passive.healthy.successes' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.passive.healthy.successes.tooltip' })}
required
>
<Form.Item
name={['checks', 'passive', 'healthy', 'successes']}
noStyle
+ initialValue={5}
rules={[
{
required: true,
- message: formatMessage({ id: 'page.upstream.step.input.healthyCheck.successes' }),
+ message: formatMessage({ id: 'component.upstream.fields.checks.passive.healthy.successes.required' }),
},
]}
>
diff --git a/web/src/components/Upstream/components/passive-check/Type.tsx b/web/src/components/Upstream/components/passive-check/Type.tsx
index d3401ee..f43f445 100644
--- a/web/src/components/Upstream/components/passive-check/Type.tsx
+++ b/web/src/components/Upstream/components/passive-check/Type.tsx
@@ -15,43 +15,55 @@
* limitations under the License.
*/
import React from 'react'
-import { Form, Select } from 'antd'
+import { Form, Select, Row, Col } from 'antd'
+import { useIntl } from 'umi'
type Props = {
readonly?: boolean
}
-const PassiveCheckTypeComponent: React.FC<Props> = ({ readonly }) => {
- const options = [
- {
- label: "HTTP",
- value: "http"
- }, {
- label: "HTTPs",
- value: "https"
- }, {
- label: "TCP",
- value: "tcp"
- }
- ]
+const options = [
+ {
+ label: "HTTP",
+ value: "http"
+ }, {
+ label: "HTTPs",
+ value: "https"
+ }, {
+ label: "TCP",
+ value: "tcp"
+ }
+]
+
+const ActiveCheckTypeComponent: React.FC<Props> = ({ readonly }) => {
+ const { formatMessage } = useIntl()
return (
<Form.Item
- label="Type"
- name={['checks', 'passive', 'type']}
- rules={[{ required: true }]}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.type' })}
+ style={{ marginBottom: 0 }}
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.active.type.tooltip' })}
>
- <Select disabled={readonly}>
- {options.map(item => {
- return (
- <Select.Option value={item.value} key={item.value}>
- {item.label}
- </Select.Option>
- );
- })}
- </Select>
+ <Row>
+ <Col span={5}>
+ <Form.Item
+ name={['checks', 'passive', 'type']}
+ initialValue="http"
+ >
+ <Select disabled={readonly}>
+ {options.map(item => {
+ return (
+ <Select.Option value={item.value} key={item.value}>
+ {item.label}
+ </Select.Option>
+ );
+ })}
+ </Select>
+ </Form.Item>
+ </Col>
+ </Row>
</Form.Item>
)
}
-export default PassiveCheckTypeComponent
+export default ActiveCheckTypeComponent
diff --git a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx b/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx
index 3ba6154..be282b7 100644
--- a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx
+++ b/web/src/components/Upstream/components/passive-check/Unhealthy/HttpFailures.tsx
@@ -27,18 +27,19 @@ const Component: React.FC<Props> = ({ readonly }) => {
return (
<Form.Item
- label={formatMessage({ id: 'page.upstream.step.healthyCheck.http_failures' })}
+ label={formatMessage({ id: 'component.upstream.fields.checks.active.unhealthy.http_failures' })}
required
tooltip={formatMessage({ id: 'page.upstream.checks.passive.unhealthy.http_failures.description' })}
>
<Form.Item
name={['checks', 'passive', 'unhealthy', 'http_failures']}
noStyle
+ initialValue={2}
rules={[
{
required: true,
message: formatMessage({
- id: 'page.upstream.step.input.healthyCheck.http_failures',
+ id: 'component.upstream.fields.checks.active.unhealthy.http_failures.required',
}),
},
]}
diff --git a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpStatuses.tsx b/web/src/components/Upstream/components/passive-check/Unhealthy/HttpStatuses.tsx
index ba9ba75..2127c05 100644
--- a/web/src/components/Upstream/components/passive-check/Unhealthy/HttpStatuses.tsx
+++ b/web/src/components/Upstream/components/passive-check/Unhealthy/HttpStatuses.tsx
@@ -28,7 +28,7 @@ type Props = {
const Component: React.FC<Props> = ({ readonly }) => {
const { formatMessage } = useIntl()
return (
- <Form.List name={['checks', 'passive', 'unhealthy', 'http_statuses']}>
+ <Form.List name={['checks', 'passive', 'unhealthy', 'http_statuses']} initialValue={[429, 500, 503]}>
{(fields, { add, remove }) => (
<>
<Form.Item
diff --git a/web/src/components/Upstream/components/passive-check/Unhealthy/TcpFailures.tsx b/web/src/components/Upstream/components/passive-check/Unhealthy/TcpFailures.tsx
index 175d22f..7828cb2 100644
--- a/web/src/components/Upstream/components/passive-check/Unhealthy/TcpFailures.tsx
+++ b/web/src/components/Upstream/components/passive-check/Unhealthy/TcpFailures.tsx
@@ -33,6 +33,7 @@ const Component: React.FC<Props> = ({ readonly }) => {
<Form.Item
name={['checks', 'passive', 'unhealthy', 'tcp_failures']}
noStyle
+ initialValue={2}
rules={[
{
required: true,
diff --git a/web/src/components/Upstream/components/passive-check/Unhealthy/Timeouts.tsx b/web/src/components/Upstream/components/passive-check/Unhealthy/Timeouts.tsx
index 91b7b4f..6eff53a 100644
--- a/web/src/components/Upstream/components/passive-check/Unhealthy/Timeouts.tsx
+++ b/web/src/components/Upstream/components/passive-check/Unhealthy/Timeouts.tsx
@@ -16,23 +16,29 @@
*/
import React from 'react'
import { Form, InputNumber } from 'antd'
+import { useIntl } from 'umi'
type Props = {
readonly?: boolean
}
-const Component: React.FC<Props> = ({ readonly }) => (
- <Form.Item
- label="Timeouts"
- required
- >
+const Component: React.FC<Props> = ({ readonly }) => {
+ const { formatMessage } = useIntl()
+ return (
<Form.Item
- name={['checks', 'passive', 'unhealthy', 'timeouts']}
- noStyle
+ label={formatMessage({ id: 'component.upstream.fields.checks.passive.unhealthy.timeouts' })}
+ required
+ tooltip={formatMessage({ id: 'component.upstream.fields.checks.passive.unhealthy.timeouts.tooltip' })}
>
- <InputNumber disabled={readonly} min={1} max={254} />
+ <Form.Item
+ name={['checks', 'passive', 'unhealthy', 'timeouts']}
+ noStyle
+ initialValue={7}
+ >
+ <InputNumber disabled={readonly} min={1} max={254} />
+ </Form.Item>
</Form.Item>
- </Form.Item>
-)
+ )
+}
export default Component
diff --git a/web/src/components/Upstream/constant.ts b/web/src/components/Upstream/constant.ts
index d4f243b..66ddc45 100644
--- a/web/src/components/Upstream/constant.ts
+++ b/web/src/components/Upstream/constant.ts
@@ -14,77 +14,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-export const DEFAULT_UPSTREAM = {
- upstream_id: '',
- // NOTE: the following fields are the default configurations
- // https://github.com/apache/apisix/blob/master/apisix/schema_def.lua#L325
- nodes: [
- {
- host: '',
- port: 80,
- weight: 1
- }
- ],
- retries: 0,
- timeout: {
- connect: 6,
- send: 6,
- read: 6,
- },
- type: 'roundrobin',
- checks: {},
- scheme: "http",
- pass_host: "pass",
- name: "",
- desc: ""
-};
-
-// NOTE: checks.active
-// https://github.com/apache/apisix/blob/master/apisix/schema_def.lua#L40
-export const DEFAULT_HEALTH_CHECK_ACTIVE = {
- type: "http",
- timeout: 1,
- concurrency: 10,
- host: "",
- port: 80,
- http_path: "",
- https_verify_certificate: true,
- healthy: {
- interval: 1,
- http_statuses: [200, 302],
- successes: 2
- },
- unhealthy: {
- interval: 1,
- http_statuses: [429, 404, 500, 501, 502, 503, 504, 505],
- http_failures: 5,
- tcp_failures: 2,
- timeouts: 3
- },
- req_headers: []
-}
-
-// NOTE: checks.passive
-export const DEFAULT_HEALTH_CHECK_PASSIVE = {
- type: "http",
- healthy: {
- http_statuses: [
- 200, 201, 202, 203, 204, 205, 206, 207,
- 208, 226, 300, 301, 302, 303, 304, 305,
- 306, 307, 308
- ],
- successes: 5
- },
- unhealthy: {
- http_statuses: [429, 500, 503],
- tcp_failures: 2,
- timeouts: 7,
- http_failures: 5
- }
-}
export const removeBtnStyle = {
marginLeft: 20,
display: 'flex',
alignItems: 'center',
};
+
+export enum AlgorithmEnum {
+ chash = "chash",
+ roundrobin = "roundrobin",
+ ewma = "ewma",
+ least_conn = "least_conn"
+}
+
+export enum HashOnEnum {
+ vars = 'vars',
+ header = 'header',
+ cookie = 'cookie',
+ consumer = 'consumer',
+ vars_combinations = 'vars_combinations'
+}
+
+export enum CommonHashKeyEnum {
+ remote_addr = 'remote_addr',
+ host = 'host',
+ uri = 'uri',
+ server_name = 'server_name',
+ server_addr = 'server_addr',
+ request_uri = 'request_uri',
+ query_string = 'query_string',
+ remote_port = 'remote_port',
+ hostname = 'hostname',
+ arg_id = 'arg_id',
+}
+
+export enum SchemeEnum {
+ grpc = "grpc",
+ grpcs = "grpcs",
+ http = "http",
+ https = "https"
+}
+
+export enum PassHostEnum {
+ pass = "pass",
+ node = "node",
+ rewrite = "rewrite"
+}
diff --git a/web/src/components/Upstream/locales/en-US.ts b/web/src/components/Upstream/locales/en-US.ts
new file mode 100644
index 0000000..585fb66
--- /dev/null
+++ b/web/src/components/Upstream/locales/en-US.ts
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default {
+ 'component.upstream.fields.tls.client_key': 'Client Key',
+ 'component.upstream.fields.tls.client_cert': 'Client Cert',
+
+ 'component.upstream.fields.discovery_type': 'Discovery Type',
+ 'component.upstream.fields.discovery_type.tooltip': 'Discovery Type',
+ 'component.upstream.fields.discovery_type.placeholder': 'Please enter the discovery type',
+
+ 'component.upstream.fields.service_name': 'Service Name',
+ 'component.upstream.fields.service_name.tooltip': 'Service Name',
+ 'component.upstream.fields.service_name.placeholder': 'Please enter the service name',
+
+ 'component.upstream.fields.tls': 'TLS',
+ 'component.upstream.fields.tls.tooltip': 'TLS Certificate',
+
+ 'component.upstream.fields.hash_on': 'Hash on',
+ 'component.upstream.fields.hash_on.tooltip': 'What to use as hashing input',
+
+ 'component.upstream.fields.key': 'Key',
+ 'component.upstream.fields.key.tooltip': 'Key as hashing input',
+
+ 'component.upstream.fields.retries': 'Retries',
+ 'component.upstream.fields.retries.tooltip': 'The retry mechanism sends the request to the next upstream node. A value of 0 disables the retry mechanism and leaves the table empty to use the number of available backend nodes.',
+
+ 'component.upstream.fields.checks.active.type': 'Type',
+ 'component.upstream.fields.checks.active.type.tooltip': 'Whether to perform active health checks using HTTP or HTTPS, or just attempt a TCP connection.',
+
+ 'component.upstream.fields.checks.active.concurrency': 'Concurrency',
+ 'component.upstream.fields.checks.active.concurrency.tooltip': 'Number of targets to check concurrently in active health checks.',
+
+ 'component.upstream.fields.checks.active.host': 'Host',
+ 'component.upstream.fields.checks.active.host.required': 'Please enter the hostname',
+ 'component.upstream.fields.checks.active.host.tooltip': 'The hostname of the HTTP request used to perform the active health check',
+ 'component.upstream.fields.checks.active.host.scope': 'Only letters, numbers and . are supported',
+
+ 'component.upstream.fields.checks.active.port': 'Port',
+ 'component.upstream.fields.checks.active.port.required': 'Please enter the port',
+
+ 'component.upstream.fields.checks.active.http_path': 'HTTP Path',
+ 'component.upstream.fields.checks.active.http_path.tooltip': 'The path that should be used when issuing the HTTP GET request to the target. The default value is /.',
+
+ 'component.upstream.fields.checks.active.https_verify_certificate': 'Verify HTTPs Certificate',
+ 'component.upstream.fields.checks.active.https_verify_certificate.tooltip': 'Whether to check the validity of the SSL certificate of the remote host when performing active health checks using HTTPS.',
+
+ 'component.upstream.fields.checks.active.req_headers': 'Request Headers',
+ 'component.upstream.fields.checks.active.req_headers.tooltip': 'Additional request headers, example: User-Agent: curl/7.29.0',
+
+ 'component.upstream.fields.checks.active.healthy.interval': 'Interval',
+ 'component.upstream.fields.checks.active.healthy.interval.tooltip': 'Interval between checks for healthy targets (in seconds)',
+
+ 'component.upstream.fields.checks.active.healthy.successes': 'Successes',
+ 'component.upstream.fields.checks.active.healthy.successes.tooltip': 'Number of successes to consider a target healthy',
+ 'component.upstream.fields.checks.active.healthy.successes.required': 'Please enter successes number',
+
+ 'component.upstream.fields.checks.active.healthy.http_statuses': 'HTTP Statuses',
+ 'component.upstream.fields.checks.active.healthy.http_statuses.tooltip': 'An array of HTTP statuses to consider a success, indicating healthiness, when returned by a probe in active health checks.',
+
+ 'component.upstream.fields.checks.active.unhealthy.timeouts': 'Timeouts',
+ 'component.upstream.fields.checks.active.unhealthy.timeouts.tooltip': 'Number of timeouts in active probes to consider a target unhealthy.',
+
+ 'component.upstream.fields.checks.active.unhealthy.http_failures': 'HTTP Failures',
+ 'component.upstream.fields.checks.active.unhealthy.http_failures.tooltip': 'Number of HTTP failures to consider a target unhealthy',
+ 'component.upstream.fields.checks.active.unhealthy.http_failures.required': 'Please enter the HTTP failures',
+
+ 'component.upstream.fields.checks.active.unhealthy.interval': 'Interval',
+ 'component.upstream.fields.checks.active.unhealthy.interval.tooltip': 'Interval between active health checks for unhealthy targets (in seconds). A value of zero indicates that active probes for healthy targets should not be performed.',
+ 'component.upstream.fields.checks.active.unhealthy.required': 'Please enter the unhelthy interval',
+
+ 'component.upstream.fields.checks.passive.healthy.successes': 'Successes',
+ 'component.upstream.fields.checks.passive.healthy.successes.tooltip': 'Number of successes to consider a target healthy',
+ 'component.upstream.fields.checks.passive.healthy.successes.required': 'Please enter the successes number',
+
+ 'component.upstream.fields.checks.passive.unhealthy.timeouts': 'Timeouts',
+ 'component.upstream.fields.checks.passive.unhealthy.timeouts.tooltip': 'Number of timeouts in proxied traffic to consider a target unhealthy, as observed by passive health checks.',
+}
diff --git a/web/src/components/Upstream/locales/zh-CN.ts b/web/src/components/Upstream/locales/zh-CN.ts
new file mode 100644
index 0000000..62925e6
--- /dev/null
+++ b/web/src/components/Upstream/locales/zh-CN.ts
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export default {
+ 'component.upstream.fields.tls.client_key': '客户端私钥',
+ 'component.upstream.fields.tls.client_cert': '客户端证书',
+
+ 'component.upstream.fields.discovery_type': '服务发现类型',
+ 'component.upstream.fields.discovery_type.tooltip': '服务发现类型',
+ 'component.upstream.fields.discovery_type.placeholder': '请输入服务发现类型',
+
+ 'component.upstream.fields.service_name': '服务名称',
+ 'component.upstream.fields.service_name.tooltip': '服务名称',
+ 'component.upstream.fields.service_name.placeholder': '请输入服务名称',
+
+ 'component.upstream.fields.tls': 'TLS',
+ 'component.upstream.fields.tls.tooltip': 'TLS 证书',
+
+ 'component.upstream.fields.hash_on': '哈希位置',
+ 'component.upstream.fields.hash_on.tooltip': '哈希的输入的位置(Hash On)',
+
+ 'component.upstream.fields.key': 'Key',
+ 'component.upstream.fields.key.tooltip': '哈希键(Hash Key)',
+
+ 'component.upstream.fields.retries': '重试次数',
+ 'component.upstream.fields.retries.tooltip': '重试机制将请求发到下一个上游节点。值为 0 表示禁用重试机制,留空表是使用可用后端节点的数量。',
+
+ 'component.upstream.fields.checks.active.type': '类型',
+ 'component.upstream.fields.checks.active.type.tooltip': '是使用 HTTP 或 HTTPS 进行主动健康检查,还是只尝试 TCP 连接。',
+
+ 'component.upstream.fields.checks.active.concurrency': '并行数量',
+ 'component.upstream.fields.checks.active.concurrency.tooltip': '在主动健康检查中同时检查的目标数量。',
+
+ 'component.upstream.fields.checks.active.host': '主机名',
+ 'component.upstream.fields.checks.active.host.required': '请输入主机名',
+ 'component.upstream.fields.checks.active.host.tooltip': '进行主动健康检查时使用的 HTTP 请求主机名',
+ 'component.upstream.fields.checks.active.host.scope': '仅支持字母、数字和 . ',
+
+ 'component.upstream.fields.checks.active.port': '端口',
+ 'component.upstream.fields.checks.active.port.required': '请输入端口',
+
+ 'component.upstream.fields.checks.active.http_path': '请求路径',
+ 'component.upstream.fields.checks.active.http_path.tooltip': '向目标节点发出 HTTP GET 请求时应使用的路径。',
+ 'component.upstream.fields.checks.active.http_path.placeholder': '请输入 HTTP 请求路径',
+
+ 'component.upstream.fields.checks.active.https_verify_certificate': '验证证书',
+ 'component.upstream.fields.checks.active.https_verify_certificate.tooltip': '在使用 HTTPS 执行主动健康检查时,是否检查远程主机的 SSL 证书的有效性。',
+
+ 'component.upstream.fields.checks.active.req_headers': '请求头',
+ 'component.upstream.fields.checks.active.req_headers.tooltip': '额外的请求头,示例:User-Agent: curl/7.29.0',
+
+ 'component.upstream.fields.checks.active.healthy.interval': '间隔时间',
+ 'component.upstream.fields.checks.active.healthy.interval.tooltip': '对健康的上游服务目标节点进行主动健康检查的间隔时间(以秒为单位)。数值为0表示对健康节点不进行主动健康检查。',
+
+ 'component.upstream.fields.checks.active.healthy.successes': '成功次数',
+ 'component.upstream.fields.checks.active.healthy.successes.tooltip': '主动健康检查的 HTTP 成功次数,若达到此值,表示上游服务目标节点是健康的。',
+ 'component.upstream.fields.checks.active.healthy.successes.required': '请输入成功次数',
+
+ 'component.upstream.fields.checks.active.healthy.http_statuses': '状态码',
+ 'component.upstream.fields.checks.active.healthy.http_statuses.tooltip': 'HTTP 状态码列表,当探针在主动健康检查中返回时,视为健康。',
+
+ 'component.upstream.fields.checks.active.unhealthy.timeouts': '超时时间',
+ 'component.upstream.fields.checks.active.unhealthy.timeouts.tooltip': '活动探针中认为目标不健康的超时次数。',
+
+ 'component.upstream.fields.checks.active.unhealthy.interval': '间隔时间',
+ 'component.upstream.fields.checks.active.unhealthy.interval.tooltip': '对不健康目标的主动健康检查之间的间隔(以秒为单位)。数值为0表示不应该对健康目标进行主动探查。',
+ 'component.upstream.fields.checks.active.unhealthy.required': '请输入间隔时间',
+
+ 'component.upstream.fields.checks.active.unhealthy.http_failures': 'HTTP 失败次数',
+ 'component.upstream.fields.checks.active.unhealthy.http_failures.tooltip': '主动健康检查的 HTTP 失败次数,默认值为0。若达到此值,表示上游服务目标节点是不健康的。',
+ 'component.upstream.fields.checks.active.unhealthy.http_failures.required': '请输入 HTTP 失败次数',
+
+ 'component.upstream.fields.checks.active.unhealthy.tcp_failures': 'TCP 失败次数',
+ 'component.upstream.fields.checks.active.unhealthy.tcp_failures.tooltip': '主动探测中 TCP 失败次数超过该值时,认为目标不健康。',
+ 'component.upstream.fields.checks.active.unhealthy.tcp_failures.required': '请输入 TCP 失败次数',
+
+ 'component.upstream.fields.checks.passive.healthy.successes': '成功次数',
+ 'component.upstream.fields.checks.passive.healthy.successes.tooltip': '通过被动健康检查观察到的正常代理流量的成功次数。如果达到该值,上游服务目标节点将被视为健康。',
+ 'component.upstream.fields.checks.passive.healthy.successes.required': '请输入成功次数',
+
+ 'component.upstream.fields.checks.passive.unhealthy.timeouts': '超时时间',
+ 'component.upstream.fields.checks.passive.unhealthy.timeouts.tooltip': '根据被动健康检查的观察,在代理中认为目标不健康的超时次数。',
+}
diff --git a/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx b/web/src/components/Upstream/service.ts
similarity index 54%
copy from web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx
copy to web/src/components/Upstream/service.ts
index 2f5af5f..2642100 100644
--- a/web/src/components/Upstream/components/active-check/Unhealthy/Timeouts.tsx
+++ b/web/src/components/Upstream/service.ts
@@ -14,25 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react'
-import { Form, InputNumber } from 'antd'
+import cloneDeep from 'lodash/cloneDeep'
-type Props = {
- readonly?: boolean
-}
+/**
+ * Because we have some `custom` field in Upstream Form, like custom.tls/custom.checks.active etc,
+ * we need to transform data that doesn't have `custom` field to data contains `custom` field
+*/
+export const transformUpstreamDataFromRequest = (originData: UpstreamComponent.ResponseData) => {
+ const data = cloneDeep(originData)
+ data.custom = {}
+
+ if (data.checks) {
+ data.custom.checks = {}
+
+ if (data.checks.active) {
+ data.custom.checks.active = true
+ }
-const Component: React.FC<Props> = ({ readonly }) => (
- <Form.Item
- label="Timeouts"
- required
- >
- <Form.Item
- name={['checks', 'active', 'unhealthy', 'timeouts']}
- noStyle
- >
- <InputNumber disabled={readonly} min={1} max={254} />
- </Form.Item>
- </Form.Item>
-)
+ if (data.checks.passive) {
+ data.custom.checks.passive = true
+ }
+ }
-export default Component
+ if (data.tls) {
+ data.custom.tls = "enable"
+ }
+
+ return data
+}
diff --git a/web/src/components/Upstream/typings.d.ts b/web/src/components/Upstream/typings.d.ts
new file mode 100644
index 0000000..bbe22d3
--- /dev/null
+++ b/web/src/components/Upstream/typings.d.ts
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Schema: https://github.com/apache/apisix/blob/master/apisix/schema_def.lua#L335
+*/
+declare namespace UpstreamComponent {
+ type ActiveCheck = {}
+
+ type PassiveCheck = {}
+
+ type TLS = {
+ client_cert: string;
+ client_key: string
+ }
+
+ type Node = {
+ host: string;
+ port: number;
+ weight: number;
+ priority?: number;
+ }
+
+ type Timeout = {
+ connect: number;
+ send: number;
+ read: number;
+ }
+
+ type ResponseData = {
+ nodes: Node[];
+ retries?: number;
+ timeout?: Timeout;
+ tls?: TLS;
+ type?: string;
+ checks?: {
+ active?: ActiveCheck;
+ passive?: PassiveCheck;
+ }
+ hash_on?: string;
+ key?: string;
+ scheme?: string;
+ discovery_type?: string;
+ pass_host?: string;
+ upstream_host?: string;
+ name?: string;
+ desc?: string;
+ service_name?: string;
+ id?: string;
+ // NOTE: custom field
+ custom?: Record<string, any>;
+ }
+}
diff --git a/web/src/locales/en-US.ts b/web/src/locales/en-US.ts
index 19c348a..e4773a6 100644
--- a/web/src/locales/en-US.ts
+++ b/web/src/locales/en-US.ts
@@ -26,6 +26,7 @@ import other from './en-US/other'
import PluginOrchestration from '../components/PluginOrchestration/locales/en-US';
import Plugin from '../components/Plugin/locales/en-US';
import RawDataEditor from '../components/RawDataEditor/locales/en-US';
+import UpstreamComponent from '../components/Upstream/locales/en-US'
export default {
'navBar.lang': 'Languages',
@@ -43,5 +44,6 @@ export default {
...ActionBarEnUS,
...PluginOrchestration,
...Plugin,
- ...RawDataEditor
+ ...RawDataEditor,
+ ...UpstreamComponent
};
diff --git a/web/src/locales/en-US/component.ts b/web/src/locales/en-US/component.ts
index fe9e2ea..a5d6356 100644
--- a/web/src/locales/en-US/component.ts
+++ b/web/src/locales/en-US/component.ts
@@ -24,6 +24,7 @@ export default {
'component.global.format': 'Format',
'component.global.document': 'Document',
'component.global.enable': 'Enable',
+ 'component.global.disable': 'Disable',
'component.global.scope': 'Scope',
'component.global.data.editor': 'Raw Data Editor',
'component.global.delete': 'Delete',
diff --git a/web/src/locales/zh-CN.ts b/web/src/locales/zh-CN.ts
index 0c80375..4d89580 100644
--- a/web/src/locales/zh-CN.ts
+++ b/web/src/locales/zh-CN.ts
@@ -26,6 +26,7 @@ import settings from './zh-CN/setting';
import PluginOrchestration from '../components/PluginOrchestration/locales/zh-CN';
import Plugin from '../components/Plugin/locales/zh-CN';
import RawDataEditor from '../components/RawDataEditor/locales/zh-CN';
+import UpstreamComponent from '../components/Upstream/locales/zh-CN'
export default {
'navBar.lang': '语言',
@@ -43,5 +44,6 @@ export default {
...ActionBarZhCN,
...PluginOrchestration,
...Plugin,
- ...RawDataEditor
+ ...RawDataEditor,
+ ...UpstreamComponent
};
diff --git a/web/src/locales/zh-CN/component.ts b/web/src/locales/zh-CN/component.ts
index bf5ee19..df60e7f 100644
--- a/web/src/locales/zh-CN/component.ts
+++ b/web/src/locales/zh-CN/component.ts
@@ -24,6 +24,7 @@ export default {
'component.global.format': '格式化',
'component.global.document': '文档',
'component.global.enable': '启用',
+ 'component.global.disable': '禁用',
'component.global.scope': '作用域',
'component.global.data.editor': '数据编辑器',
'component.global.delete': '删除',
diff --git a/web/src/pages/Route/Create.tsx b/web/src/pages/Route/Create.tsx
index 648546f..8c478d1 100644
--- a/web/src/pages/Route/Create.tsx
+++ b/web/src/pages/Route/Create.tsx
@@ -21,7 +21,6 @@ import { history, useIntl } from 'umi';
import { isEmpty } from 'lodash';
import ActionBar from '@/components/ActionBar';
-import { DEFAULT_UPSTREAM } from '@/components/Upstream';
import { transformer as chartTransformer } from '@/components/PluginOrchestration';
import { create, fetchItem, update, checkUniqueName, checkHostWithSSL } from './service';
@@ -83,7 +82,6 @@ const Page: React.FC<Props> = (props) => {
setAdvancedMatchingRules([]);
setStep3Data(DEFAULT_STEP_3_DATA);
form1.setFieldsValue(DEFAULT_STEP_1_DATA);
- form2.setFieldsValue(DEFAULT_UPSTREAM);
setStep(1);
};
@@ -95,7 +93,7 @@ const Page: React.FC<Props> = (props) => {
}
}, []);
- const getProxyRewriteEnable =() => {
+ const getProxyRewriteEnable = () => {
return !isEmpty(transformProxyRewrite2Plugin(form1.getFieldValue('proxyRewrite')));
}
@@ -269,9 +267,8 @@ const Page: React.FC<Props> = (props) => {
return (
<>
<PageHeaderWrapper
- title={`${
- formatMessage({ id: `component.global.${props.route.path.split('/').slice(-1)[0]}`})
- } ${formatMessage({ id: 'menu.routes' })}`}
+ title={`${formatMessage({ id: `component.global.${props.route.path.split('/').slice(-1)[0]}` })
+ } ${formatMessage({ id: 'menu.routes' })}`}
>
<Card bordered={false}>
<Steps current={step - 1} className={styles.steps}>
diff --git a/web/src/pages/Service/Create.tsx b/web/src/pages/Service/Create.tsx
index cb3d667..4d1dbc2 100644
--- a/web/src/pages/Service/Create.tsx
+++ b/web/src/pages/Service/Create.tsx
@@ -22,7 +22,6 @@ import { omit } from 'lodash';
import ActionBar from '@/components/ActionBar';
import PluginPage from '@/components/Plugin';
-import { DEFAULT_UPSTREAM } from '@/components/Upstream';
import Preview from './components/Preview';
import Step1 from './components/Step1';
import { create, update, fetchItem } from './service';
@@ -46,9 +45,6 @@ const Page: React.FC = (props) => {
const [step, setStep] = useState(1);
useEffect(() => {
- // init upstream default value
- upstreamForm.setFieldsValue(DEFAULT_UPSTREAM);
-
const { serviceId } = (props as any).match.params;
if (serviceId) {
fetchItem(serviceId).then(({ data }) => {
@@ -82,8 +78,8 @@ const Page: React.FC = (props) => {
.then(() => {
notification.success({
message: `${serviceId
- ? formatMessage({ id: 'component.global.edit' })
- : formatMessage({ id: 'component.global.create' })
+ ? formatMessage({ id: 'component.global.edit' })
+ : formatMessage({ id: 'component.global.create' })
} ${formatMessage({ id: 'menu.service' })} ${formatMessage({
id: 'component.status.success',
})}`,
diff --git a/web/src/pages/Upstream/Create.tsx b/web/src/pages/Upstream/Create.tsx
index 0e068c7..993e20a 100644
--- a/web/src/pages/Upstream/Create.tsx
+++ b/web/src/pages/Upstream/Create.tsx
@@ -21,6 +21,7 @@ import { history, useIntl } from 'umi';
import { QuestionCircleOutlined } from '@ant-design/icons';
import ActionBar from '@/components/ActionBar';
+import { transformUpstreamDataFromRequest } from '@/components/Upstream/service';
import Step1 from './components/Step1';
import { fetchOne, create, update } from './service';
@@ -35,8 +36,8 @@ const Page: React.FC = (props) => {
const { id } = (props as any).match.params;
if (id) {
- fetchOne(id).then((data) => {
- form1.setFieldsValue(data.data);
+ fetchOne(id).then(({ data }) => {
+ form1.setFieldsValue(transformUpstreamDataFromRequest(data));
});
}
}, []);
diff --git a/web/src/pages/Upstream/components/Step1.tsx b/web/src/pages/Upstream/components/Step1.tsx
index 182ffbc..40f3c31 100644
--- a/web/src/pages/Upstream/components/Step1.tsx
+++ b/web/src/pages/Upstream/components/Step1.tsx
@@ -19,7 +19,7 @@ import { Form, Input } from 'antd';
import type { FormInstance } from 'antd/lib/form';
import { useIntl } from 'umi';
-import UpstreamForm, { DEFAULT_UPSTREAM } from '@/components/Upstream';
+import UpstreamForm from '@/components/Upstream';
import { fetchList } from '../service';
type Props = {
@@ -38,7 +38,7 @@ const Step1: React.FC<Props> = ({ form, disabled, upstreamRef }) => {
return (
<>
- <Form labelCol={{ span: 3 }} form={form} initialValues={DEFAULT_UPSTREAM}>
+ <Form labelCol={{ span: 3 }} form={form}>
<Form.Item
label={formatMessage({ id: 'page.upstream.step.name' })}
name="name"
diff --git a/web/src/pages/Upstream/locales/en-US.ts b/web/src/pages/Upstream/locales/en-US.ts
index bc078e2..503c6cd 100644
--- a/web/src/pages/Upstream/locales/en-US.ts
+++ b/web/src/pages/Upstream/locales/en-US.ts
@@ -19,7 +19,6 @@ export default {
'page.upstream.step.select.upstream.select.option': 'Custom',
'page.upstream.form.item-label.node.domain.or.ip': 'Targets',
'page.upstream.step.input.domain.name.or.ip': 'Please enter domain or IP',
- 'page.upstream.step.domain.name.or.ip.rule': 'Only letters, numbers and . are supported',
'page.upstream.step.domain.name.or.ip': 'Hostname or IP',
'page.upstream.step.input.port': 'Please enter port number',
'page.upstream.step.port': 'Port',
@@ -54,18 +53,7 @@ export default {
'page.upstream.step.healthyCheck.active': 'Active',
'page.upstream.step.healthyCheck.active.timeout': 'Timeout',
'page.upstream.step.input.healthyCheck.active.timeout': 'Please enter timeout',
- 'page.upstream.step.healthyCheck.active.http_path': 'HTTP Path',
- 'page.upstream.step.healthyCheck.activePort': 'Port',
- 'page.upstream.step.input.healthyCheck.activePort': 'Port',
- 'page.upstream.step.healthyCheck.activeHost': 'Host',
- 'page.upstream.step.input.healthyCheck.activeHost': 'Please enter HTTP Request Host',
- 'page.upstream.step.healthyCheck.activeInterval': 'Interval',
'page.upstream.step.input.healthyCheck.activeInterval': 'Please enter interval',
- 'page.upstream.step.healthyCheck.successes': 'Successes',
- 'page.upstream.step.input.healthyCheck.successes': 'Please enter successes',
- 'page.upstream.step.healthyCheck.http_failures': 'HTTP Failures',
- 'page.upstream.step.input.healthyCheck.http_failures': 'Please enter http failures',
- 'page.upstream.step.healthyCheck.active.req_headers': 'Request Headers',
'page.upstream.step.input.healthyCheck.active.req_headers': 'Please enter request headers',
'page.upstream.step.healthyCheck.passive': 'Passive',
'page.upstream.step.healthyCheck.passive.http_statuses': 'HTTP Status',
@@ -100,21 +88,13 @@ export default {
'page.upstream.type.roundrobin': 'Round Robin',
'page.upstream.type.chash': 'CHash',
'page.upstream.type.ewma': 'EWMA',
+ 'page.upstream.type.least_conn': 'Least conn',
'page.upstream.list.content': 'The upstream list contains the created upstream services (i.e., backend services) and allows load balancing and health checking of multiple target nodes of the upstream services.',
- 'page.upstream.retries': 'Retries',
-
- 'page.upstream.checks.active.http_path.placeholder': 'Please enter HTTP request path',
- 'page.upstream.step.input.healthyCheck.active.http_path': 'Path to use in GET HTTP request to run on active checks',
'page.upstream.checks.active.timeout.description': 'Socket timeout for active checks (in seconds)',
- 'page.upstream.checks.active.host.description': 'The hostname of the HTTP request used to perform the active health check',
- 'page.upstream.checks.active.healthy.interval.description': 'Interval between checks for healthy targets (in seconds)',
- 'page.upstream.checks.active.healthy.successes.description': 'Number of successes to consider a target healthy',
'page.upstream.checks.active.unhealthy.interval.description': 'Interval between checks for unhealthy targets (in seconds)',
- 'page.upstream.checks.active.unhealthy.http_failures.description': 'Number of HTTP failures to consider a target unhealthy',
'page.upstream.checks.passive.healthy.http_statuses.description': 'Which HTTP statuses to consider a failure',
- 'page.upstream.checks.passive.healthy.successes.description': 'Number of successes to consider a target healthy',
'page.upstream.checks.passive.unhealthy.http_statuses.description': 'Which HTTP statuses to consider a success',
'page.upstream.checks.passive.unhealthy.http_failures.description': 'Number of HTTP failures to consider a target unhealthy',
'page.upstream.checks.passive.unhealthy.tcp_failures.description': 'Number of TCP failures to consider a target unhealthy',
diff --git a/web/src/pages/Upstream/locales/zh-CN.ts b/web/src/pages/Upstream/locales/zh-CN.ts
index 58620ba..7a0d648 100644
--- a/web/src/pages/Upstream/locales/zh-CN.ts
+++ b/web/src/pages/Upstream/locales/zh-CN.ts
@@ -19,9 +19,8 @@ export default {
'page.upstream.step.select.upstream.select.option': '手动填写',
'page.upstream.form.item-label.node.domain.or.ip': '目标节点',
'page.upstream.step.input.domain.name.or.ip': '请输入域名或 IP',
- 'page.upstream.step.domain.name.or.ip.rule': '仅支持字母、数字和 . ',
'page.upstream.step.domain.name.or.ip': '主机名或 IP',
- 'page.upstream.step.input.port': '请输入端口',
+ 'page.upstream.step.input.port': '请输入',
'page.upstream.step.port': '端口',
'page.upstream.step.input.weight': '请输入权重',
'page.upstream.step.weight': '权重',
@@ -33,10 +32,10 @@ export default {
'page.upstream.step.input.description': '请输入上游服务的描述',
'page.upstream.step.type': '负载均衡算法',
'page.upstream.step.pass-host': 'Host 请求头',
- 'page.upstream.step.pass-host.pass': '保持与客户端请求一致的 Host 请求头',
- 'page.upstream.step.pass-host.node': '使用上游节点列表中的域名或 IP',
+ 'page.upstream.step.pass-host.pass': '保持与客户端请求一致的主机名',
+ 'page.upstream.step.pass-host.node': '使用上游节点列表中的主机名或 IP',
'page.upstream.step.pass-host.rewrite': '自定义 Host 请求头(即将废弃)',
- 'page.upstream.step.pass-host.upstream_host': '自定义 Host 请求头',
+ 'page.upstream.step.pass-host.upstream_host': '自定义主机名',
'page.upstream.step.connect.timeout': '连接超时',
'page.upstream.step.connect.timeout.desc': '建立从请求到上游服务器的连接的超时时间',
'page.upstream.step.input.connect.timeout': '请输入连接超时时间',
@@ -54,18 +53,7 @@ export default {
'page.upstream.step.healthyCheck.active': '主动检查',
'page.upstream.step.healthyCheck.active.timeout': '超时时间',
'page.upstream.step.input.healthyCheck.active.timeout': '请输入超时时间',
- 'page.upstream.step.healthyCheck.active.http_path': '路径',
- 'page.upstream.step.healthyCheck.activePort': '端口',
- 'page.upstream.step.input.healthyCheck.activePort': '端口',
- 'page.upstream.step.healthyCheck.activeHost': '域名',
- 'page.upstream.step.input.healthyCheck.activeHost': '请输入 HTTP 请求域名',
- 'page.upstream.step.healthyCheck.activeInterval': '间隔时间',
'page.upstream.step.input.healthyCheck.activeInterval': '请输入间隔时间',
- 'page.upstream.step.healthyCheck.successes': '成功次数',
- 'page.upstream.step.input.healthyCheck.successes': '请输入成功次数',
- 'page.upstream.step.healthyCheck.http_failures': '失败次数',
- 'page.upstream.step.input.healthyCheck.http_failures': '请输入失败次数',
- 'page.upstream.step.healthyCheck.active.req_headers': '请求头',
'page.upstream.step.input.healthyCheck.active.req_headers': '请输入请求头',
'page.upstream.step.healthyCheck.passive': '被动检查',
'page.upstream.step.healthyCheck.passive.http_statuses': '状态码',
@@ -97,24 +85,16 @@ export default {
'page.upstream.list.input': '请输入',
'page.upstream.list.create': '创建',
- 'page.upstream.type.roundrobin': '轮询调度(Round Robin)',
+ 'page.upstream.type.roundrobin': '带权轮询(Round Robin)',
'page.upstream.type.chash': '一致性哈希(CHash)',
'page.upstream.type.ewma': '指数加权移动平均法(EWMA)',
+ 'page.upstream.type.least_conn': '最小连接数(least_conn)',
'page.upstream.list.content': '上游列表包含了已创建的上游服务(即后端服务),可以对上游服务的多个目标节点进行负载均衡和健康检查。',
- 'page.upstream.retries': '重试次数',
-
- 'page.upstream.checks.active.http_path.placeholder': '请输入 HTTP 请求路径',
- 'page.upstream.step.input.healthyCheck.active.http_path': '进行主动健康检查时使用的 HTTP 请求路径(默认为 /)',
'page.upstream.checks.active.timeout.description': '主动健康检查的套接字的超时时间',
- 'page.upstream.checks.active.host.description': '进行主动健康检查时使用的 HTTP 请求主机名',
- 'page.upstream.checks.active.healthy.interval.description': '对健康的上游服务目标节点进行主动健康检查的间隔时间,默认值为0,表示对健康节点不进行主动健康检查。',
- 'page.upstream.checks.active.healthy.successes.description': '主动健康检查的 HTTP 成功次数,默认值为0。若达到此值,表示上游服务目标节点是健康的。',
'page.upstream.checks.active.unhealthy.interval.description': '对不健康的上游服务目标节点进行主动健康检查的间隔时间,默认值为0,表示对不健康节点不进行主动健康检查。',
- 'page.upstream.checks.active.unhealthy.http_failures.description': '主动健康检查的 HTTP 失败次数,默认值为0。若达到此值,表示上游服务目标节点是不健康的。',
'page.upstream.checks.passive.healthy.http_statuses.description': '当被动健康检查的探针返回值是 HTTP 状态码列表的某一个值时,代表健康状态是由代理流量产生的。',
- 'page.upstream.checks.passive.healthy.successes.description': '通过被动健康检查观察到的正常代理流量的成功次数。如果达到该值,上游服务目标节点将被视为健康。',
'page.upstream.checks.passive.unhealthy.http_statuses.description': '当被动健康检查的探针返回值是 HTTP 状态码列表的某一个值时,代表不健康状态是由代理流量产生的。',
'page.upstream.checks.passive.unhealthy.http_failures.description': '由被动健康检查所观察,代理流量中 HTTP 失败的次数。如果达到此值,则认为上游服务目标节点是不健康的。',
'page.upstream.checks.passive.unhealthy.tcp_failures.description': '被动健康检查所观察到的代理流量中 TCP 失败的次数。如果达到此值,则认为上游服务目标节点是不健康的。',
diff --git a/web/src/pages/Upstream/transform.ts b/web/src/pages/Upstream/transform.ts
index efe0f17..0b520f2 100644
--- a/web/src/pages/Upstream/transform.ts
+++ b/web/src/pages/Upstream/transform.ts
@@ -20,6 +20,9 @@ export const transformRequest = (
formData: UpstreamModule.RequestBody,
): UpstreamModule.RequestBody | undefined | { upstream_id: string } => {
let data = pickBy(formData, identity) as UpstreamModule.RequestBody;
+
+ data = omit(data, 'custom')
+
const {
type,
hash_on,
@@ -30,6 +33,7 @@ export const transformRequest = (
upstream_host,
upstream_id,
} = data;
+
data.checks = pickBy(data.checks || {}, identity);
if (data.checks.active) {
data.checks.active = pickBy(
diff --git a/web/src/pages/Upstream/typing.d.ts b/web/src/pages/Upstream/typing.d.ts
index 39ae372..a262ba1 100644
--- a/web/src/pages/Upstream/typing.d.ts
+++ b/web/src/pages/Upstream/typing.d.ts
@@ -79,6 +79,9 @@ declare namespace UpstreamModule {
desc?: string;
pass_host?: 'pass' | 'node' | 'rewrite';
upstream_host: UpstreamHost[];
+
+ // Custom Fields that need to be omitted
+ custom?: {};
};
// TODO: typing