Skip to content

Commit

Permalink
feat: add plugin template config feature (#1540)
Browse files Browse the repository at this point in the history
Co-authored-by: guoqqqi <979918879@qq.com>
  • Loading branch information
LiteSun and guoqqqi authored Mar 5, 2021
1 parent 77b42e8 commit 938b2b9
Show file tree
Hide file tree
Showing 35 changed files with 925 additions and 84 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,6 @@ api/build-tools/apisix
api/coverage.txt
api/dag-to-lua/

# frontend e2e test output
web/.nyc_output
web/coverage
12 changes: 12 additions & 0 deletions web/config/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ const routes = [
path: '/settings',
component: './Setting',
},
{
path: '/plugin-template/list',
component: './PluginTemplate/List',
},
{
path: 'plugin-template/create',
component: './PluginTemplate/Create',
},
{
path: '/plugin-template/:id/edit',
component: './PluginTemplate/Create',
},
{
path: '/user/login',
component: './User/Login',
Expand Down
8 changes: 7 additions & 1 deletion web/cypress/fixtures/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,11 @@
"updateSuccessfully": "Update Configuration Successfully",
"deleteSSLSuccess": "Remove target SSL successfully",
"sslErrorAlert": "key and cert don't match",
"pluginErrorAlert": "Invalid plugin data"
"pluginErrorAlert": "Invalid plugin data",
"pluginTemplateName": "test_plugin_template1",
"pluginTemplateName2": "test_plugin_template2",
"createPluginTemplateSuccess": "Create Plugin Template Successfully",
"editPluginTemplateSuccess": "Edit Plugin Template Successfully",
"deletePluginTemplateSuccess": "Delete Plugin Template Successfully",
"pluginTemplateErrorAlert": "Request Error Code: 10000"
}
7 changes: 6 additions & 1 deletion web/cypress/fixtures/selector.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,10 @@
"passwordInput": "#control-ref_password",
"drawer": ".ant-drawer-content",
"codemirrorScroll": ".CodeMirror-scroll",
"drawerClose": ".ant-drawer-close"
"drawerClose": ".ant-drawer-close",
"descriptionSelector": "[title=Description]",
"customSelector": "[title=Custom]",
"errorAlertClose": ".anticon-close",
"redirectURIInput": "#redirectURI",
"redirectCodeSelector": "#ret_code"
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ context('Create and Delete Consumer', () => {

// plugin config
cy.contains(this.domSelector.pluginCard, 'key-auth').within(() => {
cy.get('button').first().click();
cy.get('button').click({
force: true
});
});

cy.get(this.domSelector.disabledSwitcher).click();
Expand Down Expand Up @@ -91,7 +93,9 @@ context('Create and Delete Consumer', () => {

// plugin config
cy.contains(this.domSelector.pluginCard, 'key-auth').within(() => {
cy.get('button').first().click();
cy.get('button').click({
force: true
});
});
// edit codeMirror
cy.get(this.domSelector.codeMirror)
Expand All @@ -107,4 +111,3 @@ context('Create and Delete Consumer', () => {
cy.get(this.domSelector.notification).should('contain', this.data.pluginErrorAlert);
});
});

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-undef */

context('Create Edit and Delete PluginTemplate', () => {
const timeout = 5000;
beforeEach(() => {
cy.login();

cy.fixture('selector.json').as('domSelector');
cy.fixture('data.json').as('data');
});

it('should create pluginTemplate', function () {
cy.visit('/');
cy.contains('Route').click();
cy.contains('Plugin Template Config').click();
cy.contains('Create').click();

cy.get(this.domSelector.description).type(this.data.pluginTemplateName);
cy.contains('Next').click();
cy.contains('Enable').click({
force: true
});
cy.focused(this.domSelector.drawer).should('exist');
cy.get(this.domSelector.drawer, {
timeout
}).within(() => {
cy.get(this.domSelector.disabledSwitcher).click({
force: true,
});
});
cy.contains('Submit').click();
cy.contains('Next').click();
cy.contains('Submit').click();
cy.get(this.domSelector.notification).should('contain', this.data.createPluginTemplateSuccess);
});

it('should edit the pluginTemplate', function () {
cy.visit('plugin-template/list');

cy.get(this.domSelector.refresh).click();
cy.get(this.domSelector.descriptionSelector).type(this.data.pluginTemplateName);
cy.contains('button', 'Search').click();
cy.contains(this.data.pluginTemplateName).siblings().contains('Edit').click();

cy.get(this.domSelector.description).clear().type(this.data.pluginTemplateName2);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();

cy.get(this.domSelector.notification).should('contain', this.data.editPluginTemplateSuccess);
});

it('should delete pluginTemplate', function () {
cy.visit('plugin-template/list');

cy.get(this.domSelector.refresh).click();
cy.get(this.domSelector.descriptionSelector).type(this.data.pluginTemplateName);
cy.contains('button', 'Search').click();
cy.get(this.domSelector.empty).should('exist');

cy.contains('button', 'Reset').click();
cy.get(this.domSelector.descriptionSelector).type(this.data.pluginTemplateName2);
cy.contains('button', 'Search').click();
cy.contains(this.data.pluginTemplateName2).siblings().contains('Delete').click();
cy.contains('button', 'Confirm').click();
cy.get(this.domSelector.notification).should('contain', this.data.deletePluginTemplateSuccess);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable no-undef */

context('Create PluginTemplate Binding To Route', () => {
beforeEach(() => {
cy.login();

cy.fixture('selector.json').as('domSelector');
cy.fixture('data.json').as('data');
});

it('should create test pluginTemplate', function () {
cy.visit('/');
cy.contains('Route').click();
cy.contains('Plugin Template Config').click();
cy.contains('Create').click();
cy.get(this.domSelector.description).type(this.data.pluginTemplateName);
cy.contains('Next').click();
cy.contains('Next').click();
cy.contains('Submit').click();
cy.get(this.domSelector.notification).should('contain', this.data.createPluginTemplateSuccess);

cy.visit('routes/list');
cy.contains('Create').click();
cy.get(this.domSelector.name).type(this.data.routeName);
cy.contains('Next').click();
cy.get(this.domSelector.nodes_0_host).type(this.data.ip1);
cy.contains('Next').click();
cy.get(this.domSelector.customSelector).click();
cy.contains(this.data.pluginTemplateName).click();

cy.contains('Next').click();
cy.contains('Submit').click();
cy.contains(this.data.submitSuccess);
cy.contains('Goto List').click();
cy.url().should('contains', 'routes/list');
});

it('should delete the pluginTemplate failure', function () {
cy.visit('plugin-template/list');
cy.get(this.domSelector.refresh).click();

cy.get(this.domSelector.descriptionSelector).type(this.data.pluginTemplateName);
cy.contains('button', 'Search').click();
cy.contains(this.data.pluginTemplateName).siblings().contains('Delete').click();
cy.contains('button', 'Confirm').click();
cy.get(this.domSelector.notification).should('contain', this.data.pluginTemplateErrorAlert);
cy.get(this.domSelector.errorAlertClose).should('be.visible').click();
});

it('should edit the route with pluginTemplate', function () {
cy.visit('routes/list');

cy.get(this.domSelector.nameSelector).type(this.data.routeName);
cy.contains('Search').click();
cy.contains(this.data.routeName).siblings().contains('Edit').click();

cy.contains('Forbidden').click();
cy.contains('Custom').click();
cy.get(this.domSelector.redirectURIInput).clear().type('123');
cy.get(this.domSelector.redirectCodeSelector).click();
cy.contains('301(Permanent Redirect)').click();
cy.contains('Next').click();
cy.contains('Submit').click();
cy.contains(this.data.submitSuccess);
cy.contains('Goto List').click();
cy.url().should('contains', 'routes/list');
});

it('should delete the pluginTemplate successfully', function () {
cy.visit('plugin-template/list');

cy.get(this.domSelector.refresh).click();
cy.get(this.domSelector.descriptionSelector).type(this.data.pluginTemplateName);
cy.contains('button', 'Search').click();
cy.contains(this.data.pluginTemplateName).siblings().contains('Delete').click();
cy.contains('button', 'Confirm').click();
cy.get(this.domSelector.notification).should('contain', this.data.deletePluginTemplateSuccess);

cy.visit('/routes/list');
cy.get(this.domSelector.nameSelector).type(this.data.routeName);
cy.contains('Search').click();
cy.contains(this.data.routeName).siblings().contains('Delete').click();
cy.contains('button', 'Confirm').click();
cy.get(this.domSelector.notification).should('contain', this.data.deleteRouteSuccess);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ context('Create and Delete Route', () => {

// config prometheus plugin
cy.contains(this.domSelector.pluginCard, 'prometheus').within(() => {
cy.get('button').first().click();
cy.get('button').first().click({
force: true
});
});
cy.contains('button', 'Cancel').click();
cy.contains('Next').click();
Expand Down Expand Up @@ -138,4 +140,3 @@ context('Create and Delete Route', () => {
cy.get(this.domSelector.notification).should('contain', this.data.deleteRouteSuccess);
});
});

Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,23 @@ import { AutoComplete, Button, Col, Drawer, Form, notification, Row } from 'antd
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
import { useIntl } from 'umi';

import { transformLableValueToKeyValue } from '../../transform';
import { fetchLabelList } from '../../service';
import { transformLableValueToKeyValue } from '../../helpers';

type Props = {
title?: string;
actionName: string;
dataSource: string[];
filterList?: string[],
fetchLabelList: any,
disabled: boolean;
onClose: () => void;
} & Pick<RouteModule.Step1PassProps, 'onChange'>;

const LabelList = (disabled: boolean, labelList: RouteModule.LabelList) => {
const LabelList = (disabled: boolean, labelList: LabelList, filterList: string[] = []) => {
const { formatMessage } = useIntl();

const keyOptions = Object.keys(labelList || {})
.filter((item) => item !== 'API_VERSION')
.filter((item) => !filterList.includes(item))
.map((item) => ({ value: item }));
return (
<Form.List name="labels">
Expand Down Expand Up @@ -116,14 +117,16 @@ const LabelsDrawer: React.FC<Props> = ({
actionName = '',
disabled = false,
dataSource = [],
filterList = [],
fetchLabelList,
onClose,
onChange = () => {},
onChange = () => { },
}) => {
const transformLabel = transformLableValueToKeyValue(dataSource);

const { formatMessage } = useIntl();
const [form] = Form.useForm();
const [labelList, setLabelList] = useState<RouteModule.LabelList>({});
const [labelList, setLabelList] = useState<LabelList>({});
form.setFieldsValue({ labels: transformLabel });

useEffect(() => {
Expand Down Expand Up @@ -172,7 +175,7 @@ const LabelsDrawer: React.FC<Props> = ({
}
>
<Form form={form} layout="horizontal">
{LabelList(disabled, labelList || {})}
{LabelList(disabled, labelList || {}, filterList)}
</Form>
</Drawer>
);
Expand Down
17 changes: 17 additions & 0 deletions web/src/components/LabelsfDrawer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { default } from './LabelsDrawer';
Loading

0 comments on commit 938b2b9

Please sign in to comment.