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

juzhiyuan 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 2c158a1  chore: improve Upstream/CodeMirror (#1707)
2c158a1 is described below

commit 2c158a18f31d944fdf7f28727553bbf72f3198ce
Author: 琚致远 <[email protected]>
AuthorDate: Wed Apr 7 12:29:58 2021 +0800

    chore: improve Upstream/CodeMirror (#1707)
---
 web/cypress/fixtures/export-route-dataset.json     |   3 +
 .../rawDataEditor/test-rawDataEditor.spec.js       |   3 +-
 .../upstream/create_and_delete_upstream.spec.js    |   4 +-
 web/src/components/Plugin/PluginDetail.tsx         |  25 ++--
 web/src/components/Plugin/typing.d.ts              |   2 +-
 web/src/components/RawDataEditor/RawDataEditor.tsx |  25 ++--
 web/src/components/RawDataEditor/locales/en-US.ts  |   1 -
 web/src/components/RawDataEditor/locales/zh-CN.ts  |   1 -
 web/src/components/Upstream/UpstreamForm.tsx       | 145 +++++++++++----------
 web/src/components/Upstream/constant.ts            |  40 +++++-
 web/src/locales/en-US/component.ts                 |   5 +-
 web/src/locales/zh-CN/component.ts                 |   5 +-
 web/src/pages/Consumer/List.tsx                    |   2 +-
 web/src/pages/Route/List.tsx                       |   2 +-
 web/src/pages/Route/locales/zh-CN.ts               |   2 +-
 web/src/pages/Service/List.tsx                     |   2 +-
 web/src/pages/Upstream/Create.tsx                  |  14 +-
 web/src/pages/Upstream/List.tsx                    |   7 +-
 web/src/pages/Upstream/components/Step1.tsx        |   3 +-
 web/src/pages/Upstream/locales/en-US.ts            |  83 +++++++-----
 web/src/pages/Upstream/locales/zh-CN.ts            |  71 ++++++----
 21 files changed, 272 insertions(+), 173 deletions(-)

diff --git a/web/cypress/fixtures/export-route-dataset.json 
b/web/cypress/fixtures/export-route-dataset.json
index a60eee0..133971f 100644
--- a/web/cypress/fixtures/export-route-dataset.json
+++ b/web/cypress/fixtures/export-route-dataset.json
@@ -38,6 +38,7 @@
                 "weight": 1
               }
             ],
+            "retries": 1,
             "timeout": {
               "connect": 6,
               "read": 6,
@@ -89,6 +90,7 @@
                 "weight": 1
               }
             ],
+            "retries": 1,
             "timeout": {
               "connect": 6,
               "read": 6,
@@ -139,6 +141,7 @@
                 "weight": 1
               }
             ],
+            "retries": 1,
             "timeout": {
               "connect": 6,
               "read": 6,
diff --git a/web/cypress/integration/rawDataEditor/test-rawDataEditor.spec.js 
b/web/cypress/integration/rawDataEditor/test-rawDataEditor.spec.js
index 91856ee..3c80397 100644
--- a/web/cypress/integration/rawDataEditor/test-rawDataEditor.spec.js
+++ b/web/cypress/integration/rawDataEditor/test-rawDataEditor.spec.js
@@ -35,10 +35,9 @@ context('Test RawDataEditor', () => {
     menuList.forEach(function (item) {
       cy.visit('/');
       cy.contains(item).click();
-      cy.contains('Create with Editor').click();
+      cy.contains('Raw Data Editor').click();
       const data = dateset[item];
 
-      // create with editor
       cy.window().then(({ codemirror }) => {
         if (codemirror) {
           codemirror.setValue(JSON.stringify(data));
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 7183155..a8063eb 100644
--- a/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
+++ b/web/cypress/integration/upstream/create_and_delete_upstream.spec.js
@@ -74,9 +74,9 @@ context('Create and Delete Upstream', () => {
     cy.get(this.domSelector.description).type(this.data.description);
 
     // change upstream type to chash, todo: optimize the search method
-    cy.get('[title=roundrobin]').click();
+    cy.get('[title="Round Robin"]').click();
     cy.get(this.domSelector.upstreamType).within(() => {
-      cy.contains('chash').click();
+      cy.contains('CHash').click();
     });
     cy.get('#hash_on').click();
     cy.get(this.domSelector.upstreamType).within(() => {
diff --git a/web/src/components/Plugin/PluginDetail.tsx 
b/web/src/components/Plugin/PluginDetail.tsx
index 6ad7d9c..8c3eac7 100644
--- a/web/src/components/Plugin/PluginDetail.tsx
+++ b/web/src/components/Plugin/PluginDetail.tsx
@@ -87,24 +87,24 @@ const PluginDetail: React.FC<Props> = ({
   readonly = false,
   maskClosable = true,
   initialData = {},
-  onClose = () => {},
-  onChange = () => {},
+  onClose = () => { },
+  onChange = () => { },
 }) => {
   const { formatMessage } = useIntl();
   enum codeMirrorModeList {
-    Json = 'Json',
-    Yaml = 'Yaml',
+    JSON = 'JSON',
+    YAML = 'YAML',
   }
   const [form] = Form.useForm();
   const ref = useRef<any>(null);
   const data = initialData[name] || {};
   const pluginType = pluginList.find((item) => item.name === name)?.type;
   const [codeMirrorMode, setCodeMirrorMode] = 
useState<PluginComponent.CodeMirrorMode>(
-    codeMirrorModeList.Json,
+    codeMirrorModeList.JSON,
   );
   const modeOptions = [
-    { label: codeMirrorModeList.Json, value: codeMirrorModeList.Json },
-    { label: codeMirrorModeList.Yaml, value: codeMirrorModeList.Yaml },
+    { label: codeMirrorModeList.JSON, value: codeMirrorModeList.JSON },
+    { label: codeMirrorModeList.YAML, value: codeMirrorModeList.YAML },
   ];
 
   useEffect(() => {
@@ -160,8 +160,8 @@ const PluginDetail: React.FC<Props> = ({
   };
   const handleModeChange = (value: PluginComponent.CodeMirrorMode) => {
     switch (value) {
-      case codeMirrorModeList.Json: {
-        const { data: yamlData , error } = 
yaml2json(ref.current.editor.getValue(), true);
+      case codeMirrorModeList.JSON: {
+        const { data: yamlData, error } = 
yaml2json(ref.current.editor.getValue(), true);
 
         if (error) {
           notification.error({
@@ -176,7 +176,7 @@ const PluginDetail: React.FC<Props> = ({
         );
         break;
       }
-      case codeMirrorModeList.Yaml: {
+      case codeMirrorModeList.YAML: {
         const { data: jsonData, error } = 
json2yaml(ref.current.editor.getValue());
 
         if (error) {
@@ -250,7 +250,7 @@ const PluginDetail: React.FC<Props> = ({
                 onClick={() => {
                   try {
                     const editorData =
-                      codeMirrorMode === codeMirrorModeList.Json
+                      codeMirrorMode === codeMirrorModeList.JSON
                         ? JSON.parse(ref.current?.editor.getValue())
                         : yaml2json(ref.current?.editor.getValue(), 
false).data;
                     validateData(name, editorData).then((value) => {
@@ -320,7 +320,7 @@ const PluginDetail: React.FC<Props> = ({
               {formatMessage({ id: 'component.global.document' })}
             </Button>,
             <Select
-              defaultValue={codeMirrorModeList.Json}
+              defaultValue={codeMirrorModeList.JSON}
               value={codeMirrorMode}
               options={modeOptions}
               onChange={(value: PluginComponent.CodeMirrorMode) => {
@@ -338,6 +338,7 @@ const PluginDetail: React.FC<Props> = ({
             ref.current = codemirror;
             if (codemirror) {
               // NOTE: for debug & test
+              // @ts-ignore
               window.codemirror = codemirror.editor;
             }
           }}
diff --git a/web/src/components/Plugin/typing.d.ts 
b/web/src/components/Plugin/typing.d.ts
index 533fa6a..79dda49 100644
--- a/web/src/components/Plugin/typing.d.ts
+++ b/web/src/components/Plugin/typing.d.ts
@@ -30,5 +30,5 @@ declare namespace PluginComponent {
 
   type ReferPage = '' | 'route' | 'consumer' | 'service' | 'plugin';
 
-  type CodeMirrorMode = 'Json' | 'Yaml';
+  type CodeMirrorMode = 'JSON' | 'YAML';
 }
diff --git a/web/src/components/RawDataEditor/RawDataEditor.tsx 
b/web/src/components/RawDataEditor/RawDataEditor.tsx
index 588cebd..3117bd2 100644
--- a/web/src/components/RawDataEditor/RawDataEditor.tsx
+++ b/web/src/components/RawDataEditor/RawDataEditor.tsx
@@ -34,29 +34,29 @@ type Props = {
 };
 
 enum codeMirrorModeList {
-  Json = 'Json',
-  Yaml = 'Yaml',
+  JSON = 'JSON',
+  YAML = 'YAML',
 }
 
 const RawDataEditor: React.FC<Props> = ({ visible, readonly = true, type, data 
= {}, onClose = () => { }, onSubmit = () => { } }) => {
   const ref = useRef<any>(null);
   const { formatMessage } = useIntl();
   const [codeMirrorMode, setCodeMirrorMode] = 
useState<PluginComponent.CodeMirrorMode>(
-    codeMirrorModeList.Json,
+    codeMirrorModeList.JSON,
   );
 
   useEffect(() => {
-    setCodeMirrorMode(codeMirrorModeList.Json);
+    setCodeMirrorMode(codeMirrorModeList.JSON);
   }, [visible])
 
   const modeOptions = [
-    { label: codeMirrorModeList.Json, value: codeMirrorModeList.Json },
-    { label: codeMirrorModeList.Yaml, value: codeMirrorModeList.Yaml },
+    { label: codeMirrorModeList.JSON, value: codeMirrorModeList.JSON },
+    { label: codeMirrorModeList.YAML, value: codeMirrorModeList.YAML },
   ];
 
   const handleModeChange = (value: PluginComponent.CodeMirrorMode) => {
     switch (value) {
-      case codeMirrorModeList.Json: {
+      case codeMirrorModeList.JSON: {
         const { data: yamlData, error } = 
yaml2json(ref.current.editor.getValue(), true);
 
         if (error) {
@@ -72,12 +72,12 @@ const RawDataEditor: React.FC<Props> = ({ visible, readonly 
= true, type, data =
         );
         break;
       }
-      case codeMirrorModeList.Yaml: {
+      case codeMirrorModeList.YAML: {
         const { data: jsonData, error } = 
json2yaml(ref.current.editor.getValue());
 
         if (error) {
           notification.error({
-            message: 'Invalid Json data',
+            message: 'Invalid JSON data',
           });
           return;
         }
@@ -109,7 +109,7 @@ const RawDataEditor: React.FC<Props> = ({ visible, readonly 
= true, type, data =
   return (
     <>
       <Drawer
-        title={formatMessage({ id: 'component.rawDataEditor.title' })}
+        title={formatMessage({ id: 'component.global.data.editor' })}
         placement="right"
         width={700}
         visible={visible}
@@ -126,7 +126,7 @@ const RawDataEditor: React.FC<Props> = ({ visible, readonly 
= true, type, data =
                 onClick={() => {
                   try {
                     const editorData =
-                      codeMirrorMode === codeMirrorModeList.Json
+                      codeMirrorMode === codeMirrorModeList.JSON
                         ? JSON.parse(ref.current?.editor.getValue())
                         : yaml2json(ref.current?.editor.getValue(), 
false).data;
                     onSubmit(editorData);
@@ -159,7 +159,7 @@ const RawDataEditor: React.FC<Props> = ({ visible, readonly 
= true, type, data =
               Document
             </Button>,
             <Select
-              defaultValue={codeMirrorModeList.Json}
+              defaultValue={codeMirrorModeList.JSON}
               value={codeMirrorMode}
               options={modeOptions}
               onChange={(value: PluginComponent.CodeMirrorMode) => {
@@ -192,6 +192,7 @@ const RawDataEditor: React.FC<Props> = ({ visible, readonly 
= true, type, data =
             ref.current = codemirror;
             if (codemirror) {
               // NOTE: for debug & test
+              // @ts-ignore
               window.codemirror = codemirror.editor;
             }
           }}
diff --git a/web/src/components/RawDataEditor/locales/en-US.ts 
b/web/src/components/RawDataEditor/locales/en-US.ts
index 773b53c..c5c1643 100644
--- a/web/src/components/RawDataEditor/locales/en-US.ts
+++ b/web/src/components/RawDataEditor/locales/en-US.ts
@@ -16,5 +16,4 @@
  */
 export default {
   'component.rawDataEditor.tip': "Don't support edit mode currently",
-  'component.rawDataEditor.title': 'Raw Data Editor',
 };
diff --git a/web/src/components/RawDataEditor/locales/zh-CN.ts 
b/web/src/components/RawDataEditor/locales/zh-CN.ts
index 7a4a1ac..14e10c6 100644
--- a/web/src/components/RawDataEditor/locales/zh-CN.ts
+++ b/web/src/components/RawDataEditor/locales/zh-CN.ts
@@ -16,5 +16,4 @@
  */
 export default {
   'component.rawDataEditor.tip': '目前暂不支持编辑',
-  'component.rawDataEditor.title': '元数据编辑器',
 };
diff --git a/web/src/components/Upstream/UpstreamForm.tsx 
b/web/src/components/Upstream/UpstreamForm.tsx
index 609a15f..2d54f75 100644
--- a/web/src/components/Upstream/UpstreamForm.tsx
+++ b/web/src/components/Upstream/UpstreamForm.tsx
@@ -66,7 +66,7 @@ type Props = {
 };
 
 const removeBtnStyle = {
-  marginLeft: -10,
+  marginLeft: 20,
   display: 'flex',
   alignItems: 'center',
 };
@@ -83,14 +83,17 @@ const UpstreamForm: React.FC<Props> = forwardRef(
       {
         label: formatMessage({ id: 'page.upstream.step.connect.timeout' }),
         name: ['timeout', 'connect'],
+        desc: formatMessage({ id: 'page.upstream.step.connect.timeout.desc' })
       },
       {
         label: formatMessage({ id: 'page.upstream.step.send.timeout' }),
         name: ['timeout', 'send'],
+        desc: formatMessage({ id: 'page.upstream.step.send.timeout.desc' })
       },
       {
         label: formatMessage({ id: 'page.upstream.step.read.timeout' }),
         name: ['timeout', 'read'],
+        desc: formatMessage({ id: 'page.upstream.step.read.timeout.desc' })
       },
     ];
 
@@ -155,22 +158,9 @@ const UpstreamForm: React.FC<Props> = forwardRef(
       <Form.List name="nodes">
         {(fields, { add, remove }) => (
           <>
-            {fields.map((field, index) => (
-              <Form.Item
-                required
-                key={field.key}
-                label={
-                  index === 0 &&
-                  formatMessage({ id: 
'page.upstream.form.item-label.node.domain.or.ip' })
-                }
-                extra={
-                  index === 0 &&
-                  formatMessage({ id: 
'page.upstream.form.item.extra-message.node.domain.or.ip' })
-                }
-                labelCol={{ span: index === 0 ? 3 : 0 }}
-                wrapperCol={{ offset: index === 0 ? 0 : 3 }}
-              >
-                <Row style={{ marginBottom: 10 }} gutter={16}>
+            <Form.Item label={formatMessage({ id: 
'page.upstream.form.item-label.node.domain.or.ip' })}>
+              {fields.map((field, index) => (
+                <Row style={{ marginBottom: 10 }} gutter={16} key={index}>
                   <Col span={5}>
                     <Form.Item
                       style={{ marginBottom: 0 }}
@@ -196,10 +186,11 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                       />
                     </Form.Item>
                   </Col>
-                  <Col span={2}>
+                  <Col span={4}>
                     <Form.Item
                       style={{ marginBottom: 0 }}
                       name={[field.name, 'port']}
+                      label={formatMessage({ id: 'page.upstream.step.port' })}
                       rules={[
                         {
                           required: true,
@@ -210,15 +201,16 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                       <InputNumber
                         placeholder={formatMessage({ id: 
'page.upstream.step.port' })}
                         disabled={readonly}
-                        min={1}
+                        min={0}
                         max={65535}
                       />
                     </Form.Item>
                   </Col>
-                  <Col span={2}>
+                  <Col span={5}>
                     <Form.Item
                       style={{ marginBottom: 0 }}
                       name={[field.name, 'weight']}
+                      label={formatMessage({ id: 'page.upstream.step.weight' 
})}
                       rules={[
                         {
                           required: true,
@@ -234,14 +226,14 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                       />
                     </Form.Item>
                   </Col>
-                  <Col style={removeBtnStyle}>
-                    {!readonly && fields.length > 1 && (
+                  <Col style={{ ...removeBtnStyle, marginLeft: -25 }}>
+                    {!readonly && (
                       <MinusCircleOutlined onClick={() => remove(field.name)} 
/>
                     )}
                   </Col>
                 </Row>
-              </Form.Item>
-            ))}
+              ))}
+            </Form.Item>
             {!readonly && (
               <Form.Item wrapperCol={{ offset: 3 }}>
                 <Button type="dashed" onClick={add}>
@@ -257,15 +249,16 @@ const UpstreamForm: React.FC<Props> = forwardRef(
 
     const ActiveHealthCheck = () => (
       <>
-        <Form.Item label={formatMessage({ id: 
'page.upstream.step.healthyCheck.active.timeout' })}>
+        <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>
-            <InputNumber disabled={readonly} />
+            <InputNumber disabled={readonly} min={0} />
           </Form.Item>
-          <span style={{ margin: '0 8px' }}>s</span>
+          <TimeUnit />
         </Form.Item>
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.activeHost' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.active.host.description' })}
         >
           <Form.Item
             style={{ marginBottom: 0 }}
@@ -300,6 +293,8 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                 id: 'page.upstream.step.input.healthyCheck.activePort',
               })}
               disabled={readonly}
+              min={0}
+              max={65535}
             />
           </Form.Item>
         </Form.Item>
@@ -307,6 +302,9 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.active.http_path' })}
           required
+          tooltip={formatMessage({
+            id: 'page.upstream.step.input.healthyCheck.active.http_path',
+          })}
         >
           <Form.Item
             name={['checks', 'active', 'http_path']}
@@ -314,17 +312,13 @@ const UpstreamForm: React.FC<Props> = forwardRef(
             rules={[
               {
                 required: true,
-                message: formatMessage({
-                  id: 'page.upstream.step.input.healthyCheck.active.http_path',
-                }),
+                message: formatMessage({ id: 
'page.upstream.checks.active.http_path.placeholder' }),
               },
             ]}
           >
             <Input
               disabled={readonly}
-              placeholder={formatMessage({
-                id: 'page.upstream.step.input.healthyCheck.active.http_path',
-              })}
+              placeholder={formatMessage({ id: 
'page.upstream.checks.active.http_path.placeholder' })}
             />
           </Form.Item>
         </Form.Item>
@@ -335,8 +329,10 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.activeInterval' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.active.healthy.interval.description' })}
         >
           <Form.Item
+            noStyle
             style={{ marginBottom: 0 }}
             name={['checks', 'active', 'healthy', 'interval']}
             rules={[
@@ -350,10 +346,12 @@ const UpstreamForm: React.FC<Props> = forwardRef(
           >
             <InputNumber disabled={readonly} min={1} />
           </Form.Item>
+          <TimeUnit />
         </Form.Item>
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.successes' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.active.healthy.successes.description' })}
         >
           <Form.Item
             name={['checks', 'active', 'healthy', 'successes']}
@@ -375,6 +373,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.activeInterval' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.active.unhealthy.interval.description' })}
         >
           <Form.Item
             name={['checks', 'active', 'unhealthy', 'interval']}
@@ -390,10 +389,12 @@ const UpstreamForm: React.FC<Props> = forwardRef(
           >
             <InputNumber disabled={readonly} min={1} />
           </Form.Item>
+          <TimeUnit />
         </Form.Item>
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.http_failures' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.active.unhealthy.http_failures.description' })}
         >
           <Form.Item
             name={['checks', 'active', 'unhealthy', 'http_failures']}
@@ -469,25 +470,20 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.List name={['checks', 'passive', 'healthy', 'http_statuses']}>
           {(fields, { add, remove }) => (
             <>
-              {fields.map((field, index) => (
-                <Form.Item
-                  required
-                  key={field.key}
-                  label={
-                    index === 0 &&
-                    formatMessage({ id: 
'page.upstream.step.healthyCheck.passive.http_statuses' })
-                  }
-                  labelCol={{ span: index === 0 ? 3 : 0 }}
-                  wrapperCol={{ offset: index === 0 ? 0 : 3 }}
-                >
-                  <Row style={{ marginBottom: 10 }}>
+              <Form.Item
+                required
+                label={formatMessage({ id: 
'page.upstream.step.healthyCheck.passive.http_statuses' })}
+                tooltip={formatMessage({ id: 
'page.upstream.checks.passive.healthy.http_statuses.description' })}
+              >
+                {fields.map((field, index) => (
+                  <Row style={{ marginBottom: 10 }} key={index}>
                     <Col span={2}>
                       <Form.Item style={{ marginBottom: 0 }} 
name={[field.name]}>
-                        <InputNumber disabled={readonly} />
+                        <InputNumber disabled={readonly} min={200} max={599} />
                       </Form.Item>
                     </Col>
                     <Col style={removeBtnStyle}>
-                      {!readonly && fields.length > 1 && (
+                      {!readonly && (
                         <MinusCircleOutlined
                           onClick={() => {
                             remove(field.name);
@@ -496,8 +492,8 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                       )}
                     </Col>
                   </Row>
-                </Form.Item>
-              ))}
+                ))}
+              </Form.Item>
               {!readonly && (
                 <Form.Item wrapperCol={{ offset: 3 }}>
                   <Button type="dashed" onClick={() => add()}>
@@ -513,6 +509,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         </Form.List>
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.successes' })}
+          tooltip={formatMessage({ id: 
'page.upstream.checks.passive.healthy.successes.description' })}
           required
         >
           <Form.Item
@@ -535,21 +532,16 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.List name={['checks', 'passive', 'unhealthy', 'http_statuses']}>
           {(fields, { add, remove }) => (
             <>
-              {fields.map((field, index) => (
-                <Form.Item
-                  required
-                  key={field.key}
-                  label={
-                    index === 0 &&
-                    formatMessage({ id: 
'page.upstream.step.healthyCheck.passive.http_statuses' })
-                  }
-                  labelCol={{ span: index === 0 ? 3 : 0 }}
-                  wrapperCol={{ offset: index === 0 ? 0 : 3 }}
-                >
-                  <Row style={{ marginBottom: 10 }}>
+              <Form.Item
+                required
+                label={formatMessage({ id: 
'page.upstream.step.healthyCheck.passive.http_statuses' })}
+                tooltip={formatMessage({ id: 
'page.upstream.checks.passive.unhealthy.http_statuses.description' })}
+              >
+                {fields.map((field, index) => (
+                  <Row style={{ marginBottom: 10 }} key={index}>
                     <Col span={2}>
                       <Form.Item style={{ marginBottom: 0 }} 
name={[field.name]}>
-                        <InputNumber disabled={readonly} max={599} />
+                        <InputNumber disabled={readonly} min={200} max={599} />
                       </Form.Item>
                     </Col>
                     <Col style={removeBtnStyle}>
@@ -562,8 +554,8 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                       )}
                     </Col>
                   </Row>
-                </Form.Item>
-              ))}
+                ))}
+              </Form.Item>
               {!readonly && (
                 <Form.Item wrapperCol={{ offset: 3 }}>
                   <Button type="dashed" onClick={() => add()}>
@@ -580,6 +572,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.http_failures' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.passive.unhealthy.http_failures.description' })}
         >
           <Form.Item
             name={['checks', 'passive', 'unhealthy', 'http_failures']}
@@ -599,6 +592,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
         <Form.Item
           label={formatMessage({ id: 
'page.upstream.step.healthyCheck.passive.tcp_failures' })}
           required
+          tooltip={formatMessage({ id: 
'page.upstream.checks.passive.unhealthy.tcp_failures.description' })}
         >
           <Form.Item
             name={['checks', 'passive', 'unhealthy', 'tcp_failures']}
@@ -688,7 +682,7 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                 {Object.entries(Type).map(([label, value]) => {
                   return (
                     <Select.Option value={value} key={value}>
-                      {label}
+                      {formatMessage({ id: `page.upstream.type.${label}` })}
                     </Select.Option>
                   );
                 })}
@@ -719,6 +713,16 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                 </Select.Option>
               </Select>
             </Form.Item>
+
+            <Form.Item
+              label={formatMessage({ id: 'page.upstream.retries' })}
+              name="retries"
+            >
+              <InputNumber
+                disabled={disabled}
+              />
+            </Form.Item>
+
             <Form.Item
               noStyle
               shouldUpdate={(prev, next) => {
@@ -746,8 +750,8 @@ const UpstreamForm: React.FC<Props> = forwardRef(
               }}
             </Form.Item>
 
-            {timeoutFields.map(({ label, name }) => (
-              <Form.Item label={label} required key={label}>
+            {timeoutFields.map(({ label, name, desc = '' }) => (
+              <Form.Item label={label} required key={label} tooltip={desc}>
                 <Form.Item
                   name={name}
                   noStyle
@@ -771,7 +775,12 @@ const UpstreamForm: React.FC<Props> = forwardRef(
                 {
                   label: formatMessage({ id: 
'page.upstream.step.healthyCheck.active' }),
                   name: ['checks', 'active'],
-                  component: <ActiveHealthCheck />,
+                  component: (
+                    <>
+                      <ActiveHealthCheck />
+                      <Divider orientation="left" plain />
+                    </>
+                  ),
                 },
                 {
                   label: formatMessage({ id: 
'page.upstream.step.healthyCheck.passive' }),
diff --git a/web/src/components/Upstream/constant.ts 
b/web/src/components/Upstream/constant.ts
index 9a2bc8a..58d8ed5 100644
--- a/web/src/components/Upstream/constant.ts
+++ b/web/src/components/Upstream/constant.ts
@@ -16,11 +16,49 @@
  */
 export const DEFAULT_UPSTREAM = {
   upstream_id: '',
-  nodes: [{ host: '', port: 80, weight: 1 }],
+  nodes: [
+    {
+      host: '',
+      port: 80,
+      weight: 1
+    }
+  ],
   type: 'roundrobin',
   timeout: {
     connect: 6,
     send: 6,
     read: 6,
   },
+  retries: 1
 };
+
+// NOTE: checks.active
+export const DEFAULT_HEALTH_CHECK_ACTIVE = {
+  timeout: 0,
+  http_path: '/',
+  host: '',
+  port: 80,
+  healthy: {
+    interval: 1,
+    successes: 1
+  },
+  unhealthy: {
+    interval: 1,
+    http_failures: 1,
+    req_headers: []
+  }
+}
+
+// NOTE: checks.passive
+export const DEFAULT_HEALTH_CHECK_PASSIVE = {
+  healthy: {
+    http_statuses: [],
+    successes: 1
+  },
+  unhealthy: {
+    http_statuses: [],
+    tcp_failures: 1,
+    timeouts: 1,
+    http_failures: 1
+  }
+}
diff --git a/web/src/locales/en-US/component.ts 
b/web/src/locales/en-US/component.ts
index a6a4100..55b6a8a 100644
--- a/web/src/locales/en-US/component.ts
+++ b/web/src/locales/en-US/component.ts
@@ -25,12 +25,11 @@ export default {
   'component.global.document': 'Document',
   'component.global.enable': 'Enable',
   'component.global.scope': 'Scope',
-  'component.global.data.editor': 'Data Editor',
+  'component.global.data.editor': 'Raw Data Editor',
   'component.global.delete': 'Delete',
   'component.global.cancel': 'Cancel',
   'component.global.submit': 'Submit',
   'component.global.create': 'Create',
-  'component.global.createWithEditor': 'Create with Editor',
   'component.global.add': 'Add',
   'component.global.save': 'Save',
   'component.global.edit': 'Configure',
@@ -72,4 +71,6 @@ export default {
   // User component
   'component.user.loginByPassword': 'Username & Password',
   'component.user.login': 'Login',
+
+  'component.document': 'Document'
 };
diff --git a/web/src/locales/zh-CN/component.ts 
b/web/src/locales/zh-CN/component.ts
index ecd3324..f4171ec 100644
--- a/web/src/locales/zh-CN/component.ts
+++ b/web/src/locales/zh-CN/component.ts
@@ -25,12 +25,11 @@ export default {
   'component.global.document': '文档',
   'component.global.enable': '启用',
   'component.global.scope': '作用域',
-  'component.global.data.editor': '元数据编辑器',
+  'component.global.data.editor': '数据编辑器',
   'component.global.delete': '删除',
   'component.global.cancel': '取消',
   'component.global.submit': '提交',
   'component.global.create': '创建',
-  'component.global.createWithEditor': '使用编辑器创建',
   'component.global.add': '新建',
   'component.global.save': '保存',
   'component.global.edit': '配置',
@@ -68,4 +67,6 @@ export default {
   // User component
   'component.user.loginByPassword': '账号密码登录',
   'component.user.login': '登录',
+
+  'component.document': '操作手册'
 };
diff --git a/web/src/pages/Consumer/List.tsx b/web/src/pages/Consumer/List.tsx
index 713e377..a08a722 100644
--- a/web/src/pages/Consumer/List.tsx
+++ b/web/src/pages/Consumer/List.tsx
@@ -137,7 +137,7 @@ const Page: React.FC = () => {
             setRawData({});
           }}>
             <PlusOutlined />
-            {formatMessage({ id: 'component.global.createWithEditor' })}
+            {formatMessage({ id: 'component.global.data.editor' })}
           </Button>,
         ]}
       />
diff --git a/web/src/pages/Route/List.tsx b/web/src/pages/Route/List.tsx
index a9c1ba5..1598462 100644
--- a/web/src/pages/Route/List.tsx
+++ b/web/src/pages/Route/List.tsx
@@ -478,7 +478,7 @@ const Page: React.FC = () => {
             setRawData({});
           }}>
             <PlusOutlined />
-            {formatMessage({ id: 'component.global.createWithEditor' })}
+            {formatMessage({ id: 'component.global.data.editor' })}
           </Button>,
           <Button
             type="primary"
diff --git a/web/src/pages/Route/locales/zh-CN.ts 
b/web/src/pages/Route/locales/zh-CN.ts
index 71aef9b..f2a0d28 100644
--- a/web/src/pages/Route/locales/zh-CN.ts
+++ b/web/src/pages/Route/locales/zh-CN.ts
@@ -116,7 +116,7 @@ export default {
   'page.route.form.itemLabel.domainNameOrIp': '域名/IP',
   'page.route.form.itemExtraMessage.domainNameOrIp': 
'使用域名时,默认解析本地:/etc/resolv.conf',
   'page.route.form.itemRulesPatternMessage.domainNameOrIp': '仅支持字母、数字和 . ',
-  'page.route.portNumber': '端口号',
+  'page.route.portNumber': '端口',
   'page.route.weight': '权重',
 
   'page.route.radio.static': '静态改写',
diff --git a/web/src/pages/Service/List.tsx b/web/src/pages/Service/List.tsx
index 39f7970..7bfab39 100644
--- a/web/src/pages/Service/List.tsx
+++ b/web/src/pages/Service/List.tsx
@@ -135,7 +135,7 @@ const Page: React.FC = () => {
             setRawData({});
           }}>
             <PlusOutlined />
-            {formatMessage({ id: 'component.global.createWithEditor' })}
+            {formatMessage({ id: 'component.global.data.editor' })}
           </Button>,
         ]}
       />
diff --git a/web/src/pages/Upstream/Create.tsx 
b/web/src/pages/Upstream/Create.tsx
index 0e6714e..0e068c7 100644
--- a/web/src/pages/Upstream/Create.tsx
+++ b/web/src/pages/Upstream/Create.tsx
@@ -16,8 +16,9 @@
  */
 import React, { useState, useEffect, useRef } from 'react';
 import { PageContainer } from '@ant-design/pro-layout';
-import { Card, Steps, notification, Form } from 'antd';
+import { Card, Steps, notification, Form, Button } from 'antd';
 import { history, useIntl } from 'umi';
+import { QuestionCircleOutlined } from '@ant-design/icons';
 
 import ActionBar from '@/components/ActionBar';
 
@@ -78,8 +79,15 @@ const Page: React.FC = (props) => {
     <>
       <PageContainer
         title={(props as any).match.params.id
-        ? formatMessage({ id: 'page.upstream.configure' })
-        : formatMessage({ id: 'page.upstream.create' })}
+          ? formatMessage({ id: 'page.upstream.configure' })
+          : formatMessage({ id: 'page.upstream.create' })}
+
+        extra={
+          // TODO: support Document modal
+          <Button type="default" disabled>
+            <QuestionCircleOutlined />
+            {formatMessage({ id: 'component.document' })}
+          </Button>}
       >
         <Card bordered={false}>
           <Steps current={step - 1} style={{ marginBottom: 30 }}>
diff --git a/web/src/pages/Upstream/List.tsx b/web/src/pages/Upstream/List.tsx
index 27474e5..486fbbe 100644
--- a/web/src/pages/Upstream/List.tsx
+++ b/web/src/pages/Upstream/List.tsx
@@ -116,7 +116,7 @@ const Page: React.FC = () => {
   ];
 
   return (
-    <PageContainer title={formatMessage({ id: 'page.upstream.list' })}>
+    <PageContainer title={formatMessage({ id: 'page.upstream.list' })} 
content={formatMessage({ id: "page.upstream.list.content" })}>
       <ProTable<UpstreamModule.ResponseBody>
         actionRef={ref}
         columns={columns}
@@ -136,13 +136,12 @@ const Page: React.FC = () => {
             <PlusOutlined />
             {formatMessage({ id: 'component.global.create' })}
           </Button>,
-          <Button type="primary" onClick={() => {
+          <Button type="default" onClick={() => {
             setVisible(true);
             setEditorMode('create');
             setRawData({});
           }}>
-            <PlusOutlined />
-            {formatMessage({ id: 'component.global.createWithEditor' })}
+            {formatMessage({ id: 'component.global.data.editor' })}
           </Button>,
         ]}
       />
diff --git a/web/src/pages/Upstream/components/Step1.tsx 
b/web/src/pages/Upstream/components/Step1.tsx
index 494f3cb..182ffbc 100644
--- a/web/src/pages/Upstream/components/Step1.tsx
+++ b/web/src/pages/Upstream/components/Step1.tsx
@@ -42,8 +42,7 @@ const Step1: React.FC<Props> = ({ form, disabled, upstreamRef 
}) => {
         <Form.Item
           label={formatMessage({ id: 'page.upstream.step.name' })}
           name="name"
-          rules={[{ required: true, message: formatMessage({ id: 
'page.upstream.step.name.should.unique' }) }]}
-          extra={formatMessage({ id: 'page.upstream.step.name.should.unique' 
})}
+          rules={[{ required: true, message: formatMessage({ id: 
'page.upstream.step.input.upstream.name' }) }]}
         >
           <Input
             placeholder={formatMessage({ id: 
'page.upstream.step.input.upstream.name' })}
diff --git a/web/src/pages/Upstream/locales/en-US.ts 
b/web/src/pages/Upstream/locales/en-US.ts
index 9c35ccb..a78a162 100644
--- a/web/src/pages/Upstream/locales/en-US.ts
+++ b/web/src/pages/Upstream/locales/en-US.ts
@@ -17,36 +17,36 @@
 export default {
   'page.upstream.step.select.upstream': 'Select Upstream',
   'page.upstream.step.select.upstream.select.option': 'Custom',
-  'page.upstream.form.item-label.node.domain.or.ip': 'Node List',
-  'page.upstream.step.backend.server.domain.or.ip': 'Backend Server Domain/IP',
-  'page.upstream.form.item.extra-message.node.domain.or.ip':
-    'When using domain, it will analysis local: /etc/resolv.conf by default, 
if weight is 0, then fusing this node',
-  'page.upstream.step.input.domain.name.or.ip': 'Please input domain or IP',
+  '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': 'Domain or IP',
-  'page.upstream.step.input.port': 'Please input port number',
-  'page.upstream.step.port': 'Port Number',
-  'page.upstream.step.input.weight': 'Please input weight',
+  'page.upstream.step.domain.name.or.ip': 'Hostname or IP',
+  'page.upstream.step.input.port': 'Please enter port number',
+  'page.upstream.step.port': 'Port',
+  'page.upstream.step.input.weight': 'Please enter weight',
   'page.upstream.step.weight': 'Weight',
   'page.upstream.step.create': 'Create',
   'page.upstream.step.name': 'Name',
   'page.upstream.step.name.should.unique': 'Name should be unique',
-  'page.upstream.step.input.upstream.name': 'Please input upstream name',
+  'page.upstream.step.input.upstream.name': 'Please enter upstream name',
   'page.upstream.step.description': 'Description',
-  'page.upstream.step.input.description': 'Please input upstream\'s 
description',
-  'page.upstream.step.type': 'Type',
-  'page.upstream.step.create.node': 'Add Node',
-  'page.upstream.step.pass-host': 'Host Transform',
+  'page.upstream.step.input.description': 'Please enter upstream\'s 
description',
+  'page.upstream.step.type': 'Algorithm',
+  'page.upstream.step.create.node': 'Add Target',
+  'page.upstream.step.pass-host': 'Hostname',
   'page.upstream.step.pass-host.pass': 'Keep the same Host from client 
request',
   'page.upstream.step.pass-host.node': 'Use the domain or IP from Node List',
   'page.upstream.step.pass-host.rewrite': 'Custom Host (Will be deprecated in 
the future)',
   'page.upstream.step.pass-host.upstream_host': 'Custom Host',
   'page.upstream.step.connect.timeout': 'Connect Timeout',
-  'page.upstream.step.input.connect.timeout': 'Please input connect timeout',
+  'page.upstream.step.connect.timeout.desc': 'Timeout for establishing a 
connection from the request to the upstream server',
+  'page.upstream.step.input.connect.timeout': 'Please enter connect timeout',
   'page.upstream.step.send.timeout': 'Send Timeout',
-  'page.upstream.step.input.send.timeout': 'Please input send timeout',
+  'page.upstream.step.send.timeout.desc': 'Timeout for sending data to 
upstream servers',
+  'page.upstream.step.input.send.timeout': 'Please enter send timeout',
   'page.upstream.step.read.timeout': 'Read Timeout',
-  'page.upstream.step.input.read.timeout': 'Please input read timeout',
+  'page.upstream.step.read.timeout.desc': 'Timeout for receiving data from 
upstream servers',
+  'page.upstream.step.input.read.timeout': 'Please enter read timeout',
   'page.upstream.step.healthyCheck.healthy.check': 'Health Check',
   'page.upstream.step.healthyCheck.healthy': 'Healthy',
   'page.upstream.step.healthyCheck.unhealthy': 'Unhealthy',
@@ -54,30 +54,29 @@ export default {
   'page.upstream.step.healthyCheck.unhealthyStatus': 'Unhealthy Status',
   'page.upstream.step.healthyCheck.active': 'Active',
   'page.upstream.step.healthyCheck.active.timeout': 'Timeout',
-  'page.upstream.step.input.healthyCheck.active.timeout': 'Please input 
timeout',
+  'page.upstream.step.input.healthyCheck.active.timeout': 'Please enter 
timeout',
   'page.upstream.step.healthyCheck.active.http_path': 'HTTP Path',
-  'page.upstream.step.input.healthyCheck.active.http_path': 'Please input 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 input active 
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 input 
interval',
+  'page.upstream.step.input.healthyCheck.activeInterval': 'Please enter 
interval',
   'page.upstream.step.healthyCheck.successes': 'Successes',
-  'page.upstream.step.input.healthyCheck.successes': 'Please input successes',
+  'page.upstream.step.input.healthyCheck.successes': 'Please enter successes',
   'page.upstream.step.healthyCheck.http_failures': 'HTTP Failures',
-  'page.upstream.step.healthyCheck.active.create.req_headers': 'Create Request 
Headers',
-  'page.upstream.step.input.healthyCheck.http_failures': 'Please input http 
failures',
+  'page.upstream.step.healthyCheck.active.create.req_headers': 'Add Request 
Headers',
+  '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 input 
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.create.http_statuses': 'Create HTTP 
Status',
+  'page.upstream.step.healthyCheck.passive.create.http_statuses': 'Add HTTP 
Status',
   'page.upstream.step.healthyCheck.passive.http_statuses': 'HTTP Status',
-  'page.upstream.step.input.healthyCheck.passive.http_statuses': 'Please input 
http status',
+  'page.upstream.step.input.healthyCheck.passive.http_statuses': 'Please enter 
http status',
   'page.upstream.step.healthyCheck.passive.tcp_failures': 'TCP Failures',
-  'page.upstream.step.input.healthyCheck.passive.tcp_failures': 'Please input 
TCP failures',
+  'page.upstream.step.input.healthyCheck.passive.tcp_failures': 'Please enter 
TCP failures',
   'page.upstream.notificationMessage.enableHealthCheckFirst': 'Please enable 
health check first.',
-  'page.upstream.upstream_host.required': 'Please input the custom Host',
+  'page.upstream.upstream_host.required': 'Please enter the custom Host',
 
   'page.upstream.create': 'Create Upstream',
   'page.upstream.configure': 'Configure Upstream',
@@ -89,7 +88,7 @@ export default {
   'page.upstream.list.name': 'Name',
   'page.upstream.list.type': 'Type',
   'page.upstream.list.description': 'Description',
-  'page.upstream.list.edit.time': 'Configure Time',
+  'page.upstream.list.edit.time': 'Updated At',
   'page.upstream.list.operation': 'Operation',
   'page.upstream.list.edit': 'Configure',
   'page.upstream.list.confirm.delete': 'Are you sure to delete ?',
@@ -98,6 +97,28 @@ export default {
   'page.upstream.list.delete.successfully': 'Delete Upstream Successfully',
   'page.upstream.list.delete': 'Delete',
   'page.upstream.list': 'Upstream List',
-  'page.upstream.list.input': 'Please input',
+  'page.upstream.list.input': 'Please enter',
   'page.upstream.list.create': 'Create',
+
+  'page.upstream.type.roundrobin': 'Round Robin',
+  'page.upstream.type.chash': 'CHash',
+  'page.upstream.type.ewma': 'EWMA',
+
+  '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 b76e9a5..3049b97 100644
--- a/web/src/pages/Upstream/locales/zh-CN.ts
+++ b/web/src/pages/Upstream/locales/zh-CN.ts
@@ -17,70 +17,69 @@
 export default {
   'page.upstream.step.select.upstream': '选择上游服务',
   'page.upstream.step.select.upstream.select.option': '手动填写',
-  'page.upstream.form.item-label.node.domain.or.ip': '上游节点',
-  'page.upstream.step.backend.server.domain.or.ip': '后端服务域名或 IP',
-  'page.upstream.form.item.extra-message.node.domain.or.ip':
-    '使用域名时,默认解析本地 /etc/resolv.conf;权重为 0 则熔断该节点',
+  '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.port': '端口号',
+  'page.upstream.step.domain.name.or.ip': '主机名或 IP',
+  'page.upstream.step.input.port': '请输入端口',
+  'page.upstream.step.port': '端口',
   'page.upstream.step.input.weight': '请输入权重',
   'page.upstream.step.weight': '权重',
   'page.upstream.step.create': '创建',
   'page.upstream.step.name': '名称',
   'page.upstream.step.name.should.unique': '名称需全局唯一',
-  'page.upstream.step.input.upstream.name': '请输入上游服务名称',
+  'page.upstream.step.input.upstream.name': '请输入上游服务的名称',
   'page.upstream.step.description': '描述',
-  'page.upstream.step.input.description': '请输入上游服务描述',
-  'page.upstream.step.type': '类型',
-  'page.upstream.step.create.node': '增加节点',
+  'page.upstream.step.input.description': '请输入上游服务的描述',
+  'page.upstream.step.type': '负载均衡算法',
+  'page.upstream.step.create.node': '增加目标节点',
   '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.rewrite': '自定义 Host 请求头(即将废弃)',
   'page.upstream.step.pass-host.upstream_host': '自定义 Host 请求头',
   'page.upstream.step.connect.timeout': '连接超时',
+  'page.upstream.step.connect.timeout.desc': '建立从请求到上游服务器的连接的超时时间',
   'page.upstream.step.input.connect.timeout': '请输入连接超时时间',
   'page.upstream.step.send.timeout': '发送超时',
+  'page.upstream.step.send.timeout.desc': '发送数据到上游服务器的超时时间',
   'page.upstream.step.input.send.timeout': '请输入发送超时时间',
   'page.upstream.step.read.timeout': '接收超时',
+  'page.upstream.step.read.timeout.desc': '从上游服务器接收数据的超时时间',
   'page.upstream.step.input.read.timeout': '请输入接收超时时间',
   'page.upstream.step.healthyCheck.healthy.check': '健康检查',
   'page.upstream.step.healthyCheck.healthy': '健康',
   'page.upstream.step.healthyCheck.unhealthy': '不健康',
   'page.upstream.step.healthyCheck.healthy.status': '健康状态',
   'page.upstream.step.healthyCheck.unhealthyStatus': '不健康状态',
-  'page.upstream.step.healthyCheck.active': '主动',
+  '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.input.healthyCheck.active.http_path': '请输入路径',
   'page.upstream.step.healthyCheck.activePort': '端口',
-  'page.upstream.step.input.healthyCheck.activePort': '请输入端口',
+  'page.upstream.step.input.healthyCheck.activePort': '端口',
   'page.upstream.step.healthyCheck.activeHost': '域名',
-  'page.upstream.step.input.healthyCheck.activeHost': '请输入域名',
-  'page.upstream.step.healthyCheck.activeInterval': '间隔',
-  'page.upstream.step.input.healthyCheck.activeInterval': '请输入间隔',
+  '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.healthyCheck.active.create.req_headers': '创建请求头',
+  'page.upstream.step.healthyCheck.active.create.req_headers': '增加请求头',
   '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.create.http_statuses': '创建状态码',
+  'page.upstream.step.healthyCheck.passive': '被动检查',
+  'page.upstream.step.healthyCheck.passive.create.http_statuses': '增加状态码',
   'page.upstream.step.healthyCheck.passive.http_statuses': '状态码',
   'page.upstream.step.input.healthyCheck.passive.http_statuses': '请输入状态码',
-  'page.upstream.step.healthyCheck.passive.tcp_failures': 'tcp失败次数',
-  'page.upstream.step.input.healthyCheck.passive.tcp_failures': '请输入tcp失败次数',
+  'page.upstream.step.healthyCheck.passive.tcp_failures': 'TCP 失败次数',
+  'page.upstream.step.input.healthyCheck.passive.tcp_failures': '请输入 TCP 失败次数',
   'page.upstream.notificationMessage.enableHealthCheckFirst': '请先启用探活健康检查。',
   'page.upstream.upstream_host.required': '请输入自定义 Host 请求头',
 
   'page.upstream.create': '创建上游服务',
-  'page.upstream.configure': '配置上游',
+  'page.upstream.configure': '配置上游服务',
   'page.upstream.create.upstream.successfully': '创建上游服务成功',
   'page.upstream.edit.upstream.successfully': '更新上游服务成功',
   'page.upstream.create.basic.info': '基础信息',
@@ -89,9 +88,9 @@ export default {
   'page.upstream.list.name': '名称',
   'page.upstream.list.type': '类型',
   'page.upstream.list.description': '描述',
-  'page.upstream.list.edit.time': '编辑时间',
+  'page.upstream.list.edit.time': '更新时间',
   'page.upstream.list.operation': '操作',
-  'page.upstream.list.edit': '编辑',
+  'page.upstream.list.edit': '配置',
   'page.upstream.list.confirm.delete': '确定删除该条记录吗?',
   'page.upstream.list.confirm': '确定',
   'page.upstream.list.cancel': '取消',
@@ -100,4 +99,26 @@ export default {
   'page.upstream.list': '上游列表',
   'page.upstream.list.input': '请输入',
   'page.upstream.list.create': '创建',
+
+  'page.upstream.type.roundrobin': '轮询调度(Round Robin)',
+  'page.upstream.type.chash': '一致性哈希(CHash)',
+  'page.upstream.type.ewma': '指数加权移动平均法(EWMA)',
+
+  '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 失败的次数。如果达到此值,则认为上游服务目标节点是不健康的。'
 };

Reply via email to