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;

Reply via email to