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/03 11:16:46 UTC

[incubator-apisix-dashboard] branch next updated: feat: added api

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 6bd13a5  feat: added api
6bd13a5 is described below

commit 6bd13a58907c9b1a19942f99fbe5280f60681c8c
Author: juzhiyuan <jj...@gmail.com>
AuthorDate: Wed Jun 3 19:16:14 2020 +0800

    feat: added api
---
 config/routes.ts                                   |  6 ++
 src/locales/en-US/menu.ts                          |  1 +
 src/locales/zh-CN/menu.ts                          |  1 +
 src/pages/Routes/Create.tsx                        | 46 +++++++++++----
 .../Routes/components/Step1/MatchingRulesView.tsx  |  4 +-
 src/pages/Routes/service.ts                        | 16 +++--
 src/pages/Routes/transform.ts                      | 69 +++++++++++++++++++++-
 src/pages/Routes/typing.d.ts                       | 10 +++-
 8 files changed, 130 insertions(+), 23 deletions(-)

diff --git a/config/routes.ts b/config/routes.ts
index 1fee575..84ea03d 100644
--- a/config/routes.ts
+++ b/config/routes.ts
@@ -48,6 +48,12 @@ const routes = [
         component: './Routes/Create',
         hideInMenu: true,
       },
+      {
+        path: '/routes/:rid/edit',
+        name: 'edit',
+        component: './Routes/Create',
+        hideInMenu: true,
+      },
     ],
   },
   {
diff --git a/src/locales/en-US/menu.ts b/src/locales/en-US/menu.ts
index 17b5b37..1409f6d 100644
--- a/src/locales/en-US/menu.ts
+++ b/src/locales/en-US/menu.ts
@@ -55,4 +55,5 @@ export default {
   'menu.setting': 'Settings',
   'menu.routes': 'Route',
   'menu.routes.create': 'Create a Route',
+  'menu.routes.edit': 'Edit the Route',
 };
diff --git a/src/locales/zh-CN/menu.ts b/src/locales/zh-CN/menu.ts
index 7278b7c..6a6f5c6 100644
--- a/src/locales/zh-CN/menu.ts
+++ b/src/locales/zh-CN/menu.ts
@@ -55,4 +55,5 @@ export default {
   'menu.setting': '设置',
   'menu.routes': '路由',
   'menu.routes.create': '创建',
+  'menu.routes.edit': '编辑',
 };
diff --git a/src/pages/Routes/Create.tsx b/src/pages/Routes/Create.tsx
index 5a7dbad..6584cf4 100644
--- a/src/pages/Routes/Create.tsx
+++ b/src/pages/Routes/Create.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useState, useEffect } from 'react';
 import { Card, Steps, Form, notification } from 'antd';
 import { PageHeaderWrapper } from '@ant-design/pro-layout';
 
@@ -9,11 +9,11 @@ import CreateStep3 from './components/CreateStep3';
 import ActionBar from './components/ActionBar';
 import CreateStep4 from './components/CreateStep4';
 import { DEFAULT_STEP_1_DATA, DEFAULT_STEP_2_DATA, DEFAULT_STEP_3_DATA } from './constants';
-import { createRoute } from './service';
+import { createRoute, fetchRoute, updateRoute } from './service';
 
 const { Step } = Steps;
 
-const Create: React.FC = () => {
+const Create: React.FC = (props) => {
   const [step1Data, setStep1Data] = useState(DEFAULT_STEP_1_DATA);
   const [step2Data, setStep2Data] = useState(DEFAULT_STEP_2_DATA);
   const [step3Data, setStep3Data] = useState(DEFAULT_STEP_3_DATA);
@@ -24,17 +24,35 @@ const Create: React.FC = () => {
   const [step, setStep] = useState(0);
   const [stepHeader] = useState(['定义 API 请求', '定义 API 后端服务', '插件配置', '预览']);
 
-  const data = {
+  const routeData = {
     step1Data,
     step2Data,
     step3Data,
   };
 
+  const initRoute = (rid: number) => {
+    fetchRoute(rid).then((data) => {
+      form1.setFieldsValue(data.step1Data);
+      setStep1Data(data.step1Data);
+
+      form2.setFieldsValue(data.step2Data);
+      setStep2Data(data.step2Data);
+
+      setStep3Data(data.step3Data);
+    });
+  };
+
+  useEffect(() => {
+    if ((props as any).route.name === 'edit') {
+      initRoute((props as any).match.params.rid);
+    }
+  }, []);
+
   const renderStep = () => {
     if (step === 0) {
       return (
         <Step1
-          data={data}
+          data={routeData}
           form={form1}
           onChange={(_data: RouteModule.Step1Data) => {
             setStep1Data(_data);
@@ -46,7 +64,7 @@ const Create: React.FC = () => {
     if (step === 1) {
       return (
         <Step2
-          data={data}
+          data={routeData}
           form={form2}
           onChange={(params: RouteModule.Step2Data) => setStep2Data({ ...step2Data, ...params })}
         />
@@ -54,11 +72,11 @@ const Create: React.FC = () => {
     }
 
     if (step === 2) {
-      return <CreateStep3 data={data} onChange={setStep3Data} />;
+      return <CreateStep3 data={routeData} onChange={setStep3Data} />;
     }
 
     if (step === 3) {
-      return <CreateStep4 data={data} form1={form1} form2={form2} onChange={() => {}} />;
+      return <CreateStep4 data={routeData} form1={form1} form2={form2} onChange={() => {}} />;
     }
 
     return null;
@@ -86,9 +104,15 @@ const Create: React.FC = () => {
       setStep(nextStep);
     }
     if (nextStep === 4) {
-      createRoute({ data }).then(() => {
-        notification.success({ message: '创建路由成功' });
-      });
+      if ((props as any).route.name === 'edit') {
+        updateRoute((props as any).match.params.rid, { data: routeData }).then(() => {
+          notification.success({ message: '更新路由成功' });
+        });
+      } else {
+        createRoute({ data: routeData }).then(() => {
+          notification.success({ message: '创建路由成功' });
+        });
+      }
     }
   };
   return (
diff --git a/src/pages/Routes/components/Step1/MatchingRulesView.tsx b/src/pages/Routes/components/Step1/MatchingRulesView.tsx
index dc0522b..9bbda2c 100644
--- a/src/pages/Routes/components/Step1/MatchingRulesView.tsx
+++ b/src/pages/Routes/components/Step1/MatchingRulesView.tsx
@@ -110,8 +110,8 @@ const MatchingRulesView: React.FC<Props> = ({ data, disabled, onChange }) => {
             rules={[{ required: true, message: '请选择参数位置' }]}
           >
             <Select>
-              <Option value="header">HTTP 请求头</Option>
-              <Option value="arguments">请求参数</Option>
+              <Option value="http">HTTP 请求头</Option>
+              <Option value="arg">请求参数</Option>
               <Option value="cookie">Cookie</Option>
             </Select>
           </Form.Item>
diff --git a/src/pages/Routes/service.ts b/src/pages/Routes/service.ts
index e4427ba..f53c0f2 100644
--- a/src/pages/Routes/service.ts
+++ b/src/pages/Routes/service.ts
@@ -1,12 +1,18 @@
 import { request } from 'umi';
 
-import { transformStepData } from './transform';
+import { transformStepData, transformRouteData } from './transform';
 
-export const createRoute = (data: Pick<RouteModule.Data, 'data'>) => {
-  return request('/workspaces/default/routes', {
+export const createRoute = (data: Pick<RouteModule.Data, 'data'>) =>
+  request('/workspaces/default/routes', {
     method: 'POST',
     data: transformStepData(data),
   });
-};
 
-export const updateRoute = () => {};
+export const updateRoute = (rid: number, data: Pick<RouteModule.Data, 'data'>, wid: number = 0) =>
+  request(`/workspaces/${wid}/routes/${rid}`, {
+    method: 'PUT',
+    data: transformStepData(data),
+  });
+
+export const fetchRoute = (rid: number, wid: number = 0) =>
+  request(`/workspaces/${wid}/routes/${rid}`).then((data) => transformRouteData(data));
diff --git a/src/pages/Routes/transform.ts b/src/pages/Routes/transform.ts
index ee3896f..7d36f22 100644
--- a/src/pages/Routes/transform.ts
+++ b/src/pages/Routes/transform.ts
@@ -35,11 +35,11 @@ export const transformStepData = ({
         case 'cookie':
           key = `cookie_${name}`;
           break;
-        case 'header':
+        case 'http':
           key = `http_${name}`;
           break;
         default:
-          key = `args_${name}`;
+          key = `arg_${name}`;
       }
       return [key, operator, value];
     }),
@@ -64,3 +64,68 @@ export const transformStepData = ({
     'timeout',
   ]);
 };
+
+const transformVarsToRules = (
+  data: [string, RouteModule.Operator, string][],
+): RouteModule.MatchingRule[] =>
+  data.map(([key, operator, value]) => {
+    const [position, name] = key.split('_');
+    return {
+      position: position as RouteModule.VarPosition,
+      name,
+      value,
+      operator,
+      key: Math.random().toString(36).slice(2),
+    };
+  });
+
+const transformUpstreamNodes = (nodes: { [key: string]: number }): RouteModule.UpstreamHost[] => {
+  const data: RouteModule.UpstreamHost[] = [];
+  Object.entries(nodes).forEach(([k, v]) => {
+    const [host, port] = k.split(':');
+    data.push({ host, port: Number(port), weight: Number(v) });
+  });
+  return data;
+};
+
+export const transformRouteData = (data: RouteModule.Body) => {
+  const { name, desc, methods, uris, protocols, hosts, vars } = data;
+  // TODO: redirect
+
+  const step1Data: RouteModule.Step1Data = {
+    name,
+    desc,
+    protocols: protocols.filter((item) => item !== 'websocket'),
+    websocket: protocols.includes('websocket'),
+    hosts,
+    paths: uris,
+    methods,
+    advancedMatchingRules: transformVarsToRules(vars),
+  };
+
+  const { upstream, upstream_path, upstream_header } = data;
+
+  const upstreamHeaderList = Object.entries(upstream_header).map(([k, v]) => {
+    return { header_name: k, header_value: v, key: Math.random().toString(36).slice(2) };
+  });
+
+  const step2Data: RouteModule.Step2Data = {
+    // TODO: API
+    upstreamProtocol: 'original',
+    upstreamHeaderList,
+    upstreamHostList: transformUpstreamNodes(upstream.nodes),
+    upstreamPath: upstream_path.to,
+    timeout: upstream.timeout,
+  };
+
+  const { plugins } = data;
+  const step3Data: RouteModule.Step3Data = {
+    plugins,
+  };
+
+  return {
+    step1Data,
+    step2Data,
+    step3Data,
+  };
+};
diff --git a/src/pages/Routes/typing.d.ts b/src/pages/Routes/typing.d.ts
index 1bb29e3..fcbcb25 100644
--- a/src/pages/Routes/typing.d.ts
+++ b/src/pages/Routes/typing.d.ts
@@ -1,8 +1,10 @@
 declare namespace RouteModule {
   type Operator = '==' | '~=' | '>' | '<' | '~~';
 
+  type VarPosition = 'arg' | 'http' | 'cookie';
+
   interface MatchingRule {
-    position: 'query' | 'params' | 'header' | 'cookie';
+    position: VarPosition;
     name: string;
     operator: Operator;
     value: string;
@@ -14,6 +16,7 @@ declare namespace RouteModule {
 
   type Step1Data = {
     name: string;
+    desc: string;
     protocols: RequestProtocol[];
     websocket: boolean;
     hosts: string[];
@@ -39,7 +42,7 @@ declare namespace RouteModule {
   }
 
   type UpstreamHost = {
-    host: '';
+    host: string;
     port: number;
     weight: number;
   };
@@ -69,8 +72,9 @@ declare namespace RouteModule {
 
   // Request Body or Response Data for API
   type Body = {
+    id?: number;
     name: string;
-    desc?: string;
+    desc: string;
     priority?: number;
     methods: HttpMethod[];
     uris: string[];