Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 72 additions & 5 deletions config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,19 @@ const routes = [
{
path: '/ssl/list',
name: 'list',
component: './ssl/List',
component: './SSL/List',
hideInMenu: true,
},
{
name: 'create',
path: '/ssl/create',
component: './ssl/Create',
component: './SSL/Create',
hideInMenu: true,
},
{
name: 'edit',
path: '/ssl/:id/edit',
component: './SSL/Create',
hideInMenu: true,
},
],
Expand All @@ -52,18 +58,79 @@ const routes = [
path: '/routes/list',
name: 'list',
icon: 'BarsOutlined',
component: './Routes/List',
component: './Route/List',
hideInMenu: true,
},
{
path: '/routes/create',
name: 'create',
component: './Routes/Create',
component: './Route/Create',
hideInMenu: true,
},
{
path: '/routes/:rid/edit',
name: 'edit',
component: './Routes/Create',
component: './Route/Create',
hideInMenu: true,
},
],
},
{
name: 'consumer',
path: '/consumer',
icon: 'BarsOutlined',
routes: [
{
path: '/consumer',
redirect: '/Consumer/list',
},
{
path: '/consumer/list',
name: 'list',
icon: 'BarsOutlined',
component: './Consumer/List',
hideInMenu: true,
},
{
path: '/consumer/create',
name: 'create',
component: './Consumer/Create',
hideInMenu: true,
},
{
path: '/consumer/:id/edit',
name: 'edit',
component: './Consumer/Create',
hideInMenu: true,
},
],
},
{
name: 'upstream',
path: '/upstream',
icon: 'BarsOutlined',
routes: [
{
path: '/upstream',
redirect: '/Upstream/list',
},
{
path: '/upstream/list',
name: 'list',
icon: 'BarsOutlined',
component: './Upstream/List',
hideInMenu: true,
},
{
path: '/upstream/create',
name: 'create',
component: './Upstream/Create',
hideInMenu: true,
},
{
path: '/upstream/:id/edit',
name: 'edit',
component: './Upstream/Create',
hideInMenu: true,
},
],
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@
},
"husky": {
"hooks": {
"pre-commit": "npm run lint-staged",
"commit-msg": "node scripts/verifyCommit.js"
"pre-commit": "npm run lint-staged"
}
},
"lint-staged": {
Expand All @@ -48,8 +47,12 @@
"@ant-design/icons": "^4.2.1",
"@ant-design/pro-layout": "6.0.0-2",
"@ant-design/pro-table": "^2.3.3",
"@rjsf/antd": "^2.2.0",
"@rjsf/core": "^2.2.0",
"antd": "^4.3.3",
"classnames": "^2.2.6",
"dayjs": "^1.8.28",
"json-schema": "^0.2.5",
"lodash": "^4.17.15",
"moment": "^2.25.3",
"nzh": "^1.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import { Row, Col, Button } from 'antd';

interface Props {
step: number;
lastStep: number;
onChange(nextStep: number): void;
redirect?: boolean;
withResultView?: boolean;
}

const style: CSSProperties = {
Expand All @@ -19,23 +20,23 @@ const style: CSSProperties = {
width: '100%',
};

const ActionBar: React.FC<Props> = ({ step, onChange, redirect }) => {
if (step > 3) {
const ActionBar: React.FC<Props> = ({ step, lastStep, onChange, withResultView }) => {
if (step > lastStep && !withResultView) {
onChange(lastStep);
return null;
}

return (
<div style={style}>
<Row gutter={10} justify="end">
<Col>
<Button type="primary" onClick={() => onChange(step - 1)} disabled={step === 0}>
<Button type="primary" onClick={() => onChange(step - 1)} disabled={step === 1}>
上一步
</Button>
</Col>
<Col>
<Button type="primary" onClick={() => onChange(step + 1)}>
{!redirect && (step < 3 ? '下一步' : '提交')}
{redirect && (step === 0 ? '下一步' : '提交')}
{step < lastStep ? '下一步' : '提交'}
</Button>
</Col>
</Row>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
import React from 'react';
import React, { Fragment } from 'react';
import { Drawer, Button } from 'antd';
import { useForm } from 'antd/es/form/util';
import { withTheme, FormProps } from '@rjsf/core';
import { Theme as AntDTheme } from '@rjsf/antd';
import { JSONSchema7 } from 'json-schema';

import PluginForm from '@/components/PluginForm';

interface Props extends Omit<PluginForm.Props, 'form'> {
interface Props {
name?: string;
initialData: any;
active?: boolean;
disabled?: boolean;
schema: JSONSchema7;
onActive(name: string): void;
onInactive(name: string): void;
onClose(): void;
onFinish(values: any): void;
}

const PluginDrawer: React.FC<Props> = ({
name,
active,
disabled,
schema,
initialData,
onActive,
onInactive,
onClose,
...rest
onFinish,
}) => {
const [form] = useForm();
const PluginForm = withTheme(AntDTheme);

if (!name) {
return null;
}

// NOTE: 用于作为 PluginForm 的引用
let form: any;

return (
<Drawer
title={`配置 ${name} 插件`}
Expand Down Expand Up @@ -55,7 +64,9 @@ const PluginDrawer: React.FC<Props> = ({
<Button
type="primary"
style={{ marginRight: 8, marginLeft: 8 }}
onClick={() => form.submit()}
onClick={() => {
form.submit();
}}
>
确认
</Button>
Expand All @@ -65,7 +76,22 @@ const PluginDrawer: React.FC<Props> = ({
)
}
>
<PluginForm name={name!} form={form} {...rest} disabled={disabled} />
<PluginForm
schema={schema}
liveValidate
disabled={disabled || !active}
formData={initialData}
showErrorList={false}
ref={(_form: FormProps<any>) => {
form = _form;
}}
onSubmit={({ formData }) => {
onFinish(formData);
}}
>
{/* NOTE: 留空,用于隐藏 Submit 按钮 */}
<Fragment />
</PluginForm>
</Drawer>
);
};
Expand Down
125 changes: 125 additions & 0 deletions src/components/PluginPage/PluginPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import React, { useState, useEffect } from 'react';
import { LinkOutlined, SettingOutlined } from '@ant-design/icons';
import { omit } from 'lodash';
import { JSONSchema7 } from 'json-schema';

import PanelSection from '@/components/PanelSection';

import PluginCard from './PluginCard';
import PluginDrawer from './PluginDrawer';
import { getList, fetchPluginSchema } from './service';
import { PLUGIN_MAPPER_SOURCE } from './data';

type Props = {
disabled?: boolean;
data: PluginPage.PluginData;
onChange?(data: PluginPage.PluginData): void;
};

const PluginPage: React.FC<Props> = ({ data = {}, disabled, onChange }) => {
const [pluginName, setPluginName] = useState<string | undefined>();
const [activeList, setActiveList] = useState<PluginPage.PluginProps[]>([]);
const [inactiveList, setInactiveList] = useState<PluginPage.PluginProps[]>([]);
const [schema, setSchema] = useState<JSONSchema7>();

const pluginList = [
{
title: '已启用',
list: activeList,
},
{
title: '未启用',
list: inactiveList,
},
];

useEffect(() => {
getList(data).then((props) => {
setActiveList(props.activeList);
setInactiveList(props.inactiveList);
});
}, []);

return (
<>
{pluginList.map(({ list, title }) => {
if (disabled && title === '未启用') {
return null;
}
return (
<PanelSection
title={title}
key={title}
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3, 33.333%)',
gridRowGap: 10,
gridColumnGap: 10,
}}
>
{list.map(({ name }) => (
<PluginCard
name={name}
actions={[
<SettingOutlined
onClick={() => {
fetchPluginSchema(name).then((schemaData) => {
setSchema(schemaData);
setTimeout(() => {
setPluginName(name);
}, 300);
});
}}
/>,
<LinkOutlined
onClick={() =>
window.open(
`https://github.com/apache/incubator-apisix/blob/master/doc/plugins/${name}.md`,
)
}
/>,
]}
key={name}
/>
))}
</PanelSection>
);
})}

<PluginDrawer
name={pluginName}
initialData={pluginName ? data[pluginName] : {}}
active={Boolean(activeList.find((item) => item.name === pluginName))}
schema={schema!}
disabled={disabled}
onActive={(name) => {
// TODO: 需测试诸如 普罗米修斯 此类只需通过 {} 即可启用的插件
setActiveList(activeList.concat({ name, ...PLUGIN_MAPPER_SOURCE[name] }));
setInactiveList(inactiveList.filter((item) => item.name !== name));
}}
onInactive={(name) => {
if (!onChange) {
throw new Error('请提供 onChange 方法');
}
onChange(omit(Object.assign({}, data), name));
setInactiveList(inactiveList.concat({ name, ...PLUGIN_MAPPER_SOURCE[name] }));
setActiveList(activeList.filter((item) => item.name !== name));
setPluginName(undefined);
}}
onClose={() => setPluginName(undefined)}
onFinish={(value) => {
if (!pluginName) {
return;
}
if (!onChange) {
throw new Error('请提供 onChange 方法');
}
onChange(Object.assign({}, data, { [pluginName]: value }));
setPluginName(undefined);
}}
/>
</>
);
};

export default PluginPage;
Loading