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

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


The following commit(s) were added to refs/heads/chore-route by this push:
     new 6cf9694  added descriptions for Route fields & move them into small 
part
6cf9694 is described below

commit 6cf9694000575d6b1b7be16f8498999c008bb381
Author: juzhiyuan <[email protected]>
AuthorDate: Wed Apr 7 23:38:54 2021 +0800

    added descriptions for Route fields & move them into small part
---
 docs/en/latest/I18N_USER_GUIDE.md                  |   7 +-
 web/src/components/LabelsfDrawer/LabelsDrawer.tsx  |   4 +-
 web/src/locales/en-US/component.ts                 |   5 +-
 web/src/locales/zh-CN/component.ts                 |   5 +-
 web/src/pages/PluginTemplate/components/Step1.tsx  |   3 +-
 web/src/pages/Route/List.tsx                       |   2 +-
 .../Route/components/Step1/MatchingRulesView.tsx   |  35 +-
 web/src/pages/Route/components/Step1/MetaView.tsx  | 139 +++--
 .../Route/components/Step1/RequestConfigView.tsx   | 627 +++++++++++----------
 web/src/pages/Route/locales/en-US.ts               |   6 +-
 web/src/pages/Route/locales/zh-CN.ts               |  22 +-
 11 files changed, 470 insertions(+), 385 deletions(-)

diff --git a/docs/en/latest/I18N_USER_GUIDE.md 
b/docs/en/latest/I18N_USER_GUIDE.md
index 00f5db3..1bdb051 100644
--- a/docs/en/latest/I18N_USER_GUIDE.md
+++ b/docs/en/latest/I18N_USER_GUIDE.md
@@ -23,13 +23,13 @@ title: i18n User Guide
 
 The Apache APISIX Dashboard uses 
[@umijs/plugin-locale](https://umijs.org/plugins/plugin-locale) to solve the 
i18n issues, in order to make the i18n more clear and reasonable, we would 
recommend to obey the following rules
 
-## Location of locale configuration:
+## Location of locale configuration
 
 - Please put **the global locales** under `src/locales`.
 - Please put **each page's locale file** under `src/pages/$PAGE/locales` 
folder.
 - Please put **the Component's locale file** under 
`src/components/$COMPONENT/locales` folder, and we **MUST** import them manually
 
-## How to name the key for each locale filed:
+## How to name the key for each locale filed
 
 the key can be like this : [basicModule].[moduleName].[elementName].[...desc]
 
@@ -64,7 +64,6 @@ we have already defined many global keys, before you do i18n, 
you can refer to [
 
 ```js
 'page.route.form.itemRulesExtraMessage.parameterName': '仅支持字母和数字,且只能以字母开头',
-'page.route.form.itemLabel.apiName': 'API 名称',
 'page.route.form.itemRulesPatternMessage.apiNameRule': '最大长度100,仅支持字母、数字、- 和 
_,且只能以字母开头',
 ```
 
@@ -101,7 +100,7 @@ we have already defined many global keys, before you do 
i18n, you can refer to [
 **Example:**
 
 ```js
-'page.route.steps.stepTitle.defineApiRequest': '定义 API 请求',
+'page.route.steps.stepTitle.defineApiRequest': '设置路由信息',
 ```
 
 - **Select**
diff --git a/web/src/components/LabelsfDrawer/LabelsDrawer.tsx 
b/web/src/components/LabelsfDrawer/LabelsDrawer.tsx
index 33f5880..9f6ff5b 100644
--- a/web/src/components/LabelsfDrawer/LabelsDrawer.tsx
+++ b/web/src/components/LabelsfDrawer/LabelsDrawer.tsx
@@ -113,7 +113,7 @@ const LabelList = (disabled: boolean, labelList: LabelList, 
filterList: string[]
 };
 
 const LabelsDrawer: React.FC<Props> = ({
-  title = 'Label Manager',
+  title = "",
   actionName = '',
   disabled = false,
   dataSource = [],
@@ -135,7 +135,7 @@ const LabelsDrawer: React.FC<Props> = ({
 
   return (
     <Drawer
-      title={title}
+      title={title || formatMessage({ id: "component.label-manager" })}
       placement="right"
       width={512}
       visible
diff --git a/web/src/locales/en-US/component.ts 
b/web/src/locales/en-US/component.ts
index 55b6a8a..a2969c2 100644
--- a/web/src/locales/en-US/component.ts
+++ b/web/src/locales/en-US/component.ts
@@ -67,10 +67,11 @@ export default {
   'component.global.name': 'Name',
   'component.global.updateTime': 'UpdateAt',
   'component.global.form.itemExtraMessage.nameGloballyUnique': 'Name should be 
globally unique',
-  'component.global.input.placeholder.description': 'Can not more than 256 
characters',
+  'component.global.input.placeholder.description': 'Please enter the 
description for this route, max 256 characters',
   // User component
   'component.user.loginByPassword': 'Username & Password',
   'component.user.login': 'Login',
 
-  'component.document': 'Document'
+  'component.document': 'Document',
+  'component.label-manager': 'Label Manager'
 };
diff --git a/web/src/locales/zh-CN/component.ts 
b/web/src/locales/zh-CN/component.ts
index f4171ec..22b634c 100644
--- a/web/src/locales/zh-CN/component.ts
+++ b/web/src/locales/zh-CN/component.ts
@@ -62,11 +62,12 @@ export default {
   'component.global.steps.stepTitle.pluginConfig': '插件配置',
   'component.global.input.ruleMessage.name': '仅支持字母、数字、- 和 _,且只能以字母开头',
   'component.global.form.itemExtraMessage.nameGloballyUnique': '名称需全局唯一',
-  'component.global.input.placeholder.description': '不超过 256 个字符',
+  'component.global.input.placeholder.description': '请输入路由描述(内容不超过 256 个字符)',
 
   // User component
   'component.user.loginByPassword': '账号密码登录',
   'component.user.login': '登录',
 
-  'component.document': '操作手册'
+  'component.document': '操作手册',
+  'component.label-manager': '标签管理器'
 };
diff --git a/web/src/pages/PluginTemplate/components/Step1.tsx 
b/web/src/pages/PluginTemplate/components/Step1.tsx
index dbeea66..6e46b77 100644
--- a/web/src/pages/PluginTemplate/components/Step1.tsx
+++ b/web/src/pages/PluginTemplate/components/Step1.tsx
@@ -42,7 +42,6 @@ const Step1: React.FC<Props> = ({ form, disabled }) => {
 
   const NormalLabelComponent = () => {
     const field = 'custom_normal_labels';
-    const title = 'Label Manager';
     return (
       <React.Fragment>
         <Form.Item label={formatMessage({ id: 'component.global.labels' })} 
name={field}>
@@ -74,7 +73,7 @@ const Step1: React.FC<Props> = ({ form, disabled }) => {
               const labels = form.getFieldValue(field) || [];
               return (
                 <LabelsDrawer
-                  title={title}
+                  title={formatMessage({ id: "component.label-manager" })}
                   actionName={field}
                   dataSource={labels}
                   disabled={disabled || false}
diff --git a/web/src/pages/Route/List.tsx b/web/src/pages/Route/List.tsx
index ccbfc91..75bddc5 100644
--- a/web/src/pages/Route/List.tsx
+++ b/web/src/pages/Route/List.tsx
@@ -333,7 +333,7 @@ const Page: React.FC = () => {
       dataIndex: 'name',
     },
     {
-      title: formatMessage({ id: 'page.route.domainName' }),
+      title: formatMessage({ id: 'page.route.host' }),
       hideInSearch: true,
       render: (_, record) => {
         const list = record.hosts || (record.host && [record.host]) || [];
diff --git a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx 
b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
index 7216bee..1b01077 100644
--- a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
+++ b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
@@ -22,7 +22,7 @@ import { PanelSection } from '@api7-dashboard/ui';
 const MatchingRulesView: React.FC<RouteModule.Step1PassProps> = ({
   advancedMatchingRules,
   disabled,
-  onChange = () => {},
+  onChange = () => { },
 }) => {
   const [visible, setVisible] = useState(false);
   const [mode, setMode] = useState<RouteModule.ModalType>('CREATE');
@@ -139,28 +139,27 @@ const MatchingRulesView: 
React.FC<RouteModule.Step1PassProps> = ({
     disabled
       ? {}
       : {
-          title: formatMessage({ id: 'component.global.operation' }),
-          key: 'action',
-          render: (_: any, record: RouteModule.MatchingRule) => (
-            <Space size="middle">
-              <a onClick={() => handleEdit(record)}>
-                {formatMessage({ id: 'component.global.edit' })}
-              </a>
-              <a onClick={() => handleRemove(record.key)}>
-                {formatMessage({ id: 'component.global.delete' })}
-              </a>
-            </Space>
-          ),
-        },
+        title: formatMessage({ id: 'component.global.operation' }),
+        key: 'action',
+        render: (_: any, record: RouteModule.MatchingRule) => (
+          <Space size="middle">
+            <a onClick={() => handleEdit(record)}>
+              {formatMessage({ id: 'component.global.edit' })}
+            </a>
+            <a onClick={() => handleRemove(record.key)}>
+              {formatMessage({ id: 'component.global.delete' })}
+            </a>
+          </Space>
+        ),
+      },
   ].filter((item) => Object.keys(item).length);
 
   const renderModal = () => (
     <Modal
-      title={`${
-        mode === 'EDIT'
+      title={`${mode === 'EDIT'
           ? formatMessage({ id: 'component.global.edit' })
           : formatMessage({ id: 'component.global.create' })
-      } ${formatMessage({ id: 'page.route.rule' })}`}
+        } ${formatMessage({ id: 'page.route.rule' })}`}
       centered
       visible
       onOk={onOk}
@@ -277,7 +276,7 @@ const MatchingRulesView: 
React.FC<RouteModule.Step1PassProps> = ({
             marginBottom: 16,
           }}
         >
-          {formatMessage({ id: 'component.global.create' })}
+          {formatMessage({ id: 'component.global.add' })}
         </Button>
       )}
       <Table key="table" bordered dataSource={advancedMatchingRules} 
columns={columns} />
diff --git a/web/src/pages/Route/components/Step1/MetaView.tsx 
b/web/src/pages/Route/components/Step1/MetaView.tsx
index 8bfb2e1..b409180 100644
--- a/web/src/pages/Route/components/Step1/MetaView.tsx
+++ b/web/src/pages/Route/components/Step1/MetaView.tsx
@@ -16,7 +16,7 @@
  */
 import React, { useEffect, useState } from 'react';
 import Form from 'antd/es/form';
-import { Input, Switch, Select, Button, Tag, AutoComplete } from 'antd';
+import { Input, Switch, Select, Button, Tag, AutoComplete, Row, Col } from 
'antd';
 import { useIntl } from 'umi';
 import { PanelSection } from '@api7-dashboard/ui';
 
@@ -30,17 +30,15 @@ const MetaView: React.FC<RouteModule.Step1PassProps> = ({ 
disabled, form, isEdit
   const [labelList, setLabelList] = useState<LabelList>({});
 
   useEffect(() => {
-    // TODO: use a better state name
     fetchLabelList().then(setLabelList);
   }, []);
 
   const NormalLabelComponent = () => {
     const field = 'custom_normal_labels';
-    const title = 'Label Manager';
 
     return (
       <React.Fragment>
-        <Form.Item label={formatMessage({ id: 'component.global.labels' })} 
name={field}>
+        <Form.Item label={formatMessage({ id: 'component.global.labels' })} 
name={field} tooltip="为路由增加自定义标签,可用于路由分组。">
           <Select
             mode="tags"
             style={{ width: '100%' }}
@@ -69,7 +67,7 @@ const MetaView: React.FC<RouteModule.Step1PassProps> = ({ 
disabled, form, isEdit
               const labels = form.getFieldValue(field) || [];
               return (
                 <LabelsDrawer
-                  title={title}
+                  title={formatMessage({ id: "component.label-manager" })}
                   actionName={field}
                   dataSource={labels}
                   disabled={disabled || false}
@@ -88,66 +86,97 @@ const MetaView: React.FC<RouteModule.Step1PassProps> = ({ 
disabled, form, isEdit
 
   const VersionLabelComponent = () => {
     return (
-      <React.Fragment>
-        <Form.Item
-          label={formatMessage({ id: 'component.global.version' })}
-          name="custom_version_label"
-        >
-          <AutoComplete
-            options={(labelList.API_VERSION || []).map((item) => ({ value: 
item }))}
-            disabled={disabled}
-          />
-        </Form.Item>
-      </React.Fragment>
+      <Form.Item
+        label={formatMessage({ id: 'component.global.version' })} 
tooltip="路由的版本号,如 V1">
+        <Row>
+          <Col span={10}>
+            <Form.Item
+              noStyle
+              name="custom_version_label"
+            >
+              <AutoComplete
+                options={(labelList.API_VERSION || []).map((item) => ({ value: 
item }))}
+                disabled={disabled}
+                placeholder="请输入路由版本号"
+              />
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form.Item>
     );
   };
 
+  const Name: React.FC = () => (
+    <Form.Item label={formatMessage({ id: 'component.global.name' })} 
tooltip={formatMessage({ id: 
'page.route.form.itemRulesPatternMessage.apiNameRule' })}>
+      <Row>
+        <Col span={10}>
+          <Form.Item
+            noStyle
+            name="name"
+            rules={[
+              {
+                required: true,
+                message: "请输入路由名称",
+              },
+              {
+                pattern: new RegExp(/^[a-zA-Z][a-zA-Z0-9_-]{0,100}$/, 'g'),
+                message: formatMessage({ id: 
'page.route.form.itemRulesPatternMessage.apiNameRule' }),
+              },
+            ]}
+          >
+            <Input
+              placeholder="请输入路由名称"
+              disabled={disabled}
+            />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
+  const Description: React.FC = () => (
+    <Form.Item label={formatMessage({ id: 'component.global.description' })} 
tooltip="路由的描述信息">
+      <Row>
+        <Col span={10}>
+          <Form.Item noStyle name="desc">
+            <Input.TextArea
+              placeholder={formatMessage({ id: 
'component.global.input.placeholder.description' })}
+              disabled={disabled}
+              showCount
+              maxLength={256}
+            />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
+  const Publish: React.FC = () => (
+    <Form.Item label={formatMessage({ id: 'page.route.publish' })} 
tooltip="用于控制路由创建后,是否立即发布到网关">
+      <Row>
+        <Col>
+          <Form.Item
+            noStyle
+            name="status"
+            valuePropName="checked"
+          >
+            <Switch disabled={isEdit} />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
   return (
     <PanelSection title={formatMessage({ id: 
'page.route.panelSection.title.nameDescription' })}>
-      <Form.Item
-        label={formatMessage({ id: 'component.global.name' })}
-        name="name"
-        rules={[
-          {
-            required: true,
-            message: `${formatMessage({ id: 'component.global.pleaseEnter' })} 
${formatMessage({
-              id: 'page.route.form.itemLabel.apiName',
-            })}`,
-          },
-          {
-            pattern: new RegExp(/^[a-zA-Z][a-zA-Z0-9_-]{0,100}$/, 'g'),
-            message: formatMessage({ id: 
'page.route.form.itemRulesPatternMessage.apiNameRule' }),
-          },
-        ]}
-        extra={formatMessage({ id: 
'page.route.form.itemRulesPatternMessage.apiNameRule' })}
-      >
-        <Input
-          placeholder={`${formatMessage({ id: 'component.global.pleaseEnter' 
})} ${formatMessage({
-            id: 'page.route.form.itemLabel.apiName',
-          })}`}
-          disabled={disabled}
-        />
-      </Form.Item>
+      <Name />
 
       <NormalLabelComponent />
       <VersionLabelComponent />
 
-      <Form.Item label={formatMessage({ id: 'component.global.description' })} 
name="desc">
-        <Input.TextArea
-          placeholder={formatMessage({ id: 
'component.global.input.placeholder.description' })}
-          disabled={disabled}
-          showCount
-          maxLength={256}
-        />
-      </Form.Item>
+      <Description />
+      <Publish />
 
-      <Form.Item
-        label={formatMessage({ id: 'page.route.publish' })}
-        name="status"
-        valuePropName="checked"
-      >
-        <Switch disabled={isEdit} />
-      </Form.Item>
     </PanelSection>
   );
 };
diff --git a/web/src/pages/Route/components/Step1/RequestConfigView.tsx 
b/web/src/pages/Route/components/Step1/RequestConfigView.tsx
index 7ad1631..08c55f8 100644
--- a/web/src/pages/Route/components/Step1/RequestConfigView.tsx
+++ b/web/src/pages/Route/components/Step1/RequestConfigView.tsx
@@ -28,10 +28,16 @@ import {
 } from '@/pages/Route/constants';
 import { fetchServiceList } from '../../service';
 
+const removeBtnStyle = {
+  marginLeft: 20,
+  display: 'flex',
+  alignItems: 'center',
+};
+
 const RequestConfigView: React.FC<RouteModule.Step1PassProps> = ({
   form,
   disabled,
-  onChange = () => {},
+  onChange = () => { },
 }) => {
   const { formatMessage } = useIntl();
   const [serviceList, setServiceList] = 
useState<ServiceModule.ResponseBody[]>([]);
@@ -45,47 +51,47 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
       {(fields, { add, remove }) => {
         return (
           <div>
-            {fields.map((field, index) => (
-              <Form.Item
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={index === 0 && formatMessage({ id: 
'page.route.domainName' })}
-                key={field.key}
-                extra={
-                  index === 0 && formatMessage({ id: 
'page.route.form.itemExtraMessage.domain' })
-                }
-              >
-                <Form.Item
-                  {...field}
-                  validateTrigger={['onChange', 'onBlur']}
-                  rules={[
-                    {
-                      pattern: new RegExp(/(^\*?[a-zA-Z0-9._-]+$|^\*$)/, 'g'),
-                      message: formatMessage({
-                        id: 'page.route.form.itemRulesPatternMessage.domain',
-                      }),
-                    },
-                  ]}
-                  noStyle
-                >
-                  <Input
-                    placeholder={`${formatMessage({
-                      id: 'component.global.pleaseEnter',
-                    })} ${formatMessage({ id: 'page.route.domainName' })}`}
-                    style={{ width: '60%' }}
-                    disabled={disabled}
-                  />
-                </Form.Item>
-                {!disabled && fields.length > 1 ? (
-                  <MinusCircleOutlined
-                    className="dynamic-delete-button"
-                    style={{ margin: '0 8px' }}
-                    onClick={() => {
-                      remove(field.name);
-                    }}
-                  />
-                ) : null}
-              </Form.Item>
-            ))}
+            <Form.Item
+              label={formatMessage({ id: 'page.route.host' })}
+              tooltip={formatMessage({ id: 
'page.route.form.itemExtraMessage.domain' })}
+              style={{ marginBottom: 0 }}
+            >
+              {fields.map((field, index) => (
+                <Row style={{ marginBottom: 10 }} gutter={16} key={index}>
+                  <Col span={10}>
+                    <Form.Item
+                      {...field}
+                      validateTrigger={['onChange', 'onBlur']}
+                      rules={[
+                        {
+                          // NOTE: 
https://github.com/apache/apisix/blob/master/apisix/schema_def.lua#L40
+                          pattern: new RegExp(/^\\*?[0-9a-zA-Z-._]+$/, 'g'),
+                          message: formatMessage({
+                            id: 
'page.route.form.itemRulesPatternMessage.domain',
+                          }),
+                        },
+                      ]}
+                      noStyle
+                    >
+                      <Input
+                        placeholder="请输入 HTTP 请求域名"
+                        disabled={disabled}
+                      />
+                    </Form.Item>
+                  </Col>
+                  <Col style={{ ...removeBtnStyle, marginLeft: -10 }}>
+                    {!disabled && fields.length > 1 ? (
+                      <MinusCircleOutlined
+                        className="dynamic-delete-button"
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    ) : null}
+                  </Col>
+                </Row>
+              ))}
+            </Form.Item>
             {!disabled && (
               <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
                 <Button
@@ -95,7 +101,7 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
                     add();
                   }}
                 >
-                  <PlusOutlined /> {formatMessage({ id: 
'component.global.create' })}
+                  <PlusOutlined /> {formatMessage({ id: 'component.global.add' 
})}
                 </Button>
               </Form.Item>
             )}
@@ -110,61 +116,53 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
       {(fields, { add, remove }) => {
         return (
           <div>
-            {fields.map((field, index) => (
-              <Form.Item
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={index === 0 && formatMessage({ id: 'page.route.path' })}
-                required
-                key={field.key}
-                extra={
-                  index === 0 && (
-                    <div>
-                      {formatMessage({ id: 
'page.route.form.itemExtraMessage1.path' })}
-                      <br />
-                      {formatMessage({ id: 
'page.route.form.itemExtraMessage2.path' })}
-                    </div>
-                  )
-                }
-              >
-                <Form.Item
-                  {...field}
-                  validateTrigger={['onChange', 'onBlur']}
-                  rules={[
-                    {
-                      required: true,
-                      whitespace: true,
-                      message: `${formatMessage({
-                        id: 'component.global.pleaseEnter',
-                      })} ${formatMessage({ id: 'page.route.path' })}`,
-                    },
-                    {
-                      pattern: new 
RegExp(/^\/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$/, 'g'),
-                      message: formatMessage({
-                        id: 'page.route.form.itemRulesPatternMessage.path',
-                      }),
-                    },
-                  ]}
-                  noStyle
-                >
-                  <Input
-                    placeholder={`${formatMessage({
-                      id: 'component.global.pleaseEnter',
-                    })} ${formatMessage({ id: 'page.route.path' })}`}
-                    style={{ width: '60%' }}
-                    disabled={disabled}
-                  />
-                </Form.Item>
-                {!disabled && fields.length > 1 && (
-                  <MinusCircleOutlined
-                    className="dynamic-delete-button"
-                    style={{ margin: '0 8px' }}
-                    onClick={() => {
-                      remove(field.name);
-                    }}
-                  />
-                )}
-              </Form.Item>
-            ))}
+            <Form.Item
+              label={formatMessage({ id: 'page.route.path' })}
+              required
+              tooltip={
+                formatMessage({ id: 'page.route.form.itemExtraMessage1.path' })
+              }
+              style={{ marginBottom: 0 }}
+            >
+              {fields.map((field, index) => (
+                <Row style={{ marginBottom: 10 }} gutter={16} key={index}>
+                  <Col span={10}>
+                    <Form.Item
+                      {...field}
+                      validateTrigger={['onChange', 'onBlur']}
+                      rules={[
+                        {
+                          required: true,
+                          whitespace: true,
+                          message: "请输入有效的 HTTP 请求路径",
+                        },
+                        {
+                          pattern: new 
RegExp(/^\/[a-zA-Z0-9\-._~%!$&'()+,;=:@/]*\*?$/, 'g'),
+                          message: formatMessage({
+                            id: 'page.route.form.itemRulesPatternMessage.path',
+                          }),
+                        },
+                      ]}
+                      noStyle
+                    >
+                      <Input
+                        placeholder="请输入 HTTP 请求路径"
+                        disabled={disabled}
+                      />
+                    </Form.Item>
+                  </Col>
+                  <Col style={{ ...removeBtnStyle, marginLeft: -10 }}>
+                    {!disabled && fields.length > 1 && (
+                      <MinusCircleOutlined
+                        className="dynamic-delete-button"
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    )}</Col>
+                </Row>
+              ))}
+            </Form.Item>
             {!disabled && (
               <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
                 <Button
@@ -174,7 +172,7 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
                     add();
                   }}
                 >
-                  <PlusOutlined /> {formatMessage({ id: 
'component.global.create' })}
+                  <PlusOutlined /> {formatMessage({ id: 'component.global.add' 
})}
                 </Button>
               </Form.Item>
             )}
@@ -189,54 +187,49 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
       {(fields, { add, remove }) => {
         return (
           <div>
-            {fields.map((field, index) => (
-              <Form.Item
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={index === 0 && formatMessage({ id: 
'page.route.remoteAddrs' })}
-                key={field.key}
-                extra={
-                  index === 0 && (
-                    <div>
-                      {formatMessage({ id: 
'page.route.form.itemExtraMessage1.remoteAddrs' })}
-                    </div>
-                  )
-                }
-              >
-                <Form.Item
-                  {...field}
-                  validateTrigger={['onChange', 'onBlur']}
-                  rules={[
-                    {
-                      pattern: new RegExp(
-                        
/^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$|^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}\/[0-9]{1,2}$|^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$|^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?\/[0-9]{1,3}$/,
-                        'g',
-                      ),
-                      message: formatMessage({
-                        id: 
'page.route.form.itemRulesPatternMessage.remoteAddrs',
-                      }),
-                    },
-                  ]}
-                  noStyle
-                >
-                  <Input
-                    placeholder={`${formatMessage({
-                      id: 'component.global.pleaseEnter',
-                    })} ${formatMessage({ id: 'page.route.remoteAddrs' })}`}
-                    style={{ width: '60%' }}
-                    disabled={disabled}
-                  />
-                </Form.Item>
-                {!disabled && fields.length > 1 && (
-                  <MinusCircleOutlined
-                    className="dynamic-delete-button"
-                    style={{ margin: '0 8px' }}
-                    onClick={() => {
-                      remove(field.name);
-                    }}
-                  />
-                )}
-              </Form.Item>
-            ))}
+            <Form.Item
+              label={formatMessage({ id: 'page.route.remoteAddrs' })}
+              tooltip={formatMessage({ id: 
'page.route.form.itemExtraMessage1.remoteAddrs' })}
+              style={{ marginBottom: 0 }}
+            >
+              {fields.map((field, index) => (
+                <Row style={{ marginBottom: 10 }} gutter={16} key={index}>
+                  <Col span={10}>
+                    <Form.Item
+                      {...field}
+                      validateTrigger={['onChange', 'onBlur']}
+                      rules={[
+                        {
+                          pattern: new RegExp(
+                            
/^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$|^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}\/[0-9]{1,2}$|^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?$|^([a-fA-F0-9]{0,4}:){0,8}(:[a-fA-F0-9]{0,4}){0,8}([a-fA-F0-9]{0,4})?\/[0-9]{1,3}$/,
+                            'g',
+                          ),
+                          message: formatMessage({
+                            id: 
'page.route.form.itemRulesPatternMessage.remoteAddrs',
+                          }),
+                        },
+                      ]}
+                      noStyle
+                    >
+                      <Input
+                        placeholder="请输入客户端地址"
+                        disabled={disabled}
+                      />
+                    </Form.Item>
+                  </Col>
+                  <Col style={{ ...removeBtnStyle, marginLeft: -10 }}>
+                    {!disabled && fields.length > 1 && (
+                      <MinusCircleOutlined
+                        className="dynamic-delete-button"
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    )}
+                  </Col>
+                </Row>
+              ))}
+            </Form.Item>
             {!disabled && (
               <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
                 <Button
@@ -246,7 +239,7 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
                     add();
                   }}
                 >
-                  <PlusOutlined /> {formatMessage({ id: 
'component.global.create' })}
+                  <PlusOutlined /> {formatMessage({ id: 'component.global.add' 
})}
                 </Button>
               </Form.Item>
             )}
@@ -256,6 +249,201 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
     </Form.List>
   );
 
+  const HTTPMethods: React.FC = () => (
+    <Form.Item
+      label={formatMessage({ id: 'page.route.form.itemLabel.httpMethod' })}
+    >
+      <Row>
+        <Col span={10}>
+          <Form.Item
+            name="methods"
+            noStyle
+          >
+            <Select
+              mode="multiple"
+              style={{ width: '100%' }}
+              optionLabelProp="label"
+              disabled={disabled}
+              onChange={(value) => {
+                if ((value as string[]).includes('ALL')) {
+                  form.setFieldsValue({
+                    methods: ['ALL'],
+                  });
+                }
+              }}
+            >
+              {['ALL'].concat(HTTP_METHOD_OPTION_LIST).map((item) => {
+                return (
+                  <Select.Option key={item} value={item}>
+                    {item}
+                  </Select.Option>
+                );
+              })}
+            </Select>
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
+  const RoutePriority: React.FC = () => (
+    <Form.Item label={formatMessage({ id: 'page.route.form.itemLabel.priority' 
})}>
+      <Row>
+        <Col span={5}>
+          <Form.Item
+            noStyle
+            name="priority"
+          >
+            <InputNumber
+              placeholder={`Please input ${formatMessage({
+                id: 'page.route.form.itemLabel.priority',
+              })}`}
+              disabled={disabled}
+            />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
+  const WebSocket: React.FC = () => (
+    <Form.Item label="WebSocket">
+      <Row>
+        <Col>
+          <Form.Item noStyle valuePropName="checked" name="enable_websocket">
+            <Switch disabled={disabled} />
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
+  const Redirect: React.FC = () => {
+    const list = [
+      {
+        value: "forceHttps",
+        label: formatMessage({ id: 'page.route.select.option.enableHttps' })
+      }, {
+        value: "customRedirect",
+        label: formatMessage({ id: 'page.route.select.option.configCustom' })
+      }, {
+        value: "disabled",
+        label: formatMessage({ id: 'page.route.select.option.forbidden' })
+      }
+    ]
+
+    return (
+      <Form.Item label={formatMessage({ id: 
'page.route.form.itemLabel.redirect' })}>
+        <Row>
+          <Col span={5}>
+            <Form.Item
+              name="redirectOption"
+              noStyle
+            >
+              <Select
+                disabled={disabled}
+                onChange={(parmas) => {
+                  onChange({ action: 'redirectOptionChange', data: parmas });
+                }}
+              >
+                {list.map(item => (
+                  <Select.Option value={item.value} key={item.value}>
+                    {item.label}
+                  </Select.Option>
+                ))}
+              </Select>
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form.Item>
+    )
+  }
+
+  const CustomRedirect: React.FC = () => (
+    <Form.Item
+      noStyle
+      shouldUpdate={(prev, next) => {
+        if (prev.redirectOption !== next.redirectOption) {
+          onChange({ action: 'redirectOptionChange', data: next.redirectOption 
});
+        }
+        return prev.redirectOption !== next.redirectOption;
+      }}
+    >
+      {() => {
+        if (form.getFieldValue('redirectOption') === 'customRedirect') {
+          return (
+            <Form.Item
+              label={formatMessage({ id: 
'page.route.form.itemLabel.redirectCustom' })}
+              required
+            >
+              <Row gutter={10}>
+                <Col>
+                  <Form.Item
+                    name="redirectURI"
+                    rules={[
+                      {
+                        required: true,
+                        message: `${formatMessage({
+                          id: 'component.global.pleaseEnter',
+                        })}${formatMessage({
+                          id: 'page.route.form.itemLabel.redirectURI',
+                        })}`,
+                      },
+                    ]}
+                  >
+                    <Input
+                      placeholder={formatMessage({
+                        id: 'page.route.input.placeholder.redirectCustom',
+                      })}
+                      disabled={disabled}
+                    />
+                  </Form.Item>
+                </Col>
+                <Col span={10}>
+                  <Form.Item name="ret_code" rules={[{ required: true }]}>
+                    <Select disabled={disabled}>
+                      <Select.Option value={301}>
+                        {formatMessage({ id: 
'page.route.select.option.redirect301' })}
+                      </Select.Option>
+                      <Select.Option value={302}>
+                        {formatMessage({ id: 
'page.route.select.option.redirect302' })}
+                      </Select.Option>
+                    </Select>
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form.Item>
+          );
+        }
+        return null;
+      }}
+    </Form.Item>
+  )
+
+  const ServiceSelector: React.FC = () => (
+    <Form.Item label={formatMessage({ id: 'page.route.service' })}>
+      <Row>
+        <Col span={5}>
+          <Form.Item noStyle name="service_id">
+            <Select disabled={disabled}>
+              {/* TODO: value === '' means  no service_id select, need to find 
a better way */}
+              <Select.Option value="" 
key={Math.random().toString(36).substring(7)}>
+                None
+          </Select.Option>
+              {serviceList.map((item) => {
+                return (
+                  <Select.Option value={item.id} key={item.id}>
+                    {item.name}
+                  </Select.Option>
+                );
+              })}
+            </Select>
+          </Form.Item>
+        </Col>
+      </Row>
+    </Form.Item>
+  )
+
   return (
     <PanelSection
       title={formatMessage({ id: 
'page.route.panelSection.title.requestConfigBasicDefine' })}
@@ -263,141 +451,14 @@ const RequestConfigView: 
React.FC<RouteModule.Step1PassProps> = ({
       <HostList />
       <UriList />
       <RemoteAddrList />
-      <Form.Item
-        label={formatMessage({ id: 'page.route.form.itemLabel.httpMethod' })}
-        name="methods"
-      >
-        <Select
-          mode="multiple"
-          style={{ width: '100%' }}
-          optionLabelProp="label"
-          disabled={disabled}
-          onChange={(value) => {
-            if ((value as string[]).includes('ALL')) {
-              form.setFieldsValue({
-                methods: ['ALL'],
-              });
-            }
-          }}
-        >
-          {['ALL'].concat(HTTP_METHOD_OPTION_LIST).map((item) => {
-            return (
-              <Select.Option key={item} value={item}>
-                {item}
-              </Select.Option>
-            );
-          })}
-        </Select>
-      </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'page.route.form.itemLabel.priority' })}
-        name="priority"
-      >
-        <InputNumber
-          placeholder={`Please input ${formatMessage({
-            id: 'page.route.form.itemLabel.priority',
-          })}`}
-          style={{ width: '60%' }}
-          disabled={disabled}
-        />
-      </Form.Item>
-      <Form.Item label="Websocket" valuePropName="checked" 
name="enable_websocket">
-        <Switch disabled={disabled} />
-      </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'page.route.form.itemLabel.redirect' })}
-        name="redirectOption"
-      >
-        <Select
-          disabled={disabled}
-          onChange={(parmas) => {
-            onChange({ action: 'redirectOptionChange', data: parmas });
-          }}
-        >
-          <Select.Option value="forceHttps">
-            {formatMessage({ id: 'page.route.select.option.enableHttps' })}
-          </Select.Option>
-          <Select.Option value="customRedirect">
-            {formatMessage({ id: 'page.route.select.option.configCustom' })}
-          </Select.Option>
-          <Select.Option value="disabled">
-            {formatMessage({ id: 'page.route.select.option.forbidden' })}
-          </Select.Option>
-        </Select>
-      </Form.Item>
-      <Form.Item
-        noStyle
-        shouldUpdate={(prev, next) => {
-          if (prev.redirectOption !== next.redirectOption) {
-            onChange({ action: 'redirectOptionChange', data: 
next.redirectOption });
-          }
-          return prev.redirectOption !== next.redirectOption;
-        }}
-      >
-        {() => {
-          if (form.getFieldValue('redirectOption') === 'customRedirect') {
-            return (
-              <Form.Item
-                label={formatMessage({ id: 
'page.route.form.itemLabel.redirectCustom' })}
-                required
-              >
-                <Row gutter={10}>
-                  <Col>
-                    <Form.Item
-                      name="redirectURI"
-                      rules={[
-                        {
-                          required: true,
-                          message: `${formatMessage({
-                            id: 'component.global.pleaseEnter',
-                          })}${formatMessage({
-                            id: 'page.route.form.itemLabel.redirectURI',
-                          })}`,
-                        },
-                      ]}
-                    >
-                      <Input
-                        placeholder={formatMessage({
-                          id: 'page.route.input.placeholder.redirectCustom',
-                        })}
-                        disabled={disabled}
-                      />
-                    </Form.Item>
-                  </Col>
-                  <Col span={10}>
-                    <Form.Item name="ret_code" rules={[{ required: true }]}>
-                      <Select disabled={disabled}>
-                        <Select.Option value={301}>
-                          {formatMessage({ id: 
'page.route.select.option.redirect301' })}
-                        </Select.Option>
-                        <Select.Option value={302}>
-                          {formatMessage({ id: 
'page.route.select.option.redirect302' })}
-                        </Select.Option>
-                      </Select>
-                    </Form.Item>
-                  </Col>
-                </Row>
-              </Form.Item>
-            );
-          }
-          return null;
-        }}
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'page.route.service' })} 
name="service_id">
-        <Select disabled={disabled}>
-          {/* TODO: value === '' means  no service_id select, need to find a 
better way */}
-          <Select.Option value="" 
key={Math.random().toString(36).substring(7)}>
-            None
-          </Select.Option>
-          {serviceList.map((item) => {
-            return (
-              <Select.Option value={item.id} key={item.id}>
-                {item.name}
-              </Select.Option>
-            );
-          })}
-        </Select>
-      </Form.Item>
+      <HTTPMethods />
+      <RoutePriority />
+      <WebSocket />
+
+      <Redirect />
+      <CustomRedirect />
+
+      <ServiceSelector />
     </PanelSection>
   );
 };
diff --git a/web/src/pages/Route/locales/en-US.ts 
b/web/src/pages/Route/locales/en-US.ts
index 5d4be8a..c1d8773 100644
--- a/web/src/pages/Route/locales/en-US.ts
+++ b/web/src/pages/Route/locales/en-US.ts
@@ -52,7 +52,6 @@ export default {
   'page.route.panelSection.title.advancedMatchRule': 'Advanced Routing 
Matching Conditions',
 
   'page.route.panelSection.title.nameDescription': 'Name And Description',
-  'page.route.form.itemLabel.apiName': 'API Name',
   'page.route.form.itemRulesPatternMessage.apiNameRule':
     'Maximum length 100, only letters, Numbers, _, and - are supported, and 
can only begin with letters',
 
@@ -78,8 +77,7 @@ export default {
   'page.route.form.itemRulesPatternMessage.domain':
     'Only letters, numbers and * are supported. * can only be at the 
beginning, and only single * is supported',
   'page.route.form.itemExtraMessage1.path':
-    '1. Request path, for example: /foo/index.html, supports request path 
prefix /foo/* ;',
-  'page.route.form.itemExtraMessage2.path': '2. /* represents all paths',
+    'HTTP Request path, for example: /foo/index.html, supports request path 
prefix /foo/* ; /* represents all paths',
   'page.route.form.itemRulesPatternMessage.path': 'Begin with / , and * can 
only at the end',
   'page.route.form.itemRulesPatternMessage.remoteAddrs':
     'Please enter a valid IP address, for example: 192.168.1.101, 
192.168.1.0/24, ::1, fe80::1, fe80::1/64',
@@ -124,7 +122,7 @@ export default {
   'page.route.form.itemHelp.status':
     'Whether a route can be used after it is created, the default value is 
false.',
 
-  'page.route.domainName': 'Domain Name',
+  'page.route.host': 'Host',
   'page.route.path': 'Path',
   'page.route.remoteAddrs': 'Remote Addrs',
   'page.route.PanelSection.title.defineRequestParams': 'Define Request 
Parameters',
diff --git a/web/src/pages/Route/locales/zh-CN.ts 
b/web/src/pages/Route/locales/zh-CN.ts
index 54410b2..ec48bde 100644
--- a/web/src/pages/Route/locales/zh-CN.ts
+++ b/web/src/pages/Route/locales/zh-CN.ts
@@ -28,7 +28,7 @@ export default {
   'page.route.regexMatch': '正则匹配',
   'page.route.in': 'IN',
   'page.route.rule': '规则',
-  'page.route.domainName': '域名',
+  'page.route.host': '域名',
   'page.route.path': '路径',
   'page.route.remoteAddrs': '客户端地址',
   'page.route.value': '参数值',
@@ -61,9 +61,8 @@ export default {
   'page.route.input.placeholder.paramValue': '参数值',
   // form
   'page.route.form.itemRulesRequiredMessage.parameterName': 
'仅支持字母和数字,且只能以字母开头',
-  'page.route.form.itemLabel.apiName': 'API 名称',
   'page.route.form.itemRulesPatternMessage.apiNameRule':
-    '最大长度100,仅支持字母、数字、- 和 _,且只能以字母开头',
+    '路由的名称,最大长度100,仅支持字母、数字、- 和 _,且只能以字母开头',
   'page.route.form.itemLabel.httpMethod': 'HTTP 方法',
   'page.route.form.itemLabel.scheme': '协议',
   'page.route.form.itemLabel.priority': '优先级',
@@ -73,15 +72,14 @@ export default {
   'page.route.form.itemLabel.hostRewriteType': '域名改写',
   'page.route.form.itemLabel.headerRewrite': '请求头改写',
   'page.route.form.itemLabel.redirectURI': '重定向路径',
-  'page.route.form.itemExtraMessage.domain': '域名或IP,支持泛域名,如:*.test.com',
+  'page.route.form.itemExtraMessage.domain': '路由匹配的域名列表。支持泛域名,如:*.test.com',
   'page.route.form.itemRulesPatternMessage.domain':
     '仅支持字母、数字和 * ,且 * 只能是在开头,支持单个 * ',
   'page.route.form.itemExtraMessage1.path':
-    '1. 请求路径,如 /foo/index.html,支持请求路径前缀 /foo/* ;',
-  'page.route.form.itemExtraMessage2.path': '2. /* 代表所有路径',
+    'HTTP 请求路径,如 /foo/index.html,支持请求路径前缀 /foo/*。/* 代表所有路径',
   'page.route.form.itemRulesPatternMessage.path': '以 / 开头,且 * 只能在最后',
   'page.route.form.itemExtraMessage1.remoteAddrs':
-    '客户端 IP,例如:192.168.1.101,192.168.1.0/24,::1,fe80::1,fe80::1/64',
+    '客户端与服务器握手时 IP,即客户端 
IP,例如:192.168.1.101,192.168.1.0/24,::1,fe80::1,fe80::1/64',
   'page.route.form.itemRulesPatternMessage.remoteAddrs':
     '请输入合法的 IP 地址,例如:192.168.1.101,192.168.1.0/24,::1,fe80::1,fe80::1/64',
   'page.route.form.itemLabel.username': '用户名',
@@ -98,15 +96,15 @@ export default {
   'page.route.select.option.inputManually': '手动填写',
 
   // steps
-  'page.route.steps.stepTitle.defineApiRequest': '定义 API 请求',
-  'page.route.steps.stepTitle.defineApiBackendServe': '定义 API 后端服务',
+  'page.route.steps.stepTitle.defineApiRequest': '设置路由信息',
+  'page.route.steps.stepTitle.defineApiBackendServe': '设置上游服务',
 
   // panelSection
-  'page.route.panelSection.title.nameDescription': '名称及其描述',
+  'page.route.panelSection.title.nameDescription': '基本信息',
   'page.route.panelSection.title.httpOverrideRequestHeader': 'HTTP 请求头改写',
   'page.route.panelSection.title.requestOverride': '请求改写',
-  'page.route.panelSection.title.requestConfigBasicDefine': '请求基础定义',
-  'page.route.panelSection.title.advancedMatchRule': '高级路由匹配条件',
+  'page.route.panelSection.title.requestConfigBasicDefine': '匹配条件',
+  'page.route.panelSection.title.advancedMatchRule': '高级匹配条件',
   'page.route.PanelSection.title.defineRequestParams': '请求参数定义',
   'page.route.PanelSection.title.responseResult': '请求响应结果',
 

Reply via email to