This is an automated email from the ASF dual-hosted git repository. juzhiyuan pushed a commit to branch v2.3-sync in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git
commit 7862edc75058f405fd6cdb13282a1011748683cd Author: liuxiran <belovedx...@126.com> AuthorDate: Wed Jan 6 12:32:38 2021 +0800 fix: online debug body params support content-type x-www-form-urlencoded (#1201) * fix: online debug body params support content-type x-www-form-urlencoded * fix: body code mirror support different mode * fix: use enum instead of real string * fix: lint error Co-authored-by: 琚致远 <juzhiy...@apache.org> --- .../Route/components/DebugViews/DebugDrawView.tsx | 108 ++++++++++++++++++--- .../pages/Route/components/DebugViews/index.less | 20 ++-- web/src/pages/Route/constants.ts | 6 ++ web/src/pages/Route/typing.d.ts | 8 +- 4 files changed, 117 insertions(+), 25 deletions(-) diff --git a/web/src/pages/Route/components/DebugViews/DebugDrawView.tsx b/web/src/pages/Route/components/DebugViews/DebugDrawView.tsx index 5991fbf..9180fe6 100644 --- a/web/src/pages/Route/components/DebugViews/DebugDrawView.tsx +++ b/web/src/pages/Route/components/DebugViews/DebugDrawView.tsx @@ -14,8 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, { useEffect, useState } from 'react'; -import { Input, Select, Card, Tabs, Form, Drawer, Spin, notification } from 'antd'; +import React, { useEffect, useState, useRef } from 'react'; +import { Input, Select, Card, Tabs, Form, Drawer, Spin, notification, Radio } from 'antd'; import { useIntl } from 'umi'; import CodeMirror from '@uiw/react-codemirror'; import { PanelSection } from '@api7-dashboard/ui'; @@ -27,6 +27,8 @@ import { DEFAULT_DEBUG_PARAM_FORM_DATA, DEFAULT_DEBUG_AUTH_FORM_DATA, PROTOCOL_SUPPORTED, + DEBUG_BODY_TYPE_SUPPORTED, + DEBUG_BODY_CODEMIRROR_MODE_SUPPORTED, } from '../../constants'; import { DebugParamsView, AuthenticationView } from '.'; import { debugRoute } from '../../service'; @@ -48,7 +50,17 @@ const DebugDrawView: React.FC<RouteModule.DebugDrawProps> = (props) => { const [responseCode, setResponseCode] = useState<string>(); const [loading, setLoading] = useState(false); const [codeMirrorHeight, setCodeMirrorHeight] = useState<number | string>(50); + const bodyCodeMirrorRef = useRef<any>(null); + const [bodyType, setBodyType] = useState('none'); const methodWithoutBody = ['GET', 'HEAD']; + const [bodyCodeMirrorMode, setBodyCodeMirrorMode] = useState(DEBUG_BODY_CODEMIRROR_MODE_SUPPORTED[0].mode) + + enum DebugBodyType { + None = 0, + FormUrlencoded, + Json, + RawInput, + } const resetForms = () => { queryForm.setFieldsValue(DEFAULT_DEBUG_PARAM_FORM_DATA); @@ -56,24 +68,44 @@ const DebugDrawView: React.FC<RouteModule.DebugDrawProps> = (props) => { headerForm.setFieldsValue(DEFAULT_DEBUG_PARAM_FORM_DATA); authForm.setFieldsValue(DEFAULT_DEBUG_AUTH_FORM_DATA); setResponseCode(`${formatMessage({ id: 'page.route.debug.showResultAfterSendRequest' })}`); + setBodyType(DEBUG_BODY_TYPE_SUPPORTED[DebugBodyType.None]); }; useEffect(() => { resetForms(); }, []); - const transformBodyParamsFormData = (formData: RouteModule.debugRequestParamsFormData[]) => { - let transformData = {}; - (formData || []) - .filter((data) => data.check) - .forEach((data) => { - transformData = { - ...transformData, - [data.key]: data.value, - }; - }); + const transformBodyParamsFormData = () => { + let transformDataForm: string[]; + let transformDataJson: object; + const formData: RouteModule.debugRequestParamsFormData[] = bodyForm.getFieldsValue().params; + switch (bodyType) { + case 'x-www-form-urlencoded': + transformDataForm = (formData || []) + .filter((data) => data.check) + .map((data) => { + return `${data.key}=${data.value}` + }); - return transformData; + return transformDataForm.join('&'); + case 'json': + transformDataJson = {}; + (formData || []) + .filter((data) => data.check) + .forEach((data) => { + transformDataJson = { + ...transformDataJson, + [data.key]: data.value, + }; + }); + + return JSON.stringify(transformDataJson); + case 'raw input': + return bodyCodeMirrorRef.current.editor.getValue(); + case 'none': + default: + return undefined; + } }; const transformHeaderAndQueryParamsFormData = ( @@ -128,7 +160,7 @@ const DebugDrawView: React.FC<RouteModule.DebugDrawProps> = (props) => { return; } const queryFormData = transformHeaderAndQueryParamsFormData(queryForm.getFieldsValue().params); - const bodyFormData = transformBodyParamsFormData(bodyForm.getFieldsValue().params); + const bodyFormData = transformBodyParamsFormData(); const pureHeaderFormData = transformHeaderAndQueryParamsFormData( headerForm.getFieldsValue().params, ); @@ -233,7 +265,53 @@ const DebugDrawView: React.FC<RouteModule.DebugDrawProps> = (props) => { </TabPane> {showBodyTab && ( <TabPane tab={formatMessage({ id: 'page.route.TabPane.bodyParams' })} key="body"> - <DebugParamsView form={bodyForm} /> + <Radio.Group onChange={(e) => {setBodyType(e.target.value)}} value={bodyType}> + { + DEBUG_BODY_TYPE_SUPPORTED.map((type) => ( + <Radio value={type} key={type}>{type}</Radio> + )) + } + </Radio.Group> + {bodyType === DEBUG_BODY_TYPE_SUPPORTED[DebugBodyType.RawInput] && <Select + size="small" + onChange={(value) => { + setBodyCodeMirrorMode(value) + }} + style={{ width: 100 }} + defaultValue={bodyCodeMirrorMode}> + { + DEBUG_BODY_CODEMIRROR_MODE_SUPPORTED.map((modeObj) =>( + <Select.Option key={modeObj.name} value={modeObj.mode}>{modeObj.name}</Select.Option> + )) + } + </Select>} + <div style={{marginTop: 16}}> + { + (bodyType === DEBUG_BODY_TYPE_SUPPORTED[DebugBodyType.FormUrlencoded] || bodyType === DEBUG_BODY_TYPE_SUPPORTED[DebugBodyType.Json]) && + <DebugParamsView form={bodyForm} /> + } + + { + (bodyType === DEBUG_BODY_TYPE_SUPPORTED[DebugBodyType.RawInput]) && + <Form> + <Form.Item> + <CodeMirror + ref={bodyCodeMirrorRef} + height={250} + options={{ + mode: bodyCodeMirrorMode, + readOnly: '', + lineWrapping: true, + lineNumbers: true, + showCursorWhenSelecting: true, + autofocus: true, + scrollbarStyle: null, + }} + /> + </Form.Item> + </Form> + } + </div> </TabPane> )} </Tabs> diff --git a/web/src/pages/Route/components/DebugViews/index.less b/web/src/pages/Route/components/DebugViews/index.less index f9cb5dc..65ee10b 100644 --- a/web/src/pages/Route/components/DebugViews/index.less +++ b/web/src/pages/Route/components/DebugViews/index.less @@ -24,21 +24,23 @@ .ant-drawer-body { padding: 16px; } - .ant-radio-wrapper { - display: block; - height: 30px; - line-height: 30px; - } .ant-form-item { margin-bottom: 8px; } - .ant-radio-group { - margin-right: 16px; - border-right: 1px solid #e0e0e0; - } } .authForm { display: flex; margin: 16px; + :global { + .ant-radio-wrapper { + display: block; + height: 30px; + line-height: 30px; + } + .ant-radio-group { + margin-right: 16px; + border-right: 1px solid #e0e0e0; + } + } } } diff --git a/web/src/pages/Route/constants.ts b/web/src/pages/Route/constants.ts index 1a8dc46..22b2e61 100644 --- a/web/src/pages/Route/constants.ts +++ b/web/src/pages/Route/constants.ts @@ -98,8 +98,14 @@ export const DEFAULT_DEBUG_PARAM_FORM_DATA = { value: '', }, ], + type: 'json', }; export const DEFAULT_DEBUG_AUTH_FORM_DATA = { authType: 'none', }; + +export const DEBUG_BODY_TYPE_SUPPORTED: RouteModule.DebugBodyType[]= ['none', 'x-www-form-urlencoded','json','raw input']; + +// Note: codemirror mode: apl for text; javascript for json(need to format); xml for xml; +export const DEBUG_BODY_CODEMIRROR_MODE_SUPPORTED = [{name: 'Json', mode: 'javascript'}, {name: 'Text', mode: 'apl'}, {name: 'XML', mode:'xml'}] diff --git a/web/src/pages/Route/typing.d.ts b/web/src/pages/Route/typing.d.ts index 60afe5f..8ae302f 100644 --- a/web/src/pages/Route/typing.d.ts +++ b/web/src/pages/Route/typing.d.ts @@ -251,7 +251,7 @@ declare namespace RouteModule { // TODO: grpc and websocket type debugRequest = { url: string; - request_protocol: 'http' | 'https' | 'grpc' | 'websocket'; + request_protocol: RequestProtocol | 'grpc'; method: string; body_params?: any; header_params?: any; @@ -271,6 +271,12 @@ declare namespace RouteModule { type DebugViewProps = { form: FormInstance; }; + type DebugBodyType = 'none' | 'x-www-form-urlencoded' | 'json' | 'raw input'; + type DebugDodyViewProps = { + form: FormInstance; + changeBodyParamsType:(type: DebugBodyType) => void; + codeMirrorRef: any; + }; type DebugDrawProps = { visible: boolean; onClose(): void;