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 55ac5d6 feat: handle Modal close event (#223) 55ac5d6 is described below commit 55ac5d6c2de10d602e9d4bde7fe98633482101f4 Author: litesun <31329157+lite...@users.noreply.github.com> AuthorDate: Mon Jun 1 16:43:19 2020 +0800 feat: handle Modal close event (#223) * 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: format code * feat: add page skip * feat: format code --- src/components/PluginForm/transformer.ts | 5 +- src/pages/Routes/Create.tsx | 35 ++++- src/pages/Routes/components/Step1/index.tsx | 208 +++++++++++++++++----------- 3 files changed, 161 insertions(+), 87 deletions(-) diff --git a/src/components/PluginForm/transformer.ts b/src/components/PluginForm/transformer.ts index cf55c55..8300173 100644 --- a/src/components/PluginForm/transformer.ts +++ b/src/components/PluginForm/transformer.ts @@ -4,7 +4,10 @@ import { Rule } from 'antd/es/form'; /** * Transform schema data from API for target plugin. */ -export const transformSchemaFromAPI = (schema: PluginForm.PluginSchema, pluginName: string): PluginForm.PluginSchema => { +export const transformSchemaFromAPI = ( + schema: PluginForm.PluginSchema, + pluginName: string, +): PluginForm.PluginSchema => { if (pluginName === 'key-auth') { return { ...schema, diff --git a/src/pages/Routes/Create.tsx b/src/pages/Routes/Create.tsx index ee6559f..707448c 100644 --- a/src/pages/Routes/Create.tsx +++ b/src/pages/Routes/Create.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { Card, Steps } from 'antd'; +import { Card, Steps, Row, Col, Button, message } from 'antd'; import { PageHeaderWrapper } from '@ant-design/pro-layout'; import Step1 from './components/Step1'; import styles from './Create.less'; @@ -28,7 +28,7 @@ const Create: React.FC = () => { }, }); - const [currentStep] = useState(2); + const [currentStep, setCurrentStep] = useState(0); const [stepHeader] = useState(['定义 API 请求', '定义 API 后端服务', '插件配置', '预览']); const data = { step1Data, @@ -51,6 +51,36 @@ const Create: React.FC = () => { } }; + const renderActionBar = () => { + // TODO: form validation + const onPrev = () => { + setCurrentStep(currentStep - 1); + }; + const onNext = () => { + if (currentStep === 3) { + message.success('创建成功'); + return; + } + setCurrentStep(currentStep + 1); + }; + return ( + <div> + <Row justify="center" gutter={10}> + <Col> + <Button type="primary" onClick={onPrev} disabled={currentStep === 0}> + 上一步 + </Button> + </Col> + <Col> + <Button type="primary" onClick={onNext}> + {currentStep < 3 ? '下一步' : '创建'} + </Button> + </Col> + </Row> + </div> + ); + }; + return ( <PageHeaderWrapper> <Card bordered={false}> @@ -61,6 +91,7 @@ const Create: React.FC = () => { </Steps> {renderStep()} </Card> + {renderActionBar()} </PageHeaderWrapper> ); }; diff --git a/src/pages/Routes/components/Step1/index.tsx b/src/pages/Routes/components/Step1/index.tsx index 5b06b8f..aab22e4 100644 --- a/src/pages/Routes/components/Step1/index.tsx +++ b/src/pages/Routes/components/Step1/index.tsx @@ -1,12 +1,16 @@ import React, { useState } from 'react'; import { Form, Button, Input, Checkbox, Row, Col, Table, Space, Modal, Select } from 'antd'; +import { CheckboxChangeEvent } from 'antd/lib/checkbox'; +import { CheckboxValueType } from 'antd/lib/checkbox/Group'; import styles from '../../Create.less'; - import PanelSection from '../PanelSection'; const { TextArea } = Input; const { Option } = Select; +type HttpMethod = 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS' | 'PATCH'; +type RequestProtocol = 'HTTPS' | 'HTTP'; + const formItemLayout = { labelCol: { span: 6, @@ -16,17 +20,27 @@ const formItemLayout = { }, }; +const DEFAULT_MODAL_DATA: RouteModule.MatchingRule = { + paramsLocation: 'query', + paramsName: '', + paramsExpresstion: '==', + paramsValue: '', + key: '', +}; + const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { const { step1Data } = data; const { hosts, paths, advancedMatchingRules } = step1Data; const [form] = Form.useForm(); const [modalVisible, setModalVisible] = useState(false); - const [editModalData, setEditModalData] = useState<RouteModule.MatchingRule>({ - paramsLocation: 'query', - paramsName: '', - paramsExpresstion: '==', - paramsValue: '', - key: '', + const [editModalData, setEditModalData] = useState(DEFAULT_MODAL_DATA); + const [protocolValueList, setProtocolValueList] = useState<RequestProtocol[]>(['HTTP', 'HTTPS']); + const protocolList = ['HTTP', 'HTTPS', 'WebSocket']; + const httpMethodOptionList = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH']; + const [httpMethodList, setHttpMethodList] = useState({ + checkedList: httpMethodOptionList, + indeterminate: false, + checkAll: true, }); const handleAdd = () => { @@ -155,8 +169,26 @@ const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { </> ); - const renderBaseRequestConfig = () => ( - <> + const renderBaseRequestConfig = () => { + const onProtocolChange = (e: CheckboxValueType[]) => { + if (!e.includes('HTTP') && !e.includes('HTTPS')) return; + setProtocolValueList(e as RequestProtocol[]); + }; + const onMethodsChange = (checkedList: CheckboxValueType[]) => { + setHttpMethodList({ + checkedList: checkedList as HttpMethod[], + indeterminate: !!checkedList.length && checkedList.length < httpMethodOptionList.length, + checkAll: checkedList.length === httpMethodOptionList.length, + }); + }; + const onCheckAllChange = (e: CheckboxChangeEvent) => { + setHttpMethodList({ + checkedList: e.target.checked ? httpMethodOptionList : [], + indeterminate: false, + checkAll: e.target.checked, + }); + }; + return ( <PanelSection title="请求基础定义"> <Form {...formItemLayout} form={form} layout="horizontal" className={styles.stepForm}> <Form.Item @@ -164,25 +196,18 @@ const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { name="protocol" rules={[{ required: true, message: '请勾选协议' }]} > - <Checkbox.Group style={{ width: '100%' }}> - <Row> - {['HTTP', 'HTTPS', 'WebSocket'].map((item) => ( - <Col span={6} key={item}> - <Checkbox value={item}>{item}</Checkbox> - </Col> - ))} - </Row> - </Checkbox.Group> + <Row> + <Checkbox.Group + options={protocolList} + value={protocolValueList} + onChange={onProtocolChange} + /> + </Row> </Form.Item> {/* TODO: name */} <Form.Item label="HOST" rules={[{ required: true, message: '请输入 HOST' }]}> {renderHosts()} - <Button - type="primary" - onClick={() => { - addHost(); - }} - > + <Button type="primary" onClick={addHost}> 增加 </Button> </Form.Item> @@ -198,20 +223,23 @@ const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { name="httpMethods" rules={[{ required: true, message: '请勾选 HTTP Methods' }]} > - <Checkbox.Group style={{ width: '100%' }}> - <Row> - {['ANY', 'GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'].map((item) => ( - <Col span={6} key={item}> - <Checkbox value={item}>{item}</Checkbox> - </Col> - ))} - </Row> - </Checkbox.Group> + <Checkbox + indeterminate={httpMethodList.indeterminate} + onChange={onCheckAllChange} + checked={httpMethodList.checkAll} + > + ANY + </Checkbox> + <Checkbox.Group + options={httpMethodOptionList} + value={httpMethodList.checkedList} + onChange={onMethodsChange} + /> </Form.Item> </Form> </PanelSection> - </> - ); + ); + }; const [modalForm] = Form.useForm(); const handleOk = () => { @@ -230,6 +258,12 @@ const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { setModalVisible(false); }; + const handleClose = () => { + // TODO: Data not updated in a timely manner + setEditModalData(DEFAULT_MODAL_DATA); + modalForm.resetFields(); + }; + const renderAdvancedMatchingRules = () => ( <> <PanelSection title="高级路由匹配条件"> @@ -251,56 +285,62 @@ const Step1: React.FC<RouteModule.Data> = ({ data, onChange }) => { return ( <> - {modalVisible && ( - <Modal title="新增" centered visible onOk={handleOk} onCancel={handleCancel} destroyOnClose> - <Form - form={modalForm} - labelCol={{ span: 4 }} - wrapperCol={{ span: 20 }} - initialValues={editModalData} + <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="paramsLocation" + rules={[{ required: true, message: '请选择参数位置' }]} > - <Form.Item - label="参数位置" - name="paramsLocation" - rules={[{ required: true, message: '请选择参数位置' }]} - > - <Select> - <Option value="header">header</Option> - <Option value="query">query</Option> - <Option value="params">params</Option> - <Option value="cookie">cookie</Option> - </Select> - </Form.Item> - <Form.Item - label="参数名称" - name="paramsName" - rules={[{ required: true, message: '请输入参数名称' }]} - > - <Input /> - </Form.Item> - <Form.Item - label="运算符" - name="paramsExpresstion" - rules={[{ required: true, message: '请选择运算符' }]} - > - <Select> - <Option value="==">等于</Option> - <Option value="~=">不等于</Option> - <Option value=">">大于</Option> - <Option value="<">小于</Option> - <Option value="~~">正则匹配</Option> - </Select> - </Form.Item> - <Form.Item - label="值" - name="paramsValue" - rules={[{ required: true, message: '请输入参数值' }]} - > - <Input /> - </Form.Item> - </Form> - </Modal> - )} + <Select> + <Option value="header">header</Option> + <Option value="query">query</Option> + <Option value="params">params</Option> + <Option value="cookie">cookie</Option> + </Select> + </Form.Item> + <Form.Item + label="参数名称" + name="paramsName" + rules={[{ required: true, message: '请输入参数名称' }]} + > + <Input /> + </Form.Item> + <Form.Item + label="运算符" + name="paramsExpresstion" + rules={[{ required: true, message: '请选择运算符' }]} + > + <Select> + <Option value="==">等于</Option> + <Option value="~=">不等于</Option> + <Option value=">">大于</Option> + <Option value="<">小于</Option> + <Option value="~~">正则匹配</Option> + </Select> + </Form.Item> + <Form.Item + label="值" + name="paramsValue" + rules={[{ required: true, message: '请输入参数值' }]} + > + <Input /> + </Form.Item> + </Form> + </Modal> {renderMeta()} {renderBaseRequestConfig()} {renderAdvancedMatchingRules()}