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[];