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/06/01 09:46:30 UTC

[incubator-apisix-dashboard] branch next updated: feat: add step2 page (#228)

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

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


The following commit(s) were added to refs/heads/next by this push:
     new 0b00d08  feat: add step2 page (#228)
0b00d08 is described below

commit 0b00d08cec6d09557ead7e045201b9c0c56aeb9e
Author: litesun <31...@users.noreply.github.com>
AuthorDate: Mon Jun 1 17:46:20 2020 +0800

    feat: add step2 page (#228)
    
    * feat: limit upload file
    
    * feat: intercept default upload api request
    
    * feat: limit upload file type
    
    * fix: show file when parse SSL file  fail
    
    * feat: add search feature
    
    * feat: format code
    
    * fix: remove list item not work
    
    * feat: remove relatedRouting
    
    * feat: add routes step1 page
    
    * feat: update route
    
    * feat: format code
    
    * feat: update
    
    * feat: update
    
    * feat: add checkbox rule
    
    * feat: handle Modal close event
    
    * feat: add routes step2 page
    
    * feat: add routes step2 page
    
    * feat: format code
    
    * feat: add page skip
    
    * feat: format code
    
    * feat: format code
    
    * Update Create.tsx
    
    Co-authored-by: 琚致远 <ju...@apache.org>
---
 src/pages/Routes/Create.tsx                 |  20 +++
 src/pages/Routes/components/Step2/index.tsx | 258 ++++++++++++++++++++++++++++
 src/pages/Routes/typing.d.ts                |  25 +++
 3 files changed, 303 insertions(+)

diff --git a/src/pages/Routes/Create.tsx b/src/pages/Routes/Create.tsx
index 872e4e6..bed1970 100644
--- a/src/pages/Routes/Create.tsx
+++ b/src/pages/Routes/Create.tsx
@@ -3,6 +3,7 @@ import { Card, Steps } from 'antd';
 import { PageHeaderWrapper } from '@ant-design/pro-layout';
 
 import Step1 from './components/Step1';
+import Step2 from './components/Step2';
 import styles from './Create.less';
 import CreateStep3 from './components/CreateStep3';
 import ActionBar from './components/ActionBar';
@@ -19,6 +20,17 @@ const Create: React.FC = () => {
     advancedMatchingRules: [],
   });
 
+  const [step2Data, setStep2Data] = useState<RouteModule.Step2Data>({
+    backendProtocol: 'originalRequest',
+    backendAddressList: [{ host: '', port: 0, weight: 0 }],
+    upstream_header: [],
+    timeout: {
+      connect: 30000,
+      send: 30000,
+      read: 30000,
+    },
+  });
+
   const [step3Data, setStep3Data] = useState<RouteModule.Step3Data>({
     plugins: {
       'limit-count': {
@@ -34,6 +46,7 @@ const Create: React.FC = () => {
   const [stepHeader] = useState(['定义 API 请求', '定义 API 后端服务', '插件配置', '预览']);
   const data = {
     step1Data,
+    step2Data,
     step3Data,
   };
 
@@ -46,6 +59,13 @@ const Create: React.FC = () => {
             onChange={(params: RouteModule.Step1Data) => setStep1Data({ ...step1Data, ...params })}
           />
         );
+      case 1:
+        return (
+          <Step2
+            data={data}
+            onChange={(params: RouteModule.Step2Data) => setStep2Data({ ...step2Data, ...params })}
+          />
+        );
       case 2:
         return <CreateStep3 data={data} onChange={setStep3Data} />;
       default:
diff --git a/src/pages/Routes/components/Step2/index.tsx b/src/pages/Routes/components/Step2/index.tsx
new file mode 100644
index 0000000..89e56bf
--- /dev/null
+++ b/src/pages/Routes/components/Step2/index.tsx
@@ -0,0 +1,258 @@
+import React, { useState } from 'react';
+import { Form, Row, Col, Input, Space, Button, Radio, InputNumber, Table, Modal } from 'antd';
+import { RadioChangeEvent } from 'antd/lib/radio';
+import PanelSection from '../PanelSection';
+import styles from '../../Create.less';
+
+const { TextArea } = Input;
+
+const DEFAULT_MODAL_DATA: RouteModule.UpstreamHeader = {
+  header_name: '',
+  header_value: '',
+  header_desc: '',
+  key: '',
+};
+
+const formItemLayout = {
+  labelCol: {
+    span: 6,
+  },
+  wrapperCol: {
+    span: 18,
+  },
+};
+
+const Step2: React.FC<RouteModule.Data> = ({ data, onChange }) => {
+  const { step2Data } = data;
+  const { upstream_header, backendAddressList, backendProtocol } = step2Data;
+  const [modalVisible, setModalVisible] = useState(false);
+  const [modalForm] = Form.useForm();
+  const [editModalData, setEditModalData] = useState<RouteModule.UpstreamHeader>(
+    DEFAULT_MODAL_DATA,
+  );
+  const [form] = Form.useForm();
+
+  const handleRemove = (key: string) => {
+    onChange({ upstream_header: upstream_header.filter((item) => item.key !== key) });
+  };
+
+  const columns = [
+    {
+      title: '请求头',
+      dataIndex: 'header_name',
+      key: 'header_name',
+    },
+    {
+      title: '值',
+      dataIndex: 'header_value',
+      key: 'header_value',
+    },
+    {
+      title: '描述',
+      dataIndex: 'header_desc',
+      key: 'header_desc',
+    },
+    {
+      title: '操作',
+      key: 'action',
+      render: (_: any, record: RouteModule.UpstreamHeader) => (
+        <Space size="middle">
+          <a
+            onClick={() => {
+              handleRemove(record.key);
+            }}
+          >
+            移除
+          </a>
+        </Space>
+      ),
+    },
+  ];
+
+  const renderRequestRewrite = () => {
+    const onProtocolChange = (e: RadioChangeEvent) => {
+      onChange({ backendProtocol: e.target.value });
+    };
+
+    const addBackendAddress = () => {
+      onChange({
+        backendAddressList: backendAddressList.concat({ host: '', port: 0, weight: 0 }),
+      });
+    };
+
+    const renderBackendAddress = () =>
+      backendAddressList.map((item, index) => (
+        <Row key={`${item.host + index}`} style={{ marginBottom: '10px' }} gutter={[16, 16]}>
+          <Col span={12}>
+            <Input placeholder="HOST" />
+          </Col>
+          <Col span={4}>
+            <InputNumber placeholder="Port" />
+          </Col>
+          <Col span={4}>
+            <InputNumber placeholder="Weight" />
+          </Col>
+          <Col span={4}>
+            <Space>
+              {backendAddressList.length > 1 && (
+                <Button
+                  type="primary"
+                  danger
+                  onClick={() => {
+                    onChange({
+                      backendAddressList: backendAddressList.filter(
+                        (_, _index) => _index !== index,
+                      ),
+                    });
+                  }}
+                >
+                  删除
+                </Button>
+              )}
+            </Space>
+          </Col>
+        </Row>
+      ));
+
+    return (
+      <PanelSection title="请求改写">
+        <Form
+          {...formItemLayout}
+          form={form}
+          layout="horizontal"
+          className={styles.stepForm}
+          initialValues={step2Data}
+        >
+          <Form.Item
+            label="协议"
+            name="protocol"
+            rules={[{ required: true, message: '请勾选协议' }]}
+          >
+            <Row>
+              <Radio.Group
+                onChange={onProtocolChange}
+                name="backendProtocol"
+                value={backendProtocol}
+              >
+                <Radio value="HTTP">HTTP</Radio>
+                <Radio value="HTTPS">HTTPS</Radio>
+                <Radio value="originalRequest">原始请求</Radio>
+              </Radio.Group>
+            </Row>
+          </Form.Item>
+          <Form.Item label="后端地址" rules={[{ required: true, message: '请输入后端地址' }]}>
+            {renderBackendAddress()}
+            <Button type="primary" onClick={addBackendAddress}>
+              增加
+            </Button>
+          </Form.Item>
+          <Form.Item label="后端请求 Path">
+            <Row>
+              <Input />
+            </Row>
+          </Form.Item>
+          <Form.Item label="连接超时">
+            <InputNumber /> ms
+          </Form.Item>
+          <Form.Item label="发送超时">
+            <InputNumber /> ms
+          </Form.Item>
+          <Form.Item label="接收超时">
+            <InputNumber /> ms
+          </Form.Item>
+        </Form>
+      </PanelSection>
+    );
+  };
+
+  const renderHttpHeaderRewrite = () => {
+    const handleAdd = () => {
+      setModalVisible(true);
+    };
+    return (
+      <PanelSection title="HTTP 头改写">
+        <div>
+          <Button
+            onClick={handleAdd}
+            type="primary"
+            style={{
+              marginBottom: 16,
+            }}
+          >
+            新增
+          </Button>
+          <Table key="table" bordered dataSource={upstream_header} columns={columns} />
+        </div>
+      </PanelSection>
+    );
+  };
+
+  const renderModal = () => {
+    const handleOk = () => {
+      modalForm.validateFields().then((value) => {
+        onChange({
+          upstream_header: upstream_header.concat({
+            ...(value as RouteModule.UpstreamHeader),
+            key: Math.random().toString(36).slice(2),
+          }),
+        });
+        setModalVisible(false);
+      });
+    };
+    const handleCancel = () => {
+      setModalVisible(false);
+    };
+
+    const handleClose = () => {
+      setEditModalData(DEFAULT_MODAL_DATA);
+      modalForm.resetFields();
+    };
+
+    return (
+      <Modal
+        title="新增"
+        centered
+        visible={modalVisible}
+        onOk={handleOk}
+        onCancel={handleCancel}
+        afterClose={handleClose}
+        destroyOnClose
+      >
+        <Form
+          form={modalForm}
+          labelCol={{ span: 4 }}
+          wrapperCol={{ span: 20 }}
+          initialValues={editModalData}
+        >
+          <Form.Item
+            label="请求头"
+            name="header_name"
+            rules={[{ required: true, message: '请输入请求头' }]}
+          >
+            <Input />
+          </Form.Item>
+          <Form.Item
+            label="值"
+            name="header_value"
+            rules={[{ required: true, message: '请输入值' }]}
+          >
+            <Input />
+          </Form.Item>
+          <Form.Item label="描述" name="upstream_header_desc">
+            <TextArea />
+          </Form.Item>
+        </Form>
+      </Modal>
+    );
+  };
+
+  return (
+    <>
+      {renderModal()}
+      {renderRequestRewrite()}
+      {renderHttpHeaderRewrite()}
+    </>
+  );
+};
+
+export default Step2;
diff --git a/src/pages/Routes/typing.d.ts b/src/pages/Routes/typing.d.ts
index f51d0a6..51fe10d 100644
--- a/src/pages/Routes/typing.d.ts
+++ b/src/pages/Routes/typing.d.ts
@@ -25,8 +25,33 @@ declare namespace RouteModule {
   interface Data {
     data: {
       step1Data: Step1Data;
+      step2Data: Step2Data;
       step3Data: Step3Data;
     };
     onChange(data: T): void;
   }
+
+  type backendAddressItemProps = {
+    host: '';
+    port: number;
+    weight: number;
+  };
+
+  interface UpstreamHeader {
+    header_name: string;
+    header_value: string;
+    header_desc: string;
+    key: string;
+  }
+
+  type Step2Data = {
+    backendProtocol: 'HTTP' | 'HTTPS' | 'originalRequest';
+    backendAddressList: backendAddressItemProps[];
+    upstream_header: UpstreamHeader[];
+    timeout: {
+      connect: number;
+      send: number;
+      read: number;
+    };
+  };
 }