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':