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/11 09:24:31 UTC
[incubator-apisix-dashboard] branch next updated: Feat plugins
(#254)
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 8b3dab5 Feat plugins (#254)
8b3dab5 is described below
commit 8b3dab5bc03450829b70e50a248dd6d8fc373885
Author: 琚致远 <ju...@apache.org>
AuthorDate: Thu Jun 11 17:24:21 2020 +0800
Feat plugins (#254)
* feat: refactor plugin list
* feat: added locale
* feat: refactor plugin initial
* feat: update category
* codes clean
* feat: added translation
* feat: added locale for limit-count
* feat: added locale for limit-req
* codes clean
---
src/components/PluginForm/PluginForm.tsx | 10 +-
src/components/PluginForm/data.ts | 128 ++++++++++++---------
src/components/PluginForm/index.ts | 2 -
src/components/PluginForm/locales/en-US.ts | 56 +++++++++
src/components/PluginForm/locales/zh-CN.ts | 54 +++++++++
src/components/PluginForm/service.ts | 2 -
src/components/PluginForm/typing.d.ts | 9 +-
src/pages/Routes/Create.tsx | 80 +++++++++----
.../Routes/components/CreateStep3/CreateStep3.tsx | 55 +++------
src/pages/Routes/constants.ts | 2 +
src/pages/Routes/service.ts | 2 +
src/pages/Routes/typing.d.ts | 2 +
12 files changed, 281 insertions(+), 121 deletions(-)
diff --git a/src/components/PluginForm/PluginForm.tsx b/src/components/PluginForm/PluginForm.tsx
index ee3018f..5b69bec 100644
--- a/src/components/PluginForm/PluginForm.tsx
+++ b/src/components/PluginForm/PluginForm.tsx
@@ -108,6 +108,7 @@ const PluginForm: React.FC<PluginForm.Props> = ({
initialData = {},
onFinish,
}) => {
+ const { formatMessage } = useIntl();
const [schema, setSchema] = useState<PluginForm.PluginSchema>();
useEffect(() => {
@@ -167,7 +168,14 @@ const PluginForm: React.FC<PluginForm.Props> = ({
return (
<Form.Item
- label={propertyName}
+ label={formatMessage({
+ id: `PluginForm.plugin.${name}.property.${propertyName}`,
+ defaultMessage: propertyName,
+ })}
+ extra={formatMessage({
+ id: `PluginForm.plugin.${name}.property.${propertyName}.extra`,
+ defaultMessage: '',
+ })}
name={propertyName}
key={propertyName}
rules={transformPropertyToRules(schema!, propertyName, propertyValue)}
diff --git a/src/components/PluginForm/data.ts b/src/components/PluginForm/data.ts
index f4d6afa..6cd12bd 100644
--- a/src/components/PluginForm/data.ts
+++ b/src/components/PluginForm/data.ts
@@ -1,83 +1,99 @@
-export const list: PluginForm.PluginProps[] = [
- {
- name: 'basic-auth',
+export const PLUGIN_MAPPER_SOURCE: { [name: string]: PluginForm.PluginMapperItem } = {
+ 'limit-req': {
+ category: 'Limit',
},
- {
- name: 'batch-requests',
+ 'limit-count': {
+ category: 'Limit',
},
- {
- name: 'cors',
+ 'limit-conn': {
+ category: 'Limit',
},
- {
- name: 'fault-injection',
+ 'key-auth': {
+ category: 'Security',
+ hidden: true,
},
- {
- name: 'grpc-transcoding',
+ 'basic-auth': {
+ category: 'Security',
+ hidden: true,
},
- {
- name: 'http-logger',
+ prometheus: {
+ category: 'Metric',
},
- {
- name: 'ip-restriction',
+ 'node-status': {
+ category: 'Other',
},
- {
- name: 'jwt-auth',
+ 'jwt-auth': {
+ category: 'Security',
+ hidden: true,
},
- {
- name: 'kafka-logger',
+ zipkin: {
+ category: 'Metric',
},
- {
- name: 'key-auth',
+ 'ip-restriction': {
+ category: 'Security',
},
- {
- name: 'limit-conn',
+ 'grpc-transcode': {
+ category: 'Other',
+ hidden: true,
},
- {
- name: 'limit-count',
+ 'serverless-pre-function': {
+ category: 'Other',
},
- {
- name: 'limit-req',
+ 'serverless-post-function': {
+ category: 'Other',
},
- {
- name: 'mqtt-proxy',
+ 'openid-connect': {
+ category: 'Security',
},
- {
- name: 'oauth',
+ 'proxy-rewrite': {
+ category: 'Other',
+ hidden: true,
},
- {
- name: 'prometheus',
+ redirect: {
+ category: 'Other',
+ hidden: true,
},
- {
- name: 'proxy-cache',
+ 'response-rewrite': {
+ category: 'Other',
},
- {
- name: 'proxy-mirror',
+ 'fault-injection': {
+ category: 'Security',
},
- {
- name: 'proxy-rewrite',
+ 'udp-logger': {
+ category: 'Log',
},
- {
- name: 'redirect',
+ 'wolf-rbac': {
+ category: 'Other',
+ hidden: true,
},
- {
- name: 'response-rewrite',
+ 'proxy-cache': {
+ category: 'Other',
},
- {
- name: 'serverless',
+ 'tcp-logger': {
+ category: 'Log',
},
- {
- name: 'syslog',
+ 'proxy-mirror': {
+ category: 'Other',
},
- {
- name: 'tcp-logger',
+ 'kafka-logger': {
+ category: 'Log',
},
- {
- name: 'udp-logger',
+ cors: {
+ category: 'Security',
},
- {
- name: 'wolf-rbac',
+ heartbeat: {
+ category: 'Other',
},
- {
- name: 'zipkin',
+ 'batch-requests': {
+ category: 'Other',
},
-];
+ 'http-logger': {
+ category: 'Log',
+ },
+ 'mqtt-proxy': {
+ category: 'Other',
+ },
+ oauth: {
+ category: 'Security',
+ },
+};
diff --git a/src/components/PluginForm/index.ts b/src/components/PluginForm/index.ts
index 4872268..8770cd6 100644
--- a/src/components/PluginForm/index.ts
+++ b/src/components/PluginForm/index.ts
@@ -1,5 +1,3 @@
export { default } from './PluginForm';
-export { fetchList as fetchPluginList } from './service';
-export { list as pluginList } from './data';
export { default as PluginFormZhCN } from './locales/zh-CN';
export { default as PluginFormEnUS } from './locales/en-US';
diff --git a/src/components/PluginForm/locales/en-US.ts b/src/components/PluginForm/locales/en-US.ts
index 9f57841..68ac691 100644
--- a/src/components/PluginForm/locales/en-US.ts
+++ b/src/components/PluginForm/locales/en-US.ts
@@ -17,11 +17,60 @@ export default {
'kafka-logger is a plugin which works as a Kafka client driver for the ngx_lua nginx module.',
'PluginForm.plugin.key-auth.desc':
'key-auth is an authentication plugin, it should work with consumer together.',
+
+ // TODO:
'PluginForm.plugin.limit-conn.desc':
'Limiting request concurrency (or concurrent connections) plugin for Apisix.',
+ 'PluginForm.plugin.limit-conn.property.burst': '',
+ 'PluginForm.plugin.limit-conn.property.burst.extra': '',
+ 'PluginForm.plugin.limit-conn.property.conn': '',
+ 'PluginForm.plugin.limit-conn.property.conn.extra': '',
+ 'PluginForm.plugin.limit-conn.property.default_conn_delay': '',
+ 'PluginForm.plugin.limit-conn.property.default_conn_delay.extra': '',
+ 'PluginForm.plugin.limit-conn.property.key': '',
+ 'PluginForm.plugin.limit-conn.property.key.extra': '',
+ 'PluginForm.plugin.limit-conn.property.rejected_code': '',
+ 'PluginForm.plugin.limit-conn.property.rejected_code.extra': '',
+
+ // FIXME
'PluginForm.plugin.limit-count.desc':
'Limit request rate by a fixed number of requests in a given time window.',
+ 'PluginForm.plugin.limit-count.property.count': '单位窗口内请求数量',
+ 'PluginForm.plugin.limit-count.property.count.extra': '指定时间窗口内的请求数量阈值',
+ 'PluginForm.plugin.limit-count.property.time_window': '时间窗口大小',
+ 'PluginForm.plugin.limit-count.property.time_window.extra':
+ '时间窗口的大小(以秒为单位),超过这个时间就会重置',
+ 'PluginForm.plugin.limit-count.property.key': 'Key',
+ 'PluginForm.plugin.limit-count.property.key.extra': '用来做请求计数的依据',
+ 'PluginForm.plugin.limit-count.property.rejected_code': '错误 HTTP 状态码',
+ 'PluginForm.plugin.limit-count.property.rejected_code.extra':
+ '当请求超过阈值时返回的 HTTP 状态码, 默认值是503。',
+ 'PluginForm.plugin.limit-count.property.policy': '策略',
+ 'PluginForm.plugin.limit-count.property.policy.extra': '用于检索和增加限制的速率限制策略',
+ 'PluginForm.plugin.limit-count.property.redis_host': ' Redis 地址',
+ 'PluginForm.plugin.limit-count.property.redis_host.extra': ' Redis 服务节点的地址',
+ 'PluginForm.plugin.limit-count.property.redis_port': 'Redis 端口',
+ 'PluginForm.plugin.limit-count.property.redis_port.extra': 'Redis 服务节点的端口',
+ 'PluginForm.plugin.limit-count.property.redis_password': 'Redis 密码',
+ 'PluginForm.plugin.limit-count.property.redis_password.extra': 'Redis 服务节点的密码',
+ 'PluginForm.plugin.limit-count.property.redis_timeout': 'Redis 超时时间',
+ 'PluginForm.plugin.limit-count.property.redis_timeout.extra':
+ 'Redis 服务节点以毫秒为单位的超时时间',
+
+ // FIXME
'PluginForm.plugin.limit-req.desc': 'limit request rate using the "leaky bucket" method.',
+ 'PluginForm.plugin.limit-req.property.rate': 'Rate',
+ 'PluginForm.plugin.limit-req.property.rate.extra':
+ '指定的请求速率(以秒为单位),请求速率超过 rate 但没有超过 (rate + brust)的请求会被加上延时。',
+ 'PluginForm.plugin.limit-req.property.burst': 'Burst',
+ 'PluginForm.plugin.limit-req.property.burst.extra':
+ '请求速率超过 (rate + brust)的请求会被直接拒绝。',
+ 'PluginForm.plugin.limit-req.property.key': 'Key',
+ 'PluginForm.plugin.limit-req.property.key.extra': '用来做请求计数的依据',
+ 'PluginForm.plugin.limit-req.property.rejected_code': '错误 HTTP 状态码',
+ 'PluginForm.plugin.limit-req.property.rejected_code.extra':
+ '当请求超过阈值时返回的 HTTP 状态码, 默认值是503。',
+
'PluginForm.plugin.mqtt-proxy.desc':
'The plugin mqtt-proxy only works in stream model, it help you to dynamic load balance by client_id of MQTT.',
'PluginForm.plugin.oauth.desc':
@@ -46,4 +95,11 @@ export default {
'PluginForm.plugin.wolf-rbac.desc':
'wolf-rbac is an authentication and authorization (rbac) plugin',
'PluginForm.plugin.zipkin.desc': 'Zipkin is a OpenTracing plugin.',
+ 'PluginForm.plugin.node-status.desc': 'No description currently.',
+ 'PluginForm.plugin.serverless-pre-function.desc':
+ 'It belongs to serverless, and will execute first',
+ 'PluginForm.plugin.serverless-post-function.desc':
+ 'It belongs to serverless and will execute in the end',
+ 'PluginForm.plugin.openid-connect.desc': 'No description currently.',
+ 'PluginForm.plugin.heartbeat.desc': 'No description currently.',
};
diff --git a/src/components/PluginForm/locales/zh-CN.ts b/src/components/PluginForm/locales/zh-CN.ts
index 548ecfa..5ea1019 100644
--- a/src/components/PluginForm/locales/zh-CN.ts
+++ b/src/components/PluginForm/locales/zh-CN.ts
@@ -17,10 +17,59 @@ export default {
'kafka-logger 是一个插件,可用作ngx_lua nginx 模块的 Kafka 客户端驱动程序。',
'PluginForm.plugin.key-auth.desc':
'key-auth 是一个认证插件,它需要与 consumer 一起配合才能工作。',
+
'PluginForm.plugin.limit-conn.desc': 'APISIX 的限制并发请求(或并发连接)插件。',
+ 'PluginForm.plugin.limit-conn.property.burst': '最大并发请求数',
+ 'PluginForm.plugin.limit-conn.property.burst.extra': '允许的最大并发请求数',
+ 'PluginForm.plugin.limit-conn.property.conn': '可延迟并发请求数',
+ 'PluginForm.plugin.limit-conn.property.conn.extra': '允许延迟的过多并发请求(或连接)的数量。',
+ 'PluginForm.plugin.limit-conn.property.default_conn_delay': '默认请求延迟时间',
+ 'PluginForm.plugin.limit-conn.property.default_conn_delay.extra':
+ '默认的典型连接(或请求)的处理延迟时间。',
+ 'PluginForm.plugin.limit-conn.property.key': '关键字',
+ 'PluginForm.plugin.limit-conn.property.key.extra':
+ '用户指定的限制并发级别的关键字,可以是客户端IP或服务端IP。',
+ 'PluginForm.plugin.limit-conn.property.rejected_code': '错误 HTTP 状态码',
+ 'PluginForm.plugin.limit-conn.property.rejected_code.extra':
+ '当请求超过阈值时返回的 HTTP 状态码, 默认值是503。',
+
'PluginForm.plugin.limit-count.desc':
'和 GitHub API 的限速类似, 在指定的时间范围内,限制总的请求个数。并且在 HTTP 响应头中返回剩余可以请求的个数。',
+ 'PluginForm.plugin.limit-count.property.count': '单位窗口内请求数量',
+ 'PluginForm.plugin.limit-count.property.count.extra': '指定时间窗口内的请求数量阈值',
+ 'PluginForm.plugin.limit-count.property.time_window': '时间窗口大小',
+ 'PluginForm.plugin.limit-count.property.time_window.extra':
+ '时间窗口的大小(以秒为单位),超过这个时间就会重置',
+ 'PluginForm.plugin.limit-count.property.key': 'Key',
+ 'PluginForm.plugin.limit-count.property.key.extra': '用来做请求计数的依据',
+ 'PluginForm.plugin.limit-count.property.rejected_code': '错误 HTTP 状态码',
+ 'PluginForm.plugin.limit-count.property.rejected_code.extra':
+ '当请求超过阈值时返回的 HTTP 状态码, 默认值是503。',
+ 'PluginForm.plugin.limit-count.property.policy': '策略',
+ 'PluginForm.plugin.limit-count.property.policy.extra': '用于检索和增加限制的速率限制策略',
+ 'PluginForm.plugin.limit-count.property.redis_host': ' Redis 地址',
+ 'PluginForm.plugin.limit-count.property.redis_host.extra': ' Redis 服务节点的地址',
+ 'PluginForm.plugin.limit-count.property.redis_port': 'Redis 端口',
+ 'PluginForm.plugin.limit-count.property.redis_port.extra': 'Redis 服务节点的端口',
+ 'PluginForm.plugin.limit-count.property.redis_password': 'Redis 密码',
+ 'PluginForm.plugin.limit-count.property.redis_password.extra': 'Redis 服务节点的密码',
+ 'PluginForm.plugin.limit-count.property.redis_timeout': 'Redis 超时时间',
+ 'PluginForm.plugin.limit-count.property.redis_timeout.extra':
+ 'Redis 服务节点以毫秒为单位的超时时间',
+
'PluginForm.plugin.limit-req.desc': '限制请求速度的插件,使用的是漏桶算法。',
+ 'PluginForm.plugin.limit-req.property.rate': 'Rate',
+ 'PluginForm.plugin.limit-req.property.rate.extra':
+ '指定的请求速率(以秒为单位),请求速率超过 rate 但没有超过 (rate + brust)的请求会被加上延时。',
+ 'PluginForm.plugin.limit-req.property.burst': 'Burst',
+ 'PluginForm.plugin.limit-req.property.burst.extra':
+ '请求速率超过 (rate + brust)的请求会被直接拒绝。',
+ 'PluginForm.plugin.limit-req.property.key': 'Key',
+ 'PluginForm.plugin.limit-req.property.key.extra': '用来做请求计数的依据',
+ 'PluginForm.plugin.limit-req.property.rejected_code': '错误 HTTP 状态码',
+ 'PluginForm.plugin.limit-req.property.rejected_code.extra':
+ '当请求超过阈值时返回的 HTTP 状态码, 默认值是503。',
+
'PluginForm.plugin.mqtt-proxy.desc':
'mqtt-proxy 只工作在流模式,它可以帮助你根据 MQTT 的 client_id 实现动态负载均衡。',
'PluginForm.plugin.oauth.desc':
@@ -40,4 +89,9 @@ export default {
'PluginForm.plugin.wolf-rbac.desc':
'wolf-rbac 是一个认证及授权(rbac)插件,它需要与 consumer 一起配合才能工作。',
'PluginForm.plugin.zipkin.desc': 'zipkin 是一个开源的服务跟踪插件。',
+ 'PluginForm.plugin.node-status.desc': '暂无描述',
+ 'PluginForm.plugin.serverless-pre-function.desc': '属于 serverless,会在指定阶段最开始运行。',
+ 'PluginForm.plugin.serverless-post-function.desc': '属于 serverless,会在指定阶段最后运行。',
+ 'PluginForm.plugin.openid-connect.desc': '暂无描述。',
+ 'PluginForm.plugin.heartbeat.desc': '暂无描述',
};
diff --git a/src/components/PluginForm/service.ts b/src/components/PluginForm/service.ts
index 447bd9a..a688e9c 100644
--- a/src/components/PluginForm/service.ts
+++ b/src/components/PluginForm/service.ts
@@ -1,7 +1,5 @@
import { request } from 'umi';
import { transformSchemaFromAPI } from './transformer';
-export const fetchList = () => request('/plugins/list');
-
export const fetchPluginSchema = (name: string): Promise<PluginForm.PluginSchema> =>
request(`/schema/plugins/${name}`).then((data) => transformSchemaFromAPI(data, name));
diff --git a/src/components/PluginForm/typing.d.ts b/src/components/PluginForm/typing.d.ts
index 0d1fb08..dbc106b 100644
--- a/src/components/PluginForm/typing.d.ts
+++ b/src/components/PluginForm/typing.d.ts
@@ -51,7 +51,14 @@ declare namespace PluginForm {
};
}
- interface PluginProps {
+ type PluginCategory = 'Security' | 'Limit' | 'Log' | 'Metric' | 'Other';
+
+ type PluginMapperItem = {
+ category: PluginCategory;
+ hidden?: boolean;
+ };
+
+ interface PluginProps extends PluginMapperItem {
name: string;
}
}
diff --git a/src/pages/Routes/Create.tsx b/src/pages/Routes/Create.tsx
index 02187d3..4dd8d78 100644
--- a/src/pages/Routes/Create.tsx
+++ b/src/pages/Routes/Create.tsx
@@ -2,7 +2,8 @@ import React, { useState, useEffect } from 'react';
import { Card, Steps, Form } from 'antd';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
-import { createRoute, fetchRoute, updateRoute } from './service';
+import { PLUGIN_MAPPER_SOURCE } from '@/components/PluginForm/data';
+import { createRoute, fetchRoute, updateRoute, fetchPluginList } from './service';
import Step1 from './components/Step1';
import Step2 from './components/Step2';
import CreateStep3 from './components/CreateStep3';
@@ -20,7 +21,13 @@ import styles from './Create.less';
const { Step } = Steps;
-const Create: React.FC = (props) => {
+type Props = {
+ // FIXME
+ route: any;
+ match: any;
+};
+
+const Create: React.FC<Props> = (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);
@@ -39,7 +46,33 @@ const Create: React.FC = (props) => {
step3Data,
};
- const initRoute = (rid: number) => {
+ const setupPlugin = () => {
+ const PLUGIN_BLOCK_LIST = Object.entries(PLUGIN_MAPPER_SOURCE)
+ .filter(([, value]) => value.hidden)
+ .flat()
+ .filter((item) => typeof item === 'string');
+
+ fetchPluginList().then((data: string[]) => {
+ const names = data.filter((name) => !PLUGIN_BLOCK_LIST.includes(name));
+
+ const enabledNames = Object.keys(step3Data.plugins);
+ const disabledNames = names.filter((name) => !enabledNames.includes(name));
+
+ setStep3Data({
+ plugins: step3Data.plugins,
+ _disabledPluginList: disabledNames.map((name) => ({
+ name,
+ ...PLUGIN_MAPPER_SOURCE[name],
+ })),
+ _enabledPluginList: enabledNames.map((name) => ({
+ name,
+ ...PLUGIN_MAPPER_SOURCE[name],
+ })),
+ });
+ });
+ };
+
+ const setupRoute = (rid: number) =>
fetchRoute(rid).then((data) => {
form1.setFieldsValue(data.step1Data);
setStep1Data(data.step1Data as RouteModule.Step1Data);
@@ -49,30 +82,36 @@ const Create: React.FC = (props) => {
setStep3Data(data.step3Data);
});
- };
useEffect(() => {
- if ((props as any).route.name === 'edit') {
- initRoute((props as any).match.params.rid);
+ console.log(props);
+ if (props.route.name === 'edit') {
+ setupRoute(props.match.params.rid).then(() => setupPlugin());
+ } else {
+ setupPlugin();
}
}, []);
useEffect(() => {
- if (step1Data.redirectURI !== '') {
- if (step1Data.forceHttps) {
- setStep1Data({ ...step1Data, redirectURI: '' });
- setRedirect(false);
- setStepHeader(STEP_HEADER_4);
- return;
- }
- setRedirect(true);
- setStepHeader(STEP_HEADER_2);
- } else {
+ const { redirectURI, forceHttps } = step1Data;
+ if (redirectURI === '') {
setRedirect(false);
setStepHeader(STEP_HEADER_4);
+ return;
+ }
+
+ if (!forceHttps) {
+ setRedirect(true);
+ setStepHeader(STEP_HEADER_2);
+ return;
}
+
+ setStep1Data({ ...step1Data, redirectURI: '' });
+ setRedirect(false);
+ setStepHeader(STEP_HEADER_4);
}, [step1Data]);
+ // FIXME
const onReset = () => {
setStep1Data(DEFAULT_STEP_1_DATA);
setStep2Data(DEFAULT_STEP_2_DATA);
@@ -101,6 +140,7 @@ const Create: React.FC = (props) => {
<CreateStep4 data={routeData} form1={form1} form2={form2} onChange={() => {}} redirect />
);
}
+
return (
<Step2
data={routeData}
@@ -183,13 +223,7 @@ const Create: React.FC = (props) => {
{renderStep()}
</Card>
</PageHeaderWrapper>
- <ActionBar
- step={step}
- redirect={redirect}
- onChange={(nextStep) => {
- onStepChange(nextStep);
- }}
- />
+ <ActionBar step={step} redirect={redirect} onChange={onStepChange} />
</>
);
};
diff --git a/src/pages/Routes/components/CreateStep3/CreateStep3.tsx b/src/pages/Routes/components/CreateStep3/CreateStep3.tsx
index 8d20af4..59e08c2 100644
--- a/src/pages/Routes/components/CreateStep3/CreateStep3.tsx
+++ b/src/pages/Routes/components/CreateStep3/CreateStep3.tsx
@@ -1,8 +1,8 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
import { SettingOutlined, LinkOutlined } from '@ant-design/icons';
import { omit, merge } from 'lodash';
-import { pluginList } from '@/components/PluginForm';
+import { PLUGIN_MAPPER_SOURCE } from '@/components/PluginForm/data';
import PanelSection from '../PanelSection';
import PluginDrawer from './PluginDrawer';
import PluginCard from './PluginCard';
@@ -17,38 +17,13 @@ const sectionStyle = {
};
const CreateStep3: React.FC<Props> = ({ data, disabled, onChange }) => {
- // NOTE: Plugin in blacklist WILL NOT be shown on Step3.
- const pluginBlackList = [
- 'basic-auth',
- 'batch-requests',
- 'grpc-transcoding',
- 'http-logger',
- 'jwt-auth',
- 'key-auth',
- 'mqtt-proxy',
- 'oauth',
- 'redirect',
- 'wolf-rbac',
- // BUG:
- 'proxy-rewrite',
- ];
-
- const list = pluginList.filter(({ name }) => !pluginBlackList.includes(name));
- const [activeList, setActiveList] = useState<PluginForm.PluginProps[]>([]);
- const [inactiveList, setInactiveList] = useState<PluginForm.PluginProps[]>([]);
-
- useEffect(() => {
- const pluginKeys = Object.keys(data.step3Data.plugins || []);
- setActiveList(list.filter((item) => pluginKeys.includes(item.name)));
- setInactiveList(list.filter((item) => !pluginKeys.includes(item.name)));
- }, [data.step3Data.plugins]);
-
const [currentPlugin, setCurrentPlugin] = useState<string | undefined>();
+ const { _disabledPluginList = [], _enabledPluginList = [] } = data.step3Data;
return (
<>
<PanelSection title="已启用" style={sectionStyle}>
- {activeList.map(({ name }) => (
+ {_enabledPluginList.map(({ name }) => (
<PluginCard
name={name}
actions={[
@@ -67,7 +42,7 @@ const CreateStep3: React.FC<Props> = ({ data, disabled, onChange }) => {
</PanelSection>
{!disabled && (
<PanelSection title="未启用" style={sectionStyle}>
- {inactiveList.map(({ name }) => (
+ {_disabledPluginList.map(({ name }) => (
<PluginCard
name={name}
actions={[
@@ -89,15 +64,23 @@ const CreateStep3: React.FC<Props> = ({ data, disabled, onChange }) => {
name={currentPlugin}
disabled={disabled}
initialData={currentPlugin ? data.step3Data.plugins[currentPlugin] : {}}
- active={Boolean(activeList.find((item) => item.name === currentPlugin))}
+ active={Boolean(_enabledPluginList.find((item) => item.name === currentPlugin))}
onActive={(name: string) => {
- setInactiveList(inactiveList.filter((item) => item.name !== name));
- setActiveList(activeList.concat({ name }));
+ onChange({
+ ...data.step3Data,
+ _disabledPluginList: _disabledPluginList.filter((item) => item.name !== name),
+ _enabledPluginList: _enabledPluginList.concat({ name, ...PLUGIN_MAPPER_SOURCE[name] }),
+ });
}}
onInactive={(name: string) => {
- setActiveList(activeList.filter((item) => item.name !== name));
- setInactiveList(inactiveList.concat({ name }));
- onChange(omit({ ...data.step3Data }, `plugins.${currentPlugin}`));
+ onChange({
+ ...omit({ ...data.step3Data }, `plugins.${currentPlugin}`),
+ _disabledPluginList: _disabledPluginList.concat({
+ name,
+ ...PLUGIN_MAPPER_SOURCE[name],
+ }),
+ _enabledPluginList: _enabledPluginList.filter((item) => item.name !== name),
+ });
setCurrentPlugin(undefined);
}}
onClose={() => setCurrentPlugin(undefined)}
diff --git a/src/pages/Routes/constants.ts b/src/pages/Routes/constants.ts
index c0ef624..5bcb489 100644
--- a/src/pages/Routes/constants.ts
+++ b/src/pages/Routes/constants.ts
@@ -52,6 +52,8 @@ export const DEFAULT_STEP_2_DATA: RouteModule.Step2Data = {
export const DEFAULT_STEP_3_DATA: RouteModule.Step3Data = {
plugins: {},
+ _enabledPluginList: [],
+ _disabledPluginList: [],
};
export const STEP_HEADER_2 = ['定义 API 请求', '预览'];
diff --git a/src/pages/Routes/service.ts b/src/pages/Routes/service.ts
index 9300030..9049d62 100644
--- a/src/pages/Routes/service.ts
+++ b/src/pages/Routes/service.ts
@@ -21,3 +21,5 @@ export const fetchRouteList = (wid = 0) => request(`/workspaces/${wid}/routes?pa
export const removeRoute = (rid: number, wid = 0) =>
request(`/workspaces/${wid}/routes/${rid}`, { method: 'DELETE' });
+
+export const fetchPluginList = () => request('/plugins');
diff --git a/src/pages/Routes/typing.d.ts b/src/pages/Routes/typing.d.ts
index 6b42531..aad0372 100644
--- a/src/pages/Routes/typing.d.ts
+++ b/src/pages/Routes/typing.d.ts
@@ -38,6 +38,8 @@ declare namespace RouteModule {
plugins: {
[name: string]: any;
};
+ _enabledPluginList: PluginForm.PluginProps[];
+ _disabledPluginList: PluginForm.PluginProps[];
};
interface Data {