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/08/17 09:19:29 UTC

[apisix-dashboard] branch master updated: feat(route): route add params mapping feature (#375) (#377)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 585830f  feat(route): route add params mapping feature (#375) (#377)
585830f is described below

commit 585830f18b1a347b4df45b9f7e02b5fff2b73b7e
Author: liuxiran <be...@126.com>
AuthorDate: Mon Aug 17 17:19:22 2020 +0800

    feat(route): route add params mapping feature (#375) (#377)
---
 .../Route/components/Step1/MatchingRulesView.tsx   |   2 +-
 .../components/Step2/HttpHeaderRewriteView.tsx     |  31 ++++--
 .../Route/components/Step2/RequestRewriteView.tsx  | 119 +++++++++++++++++----
 src/pages/Route/constants.ts                       |   2 +
 src/pages/Route/locales/en-US.ts                   |   3 +
 src/pages/Route/locales/zh-CN.ts                   |   3 +
 src/pages/Route/transform.ts                       |  19 ++++
 src/pages/Route/typing.d.ts                        |   3 +
 8 files changed, 153 insertions(+), 29 deletions(-)

diff --git a/src/pages/Route/components/Step1/MatchingRulesView.tsx b/src/pages/Route/components/Step1/MatchingRulesView.tsx
index f6284d4..be403da 100644
--- a/src/pages/Route/components/Step1/MatchingRulesView.tsx
+++ b/src/pages/Route/components/Step1/MatchingRulesView.tsx
@@ -165,7 +165,7 @@ const MatchingRulesView: React.FC<Props> = ({ data, disabled, onChange }) => {
       cancelText={formatMessage({ id: 'route.match.cancel' })}
       destroyOnClose
     >
-      <Form form={modalForm} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
+      <Form form={modalForm} labelCol={{ span: 9 }} wrapperCol={{ span: 15 }}>
         <Form.Item
           label={formatMessage({ id: 'route.match.parameter.position' })}
           name="position"
diff --git a/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx b/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx
index 420a7a2..665bb21 100644
--- a/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx
+++ b/src/pages/Route/components/Step2/HttpHeaderRewriteView.tsx
@@ -51,7 +51,9 @@ const HttpHeaderRewriteView: React.FC<Props> = ({ data, disabled, onChange }) =>
       dataIndex: 'header_action',
       key: 'header_action',
       render: (action: 'override' | 'remove') => {
-        return action === 'override' ? formatMessage({ id: 'route.http.override.or.create' }) : formatMessage({ id: 'route.http.delete' });
+        return action === 'override'
+          ? formatMessage({ id: 'route.http.override.or.create' })
+          : formatMessage({ id: 'route.http.delete' });
       },
     },
     {
@@ -114,7 +116,11 @@ const HttpHeaderRewriteView: React.FC<Props> = ({ data, disabled, onChange }) =>
 
     return (
       <Modal
-        title={mode === 'EDIT' ? formatMessage({ id: 'route.http.edit.request.header' }) : formatMessage({ id: 'route.http.operate.request.header' })}
+        title={
+          mode === 'EDIT'
+            ? formatMessage({ id: 'route.http.edit.request.header' })
+            : formatMessage({ id: 'route.http.operate.request.header' })
+        }
         centered
         visible
         onOk={handleOk}
@@ -126,22 +132,33 @@ const HttpHeaderRewriteView: React.FC<Props> = ({ data, disabled, onChange }) =>
         cancelText={formatMessage({ id: 'route.http.cancel' })}
         destroyOnClose
       >
-        <Form form={modalForm} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
+        <Form form={modalForm} labelCol={{ span: 8 }} wrapperCol={{ span: 16 }}>
           <Form.Item
             label={formatMessage({ id: 'route.http.request.header.name' })}
             name="header_name"
-            rules={[{ required: true, message: formatMessage({ id: 'route.http.input.request.header.name' }) }]}
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.http.input.request.header.name' }),
+              },
+            ]}
           >
             <Input />
           </Form.Item>
           <Form.Item
             label={formatMessage({ id: 'route.http.action' })}
             name="header_action"
-            rules={[{ required: true, message: formatMessage({ id: 'route.http.select.actions' }) }]}
+            rules={[
+              { required: true, message: formatMessage({ id: 'route.http.select.actions' }) },
+            ]}
           >
             <Select onChange={(e) => setShowModalValue(e === 'override')}>
-              <Select.Option value="override">{formatMessage({ id: 'route.http.override.or.create' })}</Select.Option>
-              <Select.Option value="remove">{formatMessage({ id: 'route.http.delete' })}</Select.Option>
+              <Select.Option value="override">
+                {formatMessage({ id: 'route.http.override.or.create' })}
+              </Select.Option>
+              <Select.Option value="remove">
+                {formatMessage({ id: 'route.http.delete' })}
+              </Select.Option>
             </Select>
           </Form.Item>
           {showModalValue && (
diff --git a/src/pages/Route/components/Step2/RequestRewriteView.tsx b/src/pages/Route/components/Step2/RequestRewriteView.tsx
index 337c810..8bb4616 100644
--- a/src/pages/Route/components/Step2/RequestRewriteView.tsx
+++ b/src/pages/Route/components/Step2/RequestRewriteView.tsx
@@ -38,7 +38,10 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
   useEffect(() => {
     // eslint-disable-next-line no-shadow
     fetchUpstreamList().then(({ data }) => {
-      setUpstreams([{ name: formatMessage({ id: 'route.request.override.input' }), id: null }, ...data]);
+      setUpstreams([
+        { name: formatMessage({ id: 'route.request.override.input' }), id: null },
+        ...data,
+      ]);
       if (step2Data.upstream_id) {
         onChange({ upstream_id: step2Data.upstream_id });
       }
@@ -53,8 +56,14 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
               required
               key={field.key}
               {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)}
-              label={index === 0 ? formatMessage({ id: 'route.request.override.domain.name.or.ip' }) : ''}
-              extra={index === 0 ? formatMessage({ id: 'route.request.override.use.domain.name.default.analysis' }) : ''}
+              label={
+                index === 0 ? formatMessage({ id: 'route.request.override.domain.name.or.ip' }) : ''
+              }
+              extra={
+                index === 0
+                  ? formatMessage({ id: 'route.request.override.use.domain.name.default.analysis' })
+                  : ''
+              }
             >
               <Row style={{ marginBottom: '10px' }} gutter={16}>
                 <Col span={9}>
@@ -62,7 +71,10 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
                     style={{ marginBottom: 0 }}
                     name={[field.name, 'host']}
                     rules={[
-                      { required: true, message: formatMessage({ id: 'route.request.override.input.domain.or.ip' }) },
+                      {
+                        required: true,
+                        message: formatMessage({ id: 'route.request.override.input.domain.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,}$)/,
@@ -72,14 +84,24 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
                       },
                     ]}
                   >
-                    <Input placeholder={formatMessage({ id: 'route.request.override.domain.name.or.ip' })} disabled={upstreamDisabled} />
+                    <Input
+                      placeholder={formatMessage({
+                        id: 'route.request.override.domain.name.or.ip',
+                      })}
+                      disabled={upstreamDisabled}
+                    />
                   </Form.Item>
                 </Col>
                 <Col span={4}>
                   <Form.Item
                     style={{ marginBottom: 0 }}
                     name={[field.name, 'port']}
-                    rules={[{ required: true, message: formatMessage({ id: 'route.request.override.input.port.number' }) }]}
+                    rules={[
+                      {
+                        required: true,
+                        message: formatMessage({ id: 'route.request.override.input.port.number' }),
+                      },
+                    ]}
                   >
                     <InputNumber
                       placeholder={formatMessage({ id: 'route.request.override.port.number' })}
@@ -93,7 +115,12 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
                   <Form.Item
                     style={{ marginBottom: 0 }}
                     name={[field.name, 'weight']}
-                    rules={[{ required: true, message: formatMessage({ id: 'route.request.override.input.weight' }) }]}
+                    rules={[
+                      {
+                        required: true,
+                        message: formatMessage({ id: 'route.request.override.input.weight' }),
+                      },
+                    ]}
                   >
                     <InputNumber
                       placeholder={formatMessage({ id: 'route.request.override.weight' })}
@@ -135,7 +162,6 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
   );
 
   const renderTimeUnit = () => <span style={{ margin: '0 8px' }}>ms</span>;
-
   return (
     <PanelSection title={formatMessage({ id: 'route.request.override' })}>
       <Form
@@ -148,7 +174,12 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
         <Form.Item
           label={formatMessage({ id: 'route.request.override.protocol' })}
           name="upstream_protocol"
-          rules={[{ required: true, message: formatMessage({ id: 'route.request.override.select.protocol' }) }]}
+          rules={[
+            {
+              required: true,
+              message: formatMessage({ id: 'route.request.override.select.protocol' }),
+            },
+          ]}
         >
           <Radio.Group
             onChange={(e) => {
@@ -162,28 +193,56 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
             <Radio value="https">HTTPS</Radio>
           </Radio.Group>
         </Form.Item>
-        <Form.Item label={formatMessage({ id: 'route.request.override.path' })}>
+        <Form.Item label={formatMessage({ id: 'route.request.override.path' })} name="rewriteType">
           <Radio.Group
-            defaultValue={step2Data.upstreamPath === undefined ? 'keep' : 'modify'}
             onChange={(e) => {
-              onChange({ upstreamPath: e.target.value === 'keep' ? undefined : '' });
+              onChange({ rewriteType: e.target.value });
             }}
             disabled={disabled}
           >
             <Radio value="keep">{formatMessage({ id: 'route.request.override.stay.same' })}</Radio>
-            <Radio value="modify">{formatMessage({ id: 'route.request.override.edit' })}</Radio>
+            <Radio value="static">{formatMessage({ id: 'page.route.radio.static' })}</Radio>
+            <Radio value="regx">{formatMessage({ id: 'page.route.radio.regx' })}</Radio>
           </Radio.Group>
         </Form.Item>
-        {step2Data.upstreamPath !== undefined && (
+        {step2Data.rewriteType === 'regx' && (
+          <Form.Item
+            label={formatMessage({ id: 'page.route.form.itemLabel.from' })}
+            name="mappingStrategy"
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.request.override.input.path' }),
+              },
+            ]}
+          >
+            <Input
+              disabled={disabled}
+              placeholder={formatMessage({ id: 'route.request.override.path.example' })}
+            />
+          </Form.Item>
+        )}
+        {(step2Data.rewriteType === 'static' || step2Data.rewriteType === 'regx') && (
           <Form.Item
             label={formatMessage({ id: 'route.request.override.new.path' })}
             name="upstreamPath"
-            rules={[{ required: true, message: formatMessage({ id: 'route.request.override.input.path' }) }]}
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.request.override.input.path' }),
+              },
+            ]}
           >
-            <Input disabled={disabled} placeholder={formatMessage({ id: 'route.request.override.path.example' })} />
+            <Input
+              disabled={disabled}
+              placeholder={formatMessage({ id: 'route.request.override.path.example' })}
+            />
           </Form.Item>
         )}
-        <Form.Item label={formatMessage({ id: 'route.request.override.upstream' })} name="upstream_id">
+        <Form.Item
+          label={formatMessage({ id: 'route.request.override.upstream' })}
+          name="upstream_id"
+        >
           <Select
             onChange={(value) => {
               onChange({ upstream_id: value });
@@ -200,11 +259,19 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
           </Select>
         </Form.Item>
         {renderUpstreamMeta()}
-        <Form.Item label={formatMessage({ id: 'route.request.override.connection.timeout' })} required>
+        <Form.Item
+          label={formatMessage({ id: 'route.request.override.connection.timeout' })}
+          required
+        >
           <Form.Item
             name={['timeout', 'connect']}
             noStyle
-            rules={[{ required: true, message: formatMessage({ id: 'route.request.override.input.connection.timeout' }) }]}
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.request.override.input.connection.timeout' }),
+              },
+            ]}
           >
             <InputNumber disabled={upstreamDisabled} />
           </Form.Item>
@@ -214,7 +281,12 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
           <Form.Item
             name={['timeout', 'send']}
             noStyle
-            rules={[{ required: true, message: formatMessage({ id: 'route.request.override.inout.send.timeout' }) }]}
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.request.override.inout.send.timeout' }),
+              },
+            ]}
           >
             <InputNumber disabled={upstreamDisabled} />
           </Form.Item>
@@ -224,7 +296,12 @@ const RequestRewriteView: React.FC<Props> = ({ data, form, disabled, onChange })
           <Form.Item
             name={['timeout', 'read']}
             noStyle
-            rules={[{ required: true, message: formatMessage({ id: 'route.request.override.inout.receive.timeout' }) }]}
+            rules={[
+              {
+                required: true,
+                message: formatMessage({ id: 'route.request.override.inout.receive.timeout' }),
+              },
+            ]}
           >
             <InputNumber disabled={upstreamDisabled} />
           </Form.Item>
diff --git a/src/pages/Route/constants.ts b/src/pages/Route/constants.ts
index 97e602c..bca220b 100644
--- a/src/pages/Route/constants.ts
+++ b/src/pages/Route/constants.ts
@@ -60,6 +60,8 @@ export const DEFAULT_STEP_2_DATA: RouteModule.Step2Data = {
   upstreamHostList: [{} as RouteModule.UpstreamHost],
   upstreamHeaderList: [],
   upstreamPath: undefined,
+  mappingStrategy: undefined,
+  rewriteType: 'keep',
   timeout: {
     connect: 6000,
     send: 6000,
diff --git a/src/pages/Route/locales/en-US.ts b/src/pages/Route/locales/en-US.ts
index e0c3b30..78baa5f 100644
--- a/src/pages/Route/locales/en-US.ts
+++ b/src/pages/Route/locales/en-US.ts
@@ -157,4 +157,7 @@ export default {
   'route.list': 'Route List',
   'route.list.input': 'Please input',
   'route.list.create': 'Create',
+  'page.route.radio.static': 'Static',
+  'page.route.radio.regx': 'Regx',
+  'page.route.form.itemLabel.from': 'From',
 };
diff --git a/src/pages/Route/locales/zh-CN.ts b/src/pages/Route/locales/zh-CN.ts
index 0c67f4f..5894354 100644
--- a/src/pages/Route/locales/zh-CN.ts
+++ b/src/pages/Route/locales/zh-CN.ts
@@ -152,4 +152,7 @@ export default {
   'route.list': '路由列表',
   'route.list.input': '请输入',
   'route.list.create': '创建',
+  'page.route.radio.static': '静态重写',
+  'page.route.radio.regx': '正则重写',
+  'page.route.form.itemLabel.from': '原路径',
 };
diff --git a/src/pages/Route/transform.ts b/src/pages/Route/transform.ts
index 26b292c..5c27302 100644
--- a/src/pages/Route/transform.ts
+++ b/src/pages/Route/transform.ts
@@ -81,6 +81,13 @@ export const transformStepData = ({
     data.upstream_path = {
       to: step2Data.upstreamPath,
     };
+    if (step2Data.mappingStrategy) {
+      data.upstream_path = {
+        ...data.upstream_path,
+        from: step2Data.mappingStrategy,
+        type: 'regx',
+      };
+    }
   }
 
   if (step3Data.plugins.prometheus) {
@@ -95,6 +102,8 @@ export const transformStepData = ({
       'advancedMatchingRules',
       'upstreamHostList',
       'upstreamPath',
+      'rewriteType',
+      'mappingStrategy',
       'upstreamHeaderList',
       'websocket',
       'timeout',
@@ -169,6 +178,14 @@ export const transformRouteData = (data: RouteModule.Body) => {
     upstream_protocol = 'keep',
     upstream_id,
   } = data;
+  let rewriteType = 'keep';
+  if (upstream_path && upstream_path.to) {
+    if (upstream_path.from) {
+      rewriteType = 'regx';
+    } else {
+      rewriteType = 'static';
+    }
+  }
 
   const upstreamHeaderList = Object.entries(upstream_header || {}).map(([k, v]) => {
     return {
@@ -185,6 +202,8 @@ export const transformRouteData = (data: RouteModule.Body) => {
     upstreamHostList: transformUpstreamNodes(upstream?.nodes),
     upstream_id,
     upstreamPath: upstream_path?.to,
+    mappingStrategy: upstream_path?.from,
+    rewriteType,
     timeout: upstream?.timeout || {
       connect: 6000,
       send: 6000,
diff --git a/src/pages/Route/typing.d.ts b/src/pages/Route/typing.d.ts
index c8ec042..c766120 100644
--- a/src/pages/Route/typing.d.ts
+++ b/src/pages/Route/typing.d.ts
@@ -85,6 +85,8 @@ declare namespace RouteModule {
   type Step2Data = {
     upstream_protocol: 'http' | 'https' | 'keep';
     upstreamHostList: UpstreamHost[];
+    mappingStrategy: string | undefined;
+    rewriteType: string | undefined;
     upstreamPath: string | undefined;
     upstreamHeaderList: UpstreamHeader[];
     upstream_id?: string;
@@ -127,6 +129,7 @@ declare namespace RouteModule {
       };
     };
     upstream_path?: {
+      type?: string;
       from?: string;
       to: string;
     };