You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by li...@apache.org on 2021/09/24 02:25:52 UTC
[apisix-dashboard] branch master updated: feat(plugin): allowing
basic-auth to dynamically adapt to the BE rules (#2086)
This is an automated email from the ASF dual-hosted git repository.
liuxiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git
The following commit(s) were added to refs/heads/master by this push:
new fd5afe4 feat(plugin): allowing basic-auth to dynamically adapt to the BE rules (#2086)
fd5afe4 is described below
commit fd5afe419fb24d5045e6e65c3f07f9e5d9278272
Author: wmdmomo <43...@users.noreply.github.com>
AuthorDate: Fri Sep 24 10:25:45 2021 +0800
feat(plugin): allowing basic-auth to dynamically adapt to the BE rules (#2086)
---
...te-consumer-with-basic-auth-plugin-form.spec.js | 117 +++++++++++++++++++++
web/src/components/Plugin/PluginDetail.tsx | 3 +-
web/src/components/Plugin/UI/basic-auth.tsx | 18 +++-
web/src/components/Plugin/UI/plugin.tsx | 2 +-
4 files changed, 135 insertions(+), 5 deletions(-)
diff --git a/web/cypress/integration/consumer/create-consumer-with-basic-auth-plugin-form.spec.js b/web/cypress/integration/consumer/create-consumer-with-basic-auth-plugin-form.spec.js
new file mode 100644
index 0000000..9a2331a
--- /dev/null
+++ b/web/cypress/integration/consumer/create-consumer-with-basic-auth-plugin-form.spec.js
@@ -0,0 +1,117 @@
+/*
+ * 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 and delete consumer with basic-auth plugin form', () => {
+ const selector = {
+ empty: '.ant-empty-normal',
+ username: '#username',
+ password: '#password',
+ description: '#desc',
+ pluginCard: '.ant-card',
+ drawer: '.ant-drawer-content',
+ disabledSwitcher: '#disable',
+ notification: '.ant-notification-notice-message',
+ notificationCloseIcon: '.ant-notification-close-icon',
+ monacoViewZones: '.view-zones',
+ alert: '.ant-form-item-explain-error [role=alert]'
+ };
+
+ const data = {
+ consumerName: 'test_consumer',
+ description: 'desc_by_autotest',
+ createConsumerSuccess: 'Create Consumer Successfully',
+ deleteConsumerSuccess: 'Delete Consumer Successfully',
+ username: 'root',
+ password: '1234',
+ };
+
+ beforeEach(() => {
+ cy.login();
+ });
+
+ it('creates consumer with basic-auth form', function () {
+ cy.visit('/');
+ cy.contains('Consumer').click();
+ cy.get(selector.empty).should('be.visible');
+ cy.contains('Create').click();
+ // basic information
+ cy.get(selector.username).type(data.consumerName);
+ cy.get(selector.description).type(data.description);
+ cy.contains('Next').click();
+
+ // config auth plugin
+ cy.contains(selector.pluginCard, 'key-auth').within(() => {
+ cy.contains('Enable').click({
+ force: true,
+ });
+ });
+ cy.focused(selector.drawer).should('exist');
+ cy.get(selector.monacoViewZones).should('exist');
+ cy.get(selector.disabledSwitcher).click();
+
+ // edit monaco
+ cy.window().then((window) => {
+ window.monacoEditor.setValue(JSON.stringify({ key: 'test' }));
+ cy.contains('button', 'Submit').click();
+ });
+
+ cy.contains(selector.pluginCard, 'basic-auth').within(() => {
+ cy.contains('Enable').click({
+ force: true,
+ });
+ });
+
+ cy.focused(selector.drawer).should('exist');
+
+ // config basic-auth form without username and password
+ cy.get(selector.username).click();
+ cy.get(selector.alert).contains('Please enter username');
+ cy.get(selector.password).click();
+ cy.get(selector.alert).contains('Please enter password');
+ cy.get(selector.drawer).within(() => {
+ cy.contains('Submit').click({
+ force: true,
+ });
+ });
+ cy.get(selector.notification).should('contain', 'Invalid plugin data');
+ cy.get(selector.notificationCloseIcon).click();
+
+ // config basic-auth form with username and password
+ cy.get(selector.username).type(data.username);
+ cy.get(selector.password).type(data.password);
+ cy.get(selector.alert).should('not.exist');
+ cy.get(selector.disabledSwitcher).click();
+ cy.get(selector.drawer).within(() => {
+ cy.contains('Submit').click({
+ force: true,
+ });
+ });
+ cy.get(selector.drawer).should('not.exist');
+
+ cy.contains('button', 'Next').click();
+ cy.contains('button', 'Submit').click();
+ cy.get(selector.notification).should('contain', data.createConsumerSuccess);
+ });
+
+ it('delete the consumer', function () {
+ cy.visit('/consumer/list');
+ cy.contains(data.consumerName).should('be.visible').siblings().contains('Delete').click();
+ cy.contains('button', 'Confirm').click();
+ cy.get(selector.notification).should('contain', data.deleteConsumerSuccess);
+ });
+});
diff --git a/web/src/components/Plugin/PluginDetail.tsx b/web/src/components/Plugin/PluginDetail.tsx
index 6137299..935dea6 100644
--- a/web/src/components/Plugin/PluginDetail.tsx
+++ b/web/src/components/Plugin/PluginDetail.tsx
@@ -107,7 +107,8 @@ const PluginDetail: React.FC<Props> = ({
const [UIForm] = Form.useForm();
const data = initialData[name] || {};
const pluginType = pluginList.find((item) => item.name === name)?.originType;
- const pluginSchema = pluginList.find((item) => item.name === name)?.schema;
+ const schemaName = name === 'basic-auth' ? 'consumer_schema' : 'schema';
+ const pluginSchema = pluginList.find((item) => item.name === name)?.[schemaName];
const [content, setContent] = useState<string>(JSON.stringify(data, null, 2));
const [monacoMode, setMonacoMode] = useState<PluginComponent.MonacoLanguage>(monacoModeList.JSON);
const modeOptions: { label: string; value: string }[] = [
diff --git a/web/src/components/Plugin/UI/basic-auth.tsx b/web/src/components/Plugin/UI/basic-auth.tsx
index 8613b89..507bc51 100644
--- a/web/src/components/Plugin/UI/basic-auth.tsx
+++ b/web/src/components/Plugin/UI/basic-auth.tsx
@@ -20,6 +20,7 @@ import { Form, Input } from 'antd';
type Props = {
form: FormInstance;
+ schema: Record<string, any> | undefined;
ref?: any;
};
@@ -32,13 +33,24 @@ export const FORM_ITEM_LAYOUT = {
},
};
-const BasicAuth: React.FC<Props> = ({ form }) => {
+const BasicAuth: React.FC<Props> = ({ form, schema }) => {
+ const required: string[] = schema?.required;
return (
<Form form={form} {...FORM_ITEM_LAYOUT}>
- <Form.Item label="username" name="username" required>
+ <Form.Item
+ label="username"
+ name="username"
+ rules={[{ required: required.indexOf('username') > -1 }]}
+ validateTrigger={['onChange', 'onBlur', 'onClick']}
+ >
<Input></Input>
</Form.Item>
- <Form.Item label="password" name="password" required>
+ <Form.Item
+ label="password"
+ name="password"
+ rules={[{ required: required.indexOf('password') > -1 }]}
+ validateTrigger={['onChange', 'onBlur', 'onClick']}
+ >
<Input></Input>
</Form.Item>
</Form>
diff --git a/web/src/components/Plugin/UI/plugin.tsx b/web/src/components/Plugin/UI/plugin.tsx
index abac43a..f0dd43c 100644
--- a/web/src/components/Plugin/UI/plugin.tsx
+++ b/web/src/components/Plugin/UI/plugin.tsx
@@ -62,7 +62,7 @@ export const PluginForm: React.FC<Props> = ({ name, schema, renderForm, form })
case 'api-breaker':
return <ApiBreaker form={form} schema={schema} />
case 'basic-auth':
- return <BasicAuth form={form} />;
+ return <BasicAuth form={form} schema={schema} />;
case 'limit-count':
return <LimitCount form={form} schema={schema} />
case 'cors':