You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2020/10/10 09:20:44 UTC

[apisix-dashboard] 01/01: feat(Upstream): added components

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

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

commit 1cb617272d7238dff44ef4cbcce60322b92f1174
Author: juzhiyuan <ju...@apache.org>
AuthorDate: Sat Oct 10 17:20:17 2020 +0800

    feat(Upstream): added components
---
 src/components/Upstream/UpstreamForm.tsx | 601 +++++++++++++++++++++++++++++
 src/components/Upstream/index.ts         |   1 +
 src/pages/Upstream/components/Step1.tsx  | 624 +------------------------------
 3 files changed, 607 insertions(+), 619 deletions(-)

diff --git a/src/components/Upstream/UpstreamForm.tsx b/src/components/Upstream/UpstreamForm.tsx
new file mode 100644
index 0000000..fe6df1e
--- /dev/null
+++ b/src/components/Upstream/UpstreamForm.tsx
@@ -0,0 +1,601 @@
+import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
+import { Button, Col, Divider, Form, Input, InputNumber, Row, Select, Switch } from 'antd';
+import React, { useEffect, useState } from 'react';
+import { useIntl } from 'umi';
+
+import { PanelSection } from '@api7-dashboard/ui';
+
+enum Type {
+  roundrobin = 'roundrobin',
+  chash = 'chash',
+}
+
+enum HashOn {
+  vars = 'vars',
+  header = 'header',
+  cookie = 'cookie',
+  consumer = 'consumer',
+}
+
+enum HashKey {
+  remote_addr = 'remote_addr',
+  host = 'host',
+  uri = 'uri',
+  server_name = 'server_name',
+  server_addr = 'server_addr',
+  request_uri = 'request_uri',
+  query_string = 'query_string',
+  remote_port = 'remote_port',
+  hostname = 'hostname',
+  arg_id = 'arg_id',
+}
+
+type Upstream = {};
+
+type Props = {
+  upstream?: Upstream;
+  id?: string;
+};
+
+const timeoutFields = [
+  {
+    label: '连接超时',
+    name: ['timeout', 'connect'],
+  },
+  {
+    label: '发送超时',
+    name: ['timeout', 'send'],
+  },
+  {
+    label: '接收超时',
+    name: ['timeout', 'read'],
+  },
+];
+
+const UpstreamForm: React.FC<Props> = ({ id }) => {
+  const [readonly] = useState(false);
+  const [form] = Form.useForm();
+  const { formatMessage } = useIntl();
+
+  useEffect(() => {
+    // TODO: 获取 upstream 列表
+  }, []);
+
+  useEffect(() => {
+    if (id) {
+      // TODO: 获取 upstream、设置 readonly、填充数据
+    }
+  }, [id]);
+
+  const CHash = () => (
+    <>
+      <Form.Item label="Hash On" name="hash_on" rules={[{ required: true }]}>
+        <Select disabled={readonly}>
+          {Object.entries(HashOn).map(([label, value]) => (
+            <Select.Option value={value} key={value}>
+              {label}
+            </Select.Option>
+          ))}
+        </Select>
+      </Form.Item>
+      <Form.Item label="Key" name="key" rules={[{ required: true }]}>
+        <Select disabled={readonly}>
+          {Object.entries(HashKey).map(([label, value]) => (
+            <Select.Option value={value} key={value}>
+              {label}
+            </Select.Option>
+          ))}
+        </Select>
+      </Form.Item>
+    </>
+  );
+
+  const TimeUnit = () => <span style={{ margin: '0 8px' }}>ms</span>;
+  const NodeList = () => (
+    <Form.List name="nodes">
+      {(fields, { add, remove }) => (
+        <>
+          {fields.map((field, index) => (
+            <Form.Item
+              required
+              key={field.key}
+              label={index === 0 && '节点域名/IP'}
+              extra={
+                index === 0 && '使用域名时,默认解析本地 /etc/resolv.conf;权重为0则熔断该节点'
+              }
+              labelCol={{ span: index === 0 ? 3 : 0 }}
+              wrapperCol={{ offset: index === 0 ? 0 : 3 }}
+            >
+              <Row style={{ marginBottom: '10px' }} gutter={16}>
+                <Col span={5}>
+                  <Form.Item
+                    style={{ marginBottom: 0 }}
+                    name={[field.name, 'host']}
+                    rules={[
+                      {
+                        required: true,
+                      },
+                      {
+                        pattern: new RegExp(
+                          /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/,
+                          'g',
+                        ),
+                      },
+                    ]}
+                  >
+                    <Input placeholder="域名/IP" disabled={readonly} />
+                  </Form.Item>
+                </Col>
+                <Col span={2}>
+                  <Form.Item
+                    style={{ marginBottom: 0 }}
+                    name={[field.name, 'port']}
+                    rules={[
+                      {
+                        required: true,
+                      },
+                    ]}
+                  >
+                    <InputNumber placeholder="端口号" disabled={readonly} min={1} max={65535} />
+                  </Form.Item>
+                </Col>
+                <Col span={2}>
+                  <Form.Item
+                    style={{ marginBottom: 0 }}
+                    name={[field.name, 'weight']}
+                    rules={[
+                      {
+                        required: true,
+                      },
+                    ]}
+                  >
+                    <InputNumber placeholder="权重" disabled={readonly} min={0} max={1000} />
+                  </Form.Item>
+                </Col>
+                <Col
+                  style={{
+                    marginLeft: -10,
+                    display: 'flex',
+                    alignItems: 'center',
+                  }}
+                >
+                  {!readonly && fields.length > 1 && (
+                    <MinusCircleOutlined onClick={() => remove(field.name)} />
+                  )}
+                </Col>
+              </Row>
+            </Form.Item>
+          ))}
+          {!readonly && (
+            <Form.Item wrapperCol={{ offset: 3 }}>
+              <Button type="dashed" onClick={add}>
+                <PlusOutlined />
+                创建节点
+              </Button>
+            </Form.Item>
+          )}
+        </>
+      )}
+    </Form.List>
+  );
+
+  const ActiveHealthCheck = () => (
+    <>
+      <Form.Item label="超时时间">
+        <Form.Item name={['checks', 'active', 'timeout']} noStyle>
+          <InputNumber disabled={readonly} />
+        </Form.Item>
+        <span style={{ margin: '0 8px' }}>s</span>
+      </Form.Item>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.active.http_path' })}
+        required
+      >
+        <Form.Item
+          name={['checks', 'active', 'http_path']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.http_path' }),
+            },
+          ]}
+        >
+          <Input
+            disabled={readonly}
+            placeholder={formatMessage({
+              id: 'upstream.step.input.healthy.checks.active.http_path',
+            })}
+          />
+        </Form.Item>
+      </Form.Item>
+      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.active.host' })} required>
+        <Form.Item
+          style={{ marginBottom: 0 }}
+          name={['checks', 'active', 'host']}
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.host' }),
+            },
+            {
+              pattern: new RegExp(
+                /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/,
+                'g',
+              ),
+              message: formatMessage({ id: 'upstream.step.domain.name.or.ip.rule' }),
+            },
+          ]}
+        >
+          <Input
+            placeholder={formatMessage({ id: 'upstream.step.input.healthy.checks.active.host' })}
+            disabled={readonly}
+          />
+        </Form.Item>
+      </Form.Item>
+
+      <Divider orientation="left" plain>
+        健康状态
+      </Divider>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.active.interval' })}
+        required
+      >
+        <Form.Item
+          style={{ marginBottom: 0 }}
+          name={['checks', 'active', 'healthy', 'interval']}
+          rules={[
+            {
+              required: true,
+              message: formatMessage({
+                id: 'upstream.step.input.healthy.checks.active.interval',
+              }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} />
+        </Form.Item>
+      </Form.Item>
+      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.successes' })} required>
+        <Form.Item
+          name={['checks', 'active', 'healthy', 'successes']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.healthy.checks.successes' }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} max={254} />
+        </Form.Item>
+      </Form.Item>
+
+      <Divider orientation="left" plain>
+        不健康状态
+      </Divider>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.active.interval' })}
+        required
+      >
+        <Form.Item
+          name={['checks', 'active', 'unhealthy', 'interval']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({
+                id: 'upstream.step.input.healthy.checks.active.interval',
+              }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} />
+        </Form.Item>
+      </Form.Item>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.http_failures' })}
+        required
+      >
+        <Form.Item
+          name={['checks', 'active', 'unhealthy', 'http_failures']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.healthy.checks.http_failures' }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} max={254} />
+        </Form.Item>
+      </Form.Item>
+      <Form.List name={['checks', 'active', 'req_headers']}>
+        {(fields, { add, remove }) => (
+          <>
+            {fields.map((field, index) => (
+              <Form.Item
+                key={field.key}
+                label={
+                  index === 0 &&
+                  formatMessage({ id: 'upstream.step.healthy.checks.active.req_headers' })
+                }
+                wrapperCol={{ offset: index === 0 ? 0 : 3 }}
+              >
+                <Row style={{ marginBottom: '10px' }} gutter={16}>
+                  <Col span={10}>
+                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
+                      <Input
+                        placeholder={formatMessage({
+                          id: 'upstream.step.input.healthy.checks.active.req_headers',
+                        })}
+                        disabled={readonly}
+                      />
+                    </Form.Item>
+                  </Col>
+                  <Col
+                    style={{
+                      marginLeft: -10,
+                      display: 'flex',
+                      alignItems: 'center',
+                    }}
+                  >
+                    {!readonly && fields.length > 1 && (
+                      <MinusCircleOutlined
+                        style={{ margin: '0 8px' }}
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    )}
+                  </Col>
+                </Row>
+              </Form.Item>
+            ))}
+            {!readonly && (
+              <Form.Item wrapperCol={{ offset: 3 }}>
+                <Button type="dashed" onClick={() => add()}>
+                  <PlusOutlined />
+                  创建请求头
+                </Button>
+              </Form.Item>
+            )}
+          </>
+        )}
+      </Form.List>
+    </>
+  );
+  const InActiveHealthCheck = () => (
+    <>
+      <Divider orientation="left" plain>
+        健康状态
+      </Divider>
+      <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: 'upstream.step.healthy.checks.passive.http_statuses' })
+                }
+                labelCol={{ span: index === 0 ? 3 : 0 }}
+                wrapperCol={{ offset: index === 0 ? 0 : 3 }}
+              >
+                <Row style={{ marginBottom: '10px' }}>
+                  <Col span={2}>
+                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
+                      <InputNumber disabled={readonly} />
+                    </Form.Item>
+                  </Col>
+                  <Col
+                    style={{
+                      marginLeft: -10,
+                      display: 'flex',
+                      alignItems: 'center',
+                    }}
+                  >
+                    {!readonly && fields.length > 1 && (
+                      <MinusCircleOutlined
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    )}
+                  </Col>
+                </Row>
+              </Form.Item>
+            ))}
+            {!readonly && (
+              <Form.Item wrapperCol={{ offset: 3 }}>
+                <Button type="dashed" onClick={() => add()}>
+                  <PlusOutlined />
+                  创建状态码
+                </Button>
+              </Form.Item>
+            )}
+          </>
+        )}
+      </Form.List>
+      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.successes' })} required>
+        <Form.Item
+          name={['checks', 'passive', 'healthy', 'successes']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.receive.timeout' }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} max={254} />
+        </Form.Item>
+      </Form.Item>
+
+      <Divider orientation="left" plain>
+        不健康状态
+      </Divider>
+      <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: 'upstream.step.healthy.checks.passive.http_statuses' })
+                }
+                labelCol={{ span: index === 0 ? 3 : 0 }}
+                wrapperCol={{ offset: index === 0 ? 0 : 3 }}
+              >
+                <Row style={{ marginBottom: '10px' }}>
+                  <Col span={2}>
+                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
+                      <InputNumber disabled={readonly} max={599} />
+                    </Form.Item>
+                  </Col>
+                  <Col
+                    style={{
+                      marginLeft: -10,
+                      display: 'flex',
+                      alignItems: 'center',
+                    }}
+                  >
+                    {!readonly && fields.length > 1 && (
+                      <MinusCircleOutlined
+                        onClick={() => {
+                          remove(field.name);
+                        }}
+                      />
+                    )}
+                  </Col>
+                </Row>
+              </Form.Item>
+            ))}
+            {!readonly && (
+              <Form.Item wrapperCol={{ offset: 3 }}>
+                <Button type="dashed" onClick={() => add()}>
+                  <PlusOutlined />
+                  创建状态码
+                </Button>
+              </Form.Item>
+            )}
+          </>
+        )}
+      </Form.List>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.http_failures' })}
+        required
+      >
+        <Form.Item
+          name={['checks', 'passive', 'unhealthy', 'http_failures']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'upstream.step.input.healthy.checks.http_failures' }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} max={254} />
+        </Form.Item>
+      </Form.Item>
+      <Form.Item
+        label={formatMessage({ id: 'upstream.step.healthy.checks.passive.tcp_failures' })}
+        required
+      >
+        <Form.Item
+          name={['checks', 'passive', 'unhealthy', 'tcp_failures']}
+          noStyle
+          rules={[
+            {
+              required: true,
+              message: formatMessage({
+                id: 'upstream.step.input.healthy.checks.passive.tcp_failures',
+              }),
+            },
+          ]}
+        >
+          <InputNumber disabled={readonly} min={1} max={254} />
+        </Form.Item>
+      </Form.Item>
+    </>
+  );
+
+  return (
+    <Form form={form} labelCol={{ span: 3 }}>
+      <Form.Item label="类型" name="type" rules={[{ required: true }]}>
+        <Select disabled={readonly}>
+          {Object.entries(Type).map(([label, value]) => {
+            return (
+              <Select.Option value={value} key={value}>
+                {label}
+              </Select.Option>
+            );
+          })}
+        </Select>
+      </Form.Item>
+      <Form.Item shouldUpdate noStyle>
+        {() => {
+          if (form.getFieldValue('type') === 'chash') {
+            return <CHash />;
+          }
+          return null;
+        }}
+      </Form.Item>
+
+      <NodeList />
+
+      {timeoutFields.map(({ label, name }) => (
+        <Form.Item label={label} required key={label}>
+          <Form.Item
+            name={name}
+            noStyle
+            rules={[
+              {
+                required: true,
+              },
+            ]}
+          >
+            <InputNumber disabled={readonly} />
+          </Form.Item>
+          <TimeUnit />
+        </Form.Item>
+      ))}
+
+      <PanelSection title="健康检查">
+        {[
+          {
+            label: '探活健康检查',
+            name: ['checks', 'active'],
+            component: <ActiveHealthCheck />,
+          },
+          {
+            label: '被动健康检查',
+            name: ['checks', 'passive'],
+            component: <InActiveHealthCheck />,
+          },
+        ].map(({ label, name, component }) => (
+          <>
+            <Form.Item label={label} name={name} valuePropName="checked" key={label}>
+              <Switch disabled={readonly} />
+            </Form.Item>
+            <Form.Item shouldUpdate noStyle>
+              {() => {
+                if (form.getFieldValue(name)) {
+                  return component;
+                }
+                return null;
+              }}
+            </Form.Item>
+          </>
+        ))}
+      </PanelSection>
+    </Form>
+  );
+};
+
+export default UpstreamForm;
diff --git a/src/components/Upstream/index.ts b/src/components/Upstream/index.ts
new file mode 100644
index 0000000..677668e
--- /dev/null
+++ b/src/components/Upstream/index.ts
@@ -0,0 +1 @@
+export { default } from './UpstreamForm';
diff --git a/src/pages/Upstream/components/Step1.tsx b/src/pages/Upstream/components/Step1.tsx
index da70c23..e1a457c 100644
--- a/src/pages/Upstream/components/Step1.tsx
+++ b/src/pages/Upstream/components/Step1.tsx
@@ -15,19 +15,11 @@
  * limitations under the License.
  */
 import React from 'react';
-import { Form, Input, Row, Col, InputNumber, Select, Switch, notification } from 'antd';
+import { Form, Input } from 'antd';
 import { FormInstance } from 'antd/lib/form';
 import { useIntl } from 'umi';
 
-import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
-import Button from 'antd/es/button';
-import {
-  FORM_ITEM_WITHOUT_LABEL,
-  FORM_ITEM_LAYOUT,
-  HASH_KEY_LIST,
-  HASH_ON_LIST,
-} from '@/pages/Upstream/constants';
-import { PanelSection } from '@api7-dashboard/ui';
+import UpstreamForm from '@/components/Upstream';
 
 type Props = {
   form: FormInstance;
@@ -78,518 +70,11 @@ const initialValues = {
   },
 };
 
-const Step1: React.FC<Props> = ({ form, disabled, isActive, onChange, isPassive }) => {
+const Step1: React.FC<Props> = ({ form, disabled }) => {
   const { formatMessage } = useIntl();
 
-  const renderUpstreamMeta = () => (
-    <Form.List name="nodes">
-      {(fields, { add, remove }) => (
-        <>
-          {fields.map((field, index) => (
-            <Form.Item
-              required
-              key={field.key}
-              {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-              label={
-                index === 0
-                  ? formatMessage({ id: 'upstream.step.backend.server.domain.or.ip' })
-                  : ''
-              }
-              extra={
-                index === 0
-                  ? formatMessage({ id: 'upstream.step.domain.name.default.analysis' })
-                  : ''
-              }
-            >
-              <Row style={{ marginBottom: '10px' }} gutter={16}>
-                <Col span={5}>
-                  <Form.Item
-                    style={{ marginBottom: 0 }}
-                    name={[field.name, 'host']}
-                    rules={[
-                      {
-                        required: true,
-                        message: formatMessage({ id: 'upstream.step.input.domain.name.or.ip' }),
-                      },
-                      {
-                        pattern: new RegExp(
-                          /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/,
-                          'g',
-                        ),
-                        message: formatMessage({ id: 'upstream.step.domain.name.or.ip.rule' }),
-                      },
-                    ]}
-                  >
-                    <Input
-                      placeholder={formatMessage({ id: 'upstream.step.domain.name.or.ip' })}
-                      disabled={disabled}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={3}>
-                  <Form.Item
-                    style={{ marginBottom: 0 }}
-                    name={[field.name, 'port']}
-                    rules={[
-                      {
-                        required: true,
-                        message: formatMessage({ id: 'upstream.step.input.port' }),
-                      },
-                    ]}
-                  >
-                    <InputNumber
-                      placeholder={formatMessage({ id: 'upstream.step.port' })}
-                      disabled={disabled}
-                      min={1}
-                      max={65535}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col span={3}>
-                  <Form.Item
-                    style={{ marginBottom: 0 }}
-                    name={[field.name, 'weight']}
-                    rules={[
-                      {
-                        required: true,
-                        message: formatMessage({ id: 'upstream.step.input.weight' }),
-                      },
-                    ]}
-                  >
-                    <InputNumber
-                      placeholder={formatMessage({ id: 'upstream.step.weight' })}
-                      disabled={disabled}
-                      min={0}
-                      max={1000}
-                    />
-                  </Form.Item>
-                </Col>
-                <Col
-                  style={{
-                    marginLeft: -10,
-                    display: 'flex',
-                    alignItems: 'center',
-                  }}
-                >
-                  {!disabled &&
-                    (fields.length > 1 ? (
-                      <MinusCircleOutlined
-                        style={{ margin: '0 8px' }}
-                        onClick={() => {
-                          remove(field.name);
-                        }}
-                      />
-                    ) : null)}
-                </Col>
-              </Row>
-            </Form.Item>
-          ))}
-          {!disabled && (
-            <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
-              <Button
-                type="dashed"
-                onClick={() => {
-                  add();
-                }}
-              >
-                <PlusOutlined />
-                {formatMessage({ id: 'upstream.step.create' })}
-              </Button>
-            </Form.Item>
-          )}
-        </>
-      )}
-    </Form.List>
-  );
-
-  const renderTimeUnit = () => <span style={{ margin: '0 8px' }}>ms</span>;
-
-  const handleActiveChange = () => {
-    if (isActive) {
-      onChange(!isActive, false);
-      form.setFieldsValue({ ...form.getFieldsValue(), passive: false });
-      return;
-    }
-    onChange(!isActive, isPassive);
-    form.setFieldsValue({ ...form.getFieldsValue(), active: !isActive });
-  };
-  const handlePassiveChange = () => {
-    if (!isActive) {
-      notification.warning({
-        message: formatMessage({ id: 'upstream.notificationMessage.enableHealthCheckFirst' }),
-      });
-      form.setFieldsValue({ ...form.getFieldsValue(), passive: isPassive });
-      return;
-    }
-    onChange(isActive, !isPassive);
-    form.setFieldsValue({ ...form.getFieldsValue(), passive: !isPassive });
-  };
-
-  const renderPassiveHealthyCheck = () => (
-    <>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.healthy' })} />
-      <Form.List name={['checks', 'passive', 'healthy', 'http_statuses']}>
-        {(fields, { add, remove }) => (
-          <>
-            {fields.map((field, index) => (
-              <Form.Item
-                required
-                key={field.key}
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={
-                  index === 0
-                    ? formatMessage({ id: 'upstream.step.healthy.checks.passive.http_statuses' })
-                    : ''
-                }
-              >
-                <Row style={{ marginBottom: '10px' }} gutter={16}>
-                  <Col span={4}>
-                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
-                      <InputNumber
-                        placeholder={formatMessage({
-                          id: 'upstream.step.input.healthy.checks.passive.http_statuses',
-                        })}
-                        disabled={disabled}
-                      />
-                    </Form.Item>
-                  </Col>
-                  <Col
-                    style={{
-                      marginLeft: -10,
-                      display: 'flex',
-                      alignItems: 'center',
-                    }}
-                  >
-                    {!disabled &&
-                      (fields.length > 1 ? (
-                        <MinusCircleOutlined
-                          style={{ margin: '0 8px' }}
-                          onClick={() => {
-                            remove(field.name);
-                          }}
-                        />
-                      ) : null)}
-                  </Col>
-                </Row>
-              </Form.Item>
-            ))}
-            {!disabled && (
-              <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
-                <Button
-                  type="dashed"
-                  onClick={() => {
-                    add();
-                  }}
-                >
-                  <PlusOutlined />
-                  {formatMessage({ id: 'upstream.step.create' })}
-                </Button>
-              </Form.Item>
-            )}
-          </>
-        )}
-      </Form.List>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.successes' })} required>
-        <Form.Item
-          name={['checks', 'passive', 'healthy', 'successes']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.receive.timeout' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} max={254} />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.unhealthy' })} />
-      <Form.List name={['checks', 'passive', 'unhealthy', 'http_statuses']}>
-        {(fields, { add, remove }) => (
-          <>
-            {fields.map((field, index) => (
-              <Form.Item
-                required
-                key={field.key}
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={
-                  index === 0
-                    ? formatMessage({ id: 'upstream.step.healthy.checks.passive.http_statuses' })
-                    : ''
-                }
-              >
-                <Row style={{ marginBottom: '10px' }} gutter={16}>
-                  <Col span={4}>
-                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
-                      <InputNumber
-                        placeholder={formatMessage({
-                          id: 'upstream.step.input.healthy.checks.passive.http_statuses',
-                        })}
-                        disabled={disabled}
-                        max={599}
-                      />
-                    </Form.Item>
-                  </Col>
-                  <Col
-                    style={{
-                      marginLeft: -10,
-                      display: 'flex',
-                      alignItems: 'center',
-                    }}
-                  >
-                    {!disabled &&
-                      (fields.length > 1 ? (
-                        <MinusCircleOutlined
-                          style={{ margin: '0 8px' }}
-                          onClick={() => {
-                            remove(field.name);
-                          }}
-                        />
-                      ) : null)}
-                  </Col>
-                </Row>
-              </Form.Item>
-            ))}
-            {!disabled && (
-              <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
-                <Button
-                  type="dashed"
-                  onClick={() => {
-                    add();
-                  }}
-                >
-                  <PlusOutlined />
-                  {formatMessage({ id: 'upstream.step.create' })}
-                </Button>
-              </Form.Item>
-            )}
-          </>
-        )}
-      </Form.List>
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.http_failures' })}
-        required
-      >
-        <Form.Item
-          name={['checks', 'passive', 'unhealthy', 'http_failures']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.http_failures' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} max={254} />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.passive.tcp_failures' })}
-        required
-      >
-        <Form.Item
-          name={['checks', 'passive', 'unhealthy', 'tcp_failures']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({
-                id: 'upstream.step.input.healthy.checks.passive.tcp_failures',
-              }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} max={254} />
-        </Form.Item>
-      </Form.Item>
-    </>
-  );
-
-  const renderActiveHealthyCheck = () => (
-    <>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.active.timeout' })}>
-        <Form.Item name={['checks', 'active', 'timeout']} noStyle>
-          <InputNumber disabled={disabled} />
-        </Form.Item>
-        <span style={{ margin: '0 8px' }}>s</span>
-      </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.active.http_path' })}
-        required
-      >
-        <Form.Item
-          name={['checks', 'active', 'http_path']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.http_path' }),
-            },
-          ]}
-        >
-          <Input
-            disabled={disabled}
-            placeholder={formatMessage({
-              id: 'upstream.step.input.healthy.checks.active.http_path',
-            })}
-          />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.active.host' })} required>
-        <Form.Item
-          style={{ marginBottom: 0 }}
-          name={['checks', 'active', 'host']}
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.host' }),
-            },
-            {
-              pattern: new RegExp(
-                /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/,
-                'g',
-              ),
-              message: formatMessage({ id: 'upstream.step.domain.name.or.ip.rule' }),
-            },
-          ]}
-        >
-          <Input
-            placeholder={formatMessage({ id: 'upstream.step.input.healthy.checks.active.host' })}
-            disabled={disabled}
-          />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.healthy' })} />
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.active.interval' })}
-        required
-      >
-        <Form.Item
-          style={{ marginBottom: 0 }}
-          name={['checks', 'active', 'healthy', 'interval']}
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.interval' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.successes' })} required>
-        <Form.Item
-          name={['checks', 'active', 'healthy', 'successes']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.successes' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} max={254} />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.healthy.checks.unhealthy' })} />
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.active.interval' })}
-        required
-      >
-        <Form.Item
-          name={['checks', 'active', 'unhealthy', 'interval']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.active.interval' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} />
-        </Form.Item>
-      </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.healthy.checks.http_failures' })}
-        required
-      >
-        <Form.Item
-          name={['checks', 'active', 'unhealthy', 'http_failures']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.healthy.checks.http_failures' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} min={1} max={254} />
-        </Form.Item>
-      </Form.Item>
-      <Form.List name={['checks', 'active', 'req_headers']}>
-        {(fields, { add, remove }) => (
-          <>
-            {fields.map((field, index) => (
-              <Form.Item
-                key={field.key}
-                {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-                label={
-                  index === 0
-                    ? formatMessage({ id: 'upstream.step.healthy.checks.active.req_headers' })
-                    : ''
-                }
-              >
-                <Row style={{ marginBottom: '10px' }} gutter={16}>
-                  <Col span={10}>
-                    <Form.Item style={{ marginBottom: 0 }} name={[field.name]}>
-                      <Input
-                        placeholder={formatMessage({
-                          id: 'upstream.step.input.healthy.checks.active.req_headers',
-                        })}
-                        disabled={disabled}
-                      />
-                    </Form.Item>
-                  </Col>
-                  <Col
-                    style={{
-                      marginLeft: -10,
-                      display: 'flex',
-                      alignItems: 'center',
-                    }}
-                  >
-                    {!disabled &&
-                      (fields.length > 1 ? (
-                        <MinusCircleOutlined
-                          style={{ margin: '0 8px' }}
-                          onClick={() => {
-                            remove(field.name);
-                          }}
-                        />
-                      ) : null)}
-                  </Col>
-                </Row>
-              </Form.Item>
-            ))}
-            {!disabled && (
-              <Form.Item {...FORM_ITEM_WITHOUT_LABEL}>
-                <Button
-                  type="dashed"
-                  onClick={() => {
-                    add();
-                  }}
-                >
-                  <PlusOutlined />
-                  {formatMessage({ id: 'upstream.step.create' })}
-                </Button>
-              </Form.Item>
-            )}
-          </>
-        )}
-      </Form.List>
-    </>
-  );
   return (
-    <Form {...FORM_ITEM_LAYOUT} form={form} initialValues={initialValues}>
+    <Form labelCol={{ span: 3 }} form={form} initialValues={initialValues}>
       <Form.Item
         label={formatMessage({ id: 'upstream.step.name' })}
         name="name"
@@ -607,106 +92,7 @@ const Step1: React.FC<Props> = ({ form, disabled, isActive, onChange, isPassive
           disabled={disabled}
         />
       </Form.Item>
-      <Form.Item
-        label={formatMessage({ id: 'upstream.step.type' })}
-        name="type"
-        rules={[{ required: true }]}
-      >
-        <Select disabled={disabled}>
-          <Select.Option value="roundrobin">roundrobin</Select.Option>
-          <Select.Option value="chash">chash</Select.Option>
-        </Select>
-      </Form.Item>
-      <Form.Item shouldUpdate noStyle>
-        {() => {
-          if (form.getFieldValue('type') === 'chash') {
-            return (
-              <>
-                <Form.Item label="Hash On" name="hash_on" labelCol={{ span: 6 }} rules={[{ required: true }]}>
-                  <Select disabled={disabled}>
-                    {HASH_ON_LIST.map((item) => (
-                      <Select.Option value={item} key={item}>
-                        {item}
-                      </Select.Option>
-                    ))}
-                  </Select>
-                </Form.Item>
-                <Form.Item label="Key" name="key" labelCol={{ span: 6 }} rules={[{ required: true }]}>
-                  <Select disabled={disabled}>
-                    {HASH_KEY_LIST.map((item) => (
-                      <Select.Option value={item} key={item}>
-                        {item}
-                      </Select.Option>
-                    ))}
-                  </Select>
-                </Form.Item>
-              </>
-            );
-          }
-          return null;
-        }}
-      </Form.Item>
-      {renderUpstreamMeta()}
-      <Form.Item label={formatMessage({ id: 'upstream.step.connect.timeout' })} required>
-        <Form.Item
-          name={['timeout', 'connect']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.connect.timeout' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} />
-        </Form.Item>
-        {renderTimeUnit()}
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.send.timeout' })} required>
-        <Form.Item
-          name={['timeout', 'send']}
-          noStyle
-          rules={[
-            { required: true, message: formatMessage({ id: 'upstream.step.input.send.timeout' }) },
-          ]}
-        >
-          <InputNumber disabled={disabled} />
-        </Form.Item>
-        {renderTimeUnit()}
-      </Form.Item>
-      <Form.Item label={formatMessage({ id: 'upstream.step.receive.timeout' })} required>
-        <Form.Item
-          name={['timeout', 'read']}
-          noStyle
-          rules={[
-            {
-              required: true,
-              message: formatMessage({ id: 'upstream.step.input.receive.timeout' }),
-            },
-          ]}
-        >
-          <InputNumber disabled={disabled} />
-        </Form.Item>
-        {renderTimeUnit()}
-      </Form.Item>
-      <PanelSection title={formatMessage({ id: 'upstream.step.healthy.check' })}>
-        <Form.Item
-          label={formatMessage({ id: 'upstream.step.healthy.checks.active' })}
-          name="active"
-          valuePropName="checked"
-        >
-          <Switch disabled={disabled} onChange={handleActiveChange} />
-        </Form.Item>
-        {isActive && renderActiveHealthyCheck()}
-        <Form.Item
-          label={formatMessage({ id: 'upstream.step.healthy.checks.passive' })}
-          name="passive"
-          valuePropName="checked"
-        >
-          <Switch disabled={disabled} onChange={handlePassiveChange} />
-        </Form.Item>
-        {isPassive && renderPassiveHealthyCheck()}
-      </PanelSection>
+      <UpstreamForm />
     </Form>
   );
 };