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/07/30 00:22:30 UTC
[apisix-dashboard] branch master updated: fix: make service chash
key Input inputable and selectable (#1982)
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 d49b283 fix: make service chash key Input inputable and selectable (#1982)
d49b283 is described below
commit d49b28381bc68c4da1552fe953c1ea7080423f4b
Author: foolwc <29...@qq.com>
AuthorDate: Fri Jul 30 08:22:22 2021 +0800
fix: make service chash key Input inputable and selectable (#1982)
Co-authored-by: li wencheng <we...@daocloud.io>
Co-authored-by: litesun <su...@apache.org>
---
.../route/create-route-with-chash-upstream.spec.js | 124 +++++++++++++++++++++
.../create-service-with-chash-upstream.spec.js | 106 ++++++++++++++++++
...and_edit_upstream_with_custom_chash_key.spec.js | 109 ++++++++++++++++++
web/src/components/Upstream/components/Type.tsx | 29 +++--
4 files changed, 358 insertions(+), 10 deletions(-)
diff --git a/web/cypress/integration/route/create-route-with-chash-upstream.spec.js b/web/cypress/integration/route/create-route-with-chash-upstream.spec.js
new file mode 100644
index 0000000..f2aef94
--- /dev/null
+++ b/web/cypress/integration/route/create-route-with-chash-upstream.spec.js
@@ -0,0 +1,124 @@
+/*
+ * 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 Edit Route With Custom CHash Key Upstream', () => {
+ const selector = {
+ name: '#name',
+ menu: '[role=menu]',
+ roundRobinSelect: '[title="Round Robin"]',
+ varSelect: '[title="vars"]',
+ defaultCHashKey: '[value="remote_addr"]',
+ upstreamType: ".ant-select-item-option-content",
+ hashPosition: ".ant-select-item-option-content",
+ nodes_0_host: '#nodes_0_host',
+ nodes_0_port: '#nodes_0_port',
+ nodes_0_weight: '#nodes_0_weight',
+ nameSelector: '[title=Name]',
+ chash_key: '#key',
+ deleteAlert: '.ant-modal-body',
+ notificationCloseIcon: '.ant-notification-close-icon',
+ notification: '.ant-notification-notice-message',
+ };
+
+ const data = {
+ routeName: 'roteName',
+ ip: '127.0.0.1',
+ port: '7000',
+ weight: '1',
+ deleteRouteSuccess: 'Delete Route Successfully',
+ submitSuccess: 'Submit Successfully',
+ custom_key: 'custom_key',
+ new_key: 'new_key',
+ };
+
+ beforeEach(() => {
+ cy.login();
+ });
+
+ it('should create route with custom chash key Upstream', function () {
+ cy.visit('/');
+ cy.get(selector.menu)
+ .should('be.visible')
+ .within(() => {
+ cy.contains('Route').click();
+ });
+ cy.contains('Create').click();
+
+ cy.contains('Next').click().click();
+ cy.get(selector.name).type(data.routeName);
+ cy.contains('Next').click();
+
+ cy.get(selector.roundRobinSelect).click();
+ cy.get(selector.upstreamType).within(() => {
+ cy.contains('CHash').click();
+ });
+ cy.get(selector.varSelect).click();
+ cy.get(selector.hashPosition).within(() => {
+ cy.contains('cookie').click();
+ });
+ cy.get(selector.defaultCHashKey).click();
+ cy.get(selector.defaultCHashKey).clear().type(data.custom_key);
+ cy.get(selector.nodes_0_host).click();
+ cy.get(selector.nodes_0_host).type(data.ip);
+ cy.get(selector.nodes_0_port).clear().type(data.port);
+ cy.get(selector.nodes_0_weight).clear().type(data.weight);
+
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.contains(data.submitSuccess).should('be.visible');
+
+ // back to route list page
+ cy.contains('Goto List').click();
+ cy.url().should('contains', 'routes/list');
+ });
+
+ it('should edit this route ', function () {
+ cy.visit('/');
+ cy.contains('Route').click();
+ cy.get(selector.nameSelector).type(data.routeName);
+
+ cy.contains('Search').click();
+ cy.contains(data.routeName).siblings().contains('Configure').click();
+ cy.get(selector.name).should('value', data.routeName);
+ cy.contains('Next').click({
+ force: true,
+ });
+ cy.get(selector.chash_key).should('value', data.custom_key);
+ cy.get(selector.chash_key).clear().type(data.new_key);
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.contains(data.submitSuccess).should('be.visible');
+ });
+
+ it('should delete the route', function () {
+ cy.visit('/routes/list');
+ cy.get(selector.name).clear().type(data.routeName);
+ cy.contains('Search').click();
+ cy.contains(data.routeName).siblings().contains('More').click();
+ cy.contains('Delete').click();
+ cy.get(selector.deleteAlert)
+ .should('be.visible')
+ .within(() => {
+ cy.contains('OK').click();
+ });
+ cy.get(selector.notification).should('contain', data.deleteRouteSuccess);
+ cy.get(selector.notificationCloseIcon).click({multiple: true});
+ });
+});
diff --git a/web/cypress/integration/service/create-service-with-chash-upstream.spec.js b/web/cypress/integration/service/create-service-with-chash-upstream.spec.js
new file mode 100644
index 0000000..e613586
--- /dev/null
+++ b/web/cypress/integration/service/create-service-with-chash-upstream.spec.js
@@ -0,0 +1,106 @@
+/*
+ * 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 Edit Service with Custom CHash Key Upstream', () => {
+ const selector = {
+ name: '#name',
+ description: '#desc',
+ roundRobinSelect: '[title="Round Robin"]',
+ varSelect: '[title="vars"]',
+ defaultCHashKey: '[value="remote_addr"]',
+ nodes_0_host: '#nodes_0_host',
+ nodes_0_port: '#nodes_0_port',
+ nodes_0_weight: '#nodes_0_weight',
+ upstreamType: ".ant-select-item-option-content",
+ hashPosition: ".ant-select-item-option-content",
+ chash_key: '#key',
+ notification: '.ant-notification-notice-message',
+ nameSearch: '[title=Name]',
+ notificationCloseIcon: '.ant-notification-close-icon',
+ };
+
+ const data = {
+ serviceName: 'chash-service',
+ createServiceSuccess: 'Create Service Successfully',
+ deleteServiceSuccess: 'Delete Service Successfully',
+ editServiceSuccess: 'Configure Service Successfully',
+ port: '80',
+ weight: 1,
+ description: 'desc_by_autotest',
+ ip1: '127.0.0.1',
+ port0: '7000',
+ weight0: '1',
+ custom_key: 'custom_key',
+ new_key: 'new_key',
+ };
+
+ beforeEach(() => {
+ cy.login();
+ });
+
+ it('should create a service with custom CHash key Upstream', function () {
+ cy.visit('/');
+ cy.contains('Service').click();
+ cy.contains('Create').click();
+ cy.get(selector.name).type(data.serviceName);
+ cy.get(selector.description).type(data.description);
+ cy.get(selector.roundRobinSelect).click();
+ cy.get(selector.upstreamType).within(() => {
+ cy.contains('CHash').click();
+ });
+ cy.get(selector.varSelect).click();
+ cy.get(selector.hashPosition).within(() => {
+ cy.contains('cookie').click();
+ });
+ cy.get(selector.defaultCHashKey).click();
+ cy.get(selector.defaultCHashKey).clear().type('custom_key');
+ cy.get(selector.nodes_0_host).click();
+ cy.get(selector.nodes_0_host).type(data.ip1);
+ cy.get(selector.nodes_0_port).clear().type(data.port0);
+ cy.get(selector.nodes_0_weight).clear().type(data.weight0);
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.get(selector.notification).should('contain', data.createServiceSuccess);
+ });
+
+ it('should edit the service', function () {
+ cy.visit('/service/list');
+
+ cy.get(selector.nameSearch).type(data.serviceName);
+ cy.contains('Search').click();
+ cy.contains(data.serviceName).siblings().contains('Configure').click();
+ cy.get(selector.chash_key).should('value', data.custom_key);
+ cy.get(selector.chash_key).clear().type(data.new_key);
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.get(selector.notification).should('contain', data.editServiceSuccess);
+ });
+
+
+ it('should delete this service', function () {
+ cy.visit('/service/list');
+ cy.get(selector.nameSearch).type(data.serviceName);
+ cy.contains('Search').click();
+ cy.contains(data.serviceName).siblings().contains('Delete').click();
+ cy.contains('button', 'Confirm').click();
+ cy.get(selector.notification).should('contain', data.deleteServiceSuccess);
+ cy.get(selector.notificationCloseIcon).click();
+ });
+});
diff --git a/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js b/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
new file mode 100644
index 0000000..dda1145
--- /dev/null
+++ b/web/cypress/integration/upstream/create_and_edit_upstream_with_custom_chash_key.spec.js
@@ -0,0 +1,109 @@
+/*
+ * 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 Upstream With Custom CHash Key', () => {
+ const selector = {
+ name: '#name',
+ description: '#desc',
+ roundRobinSelect: '[title="Round Robin"]',
+ varSelect: '[title="vars"]',
+ defaultCHashKey: '[value="remote_addr"]',
+ nodes_0_host: '#nodes_0_host',
+ nodes_0_port: '#nodes_0_port',
+ nodes_0_weight: '#nodes_0_weight',
+ upstreamType: ".ant-select-item-option-content",
+ hashPosition: ".ant-select-item-option-content",
+ chash_key: '#key',
+ notification: '.ant-notification-notice-message',
+ nameSelector: '[title=Name]',
+ };
+
+ const data = {
+ upstreamName: 'test_upstream',
+ description: 'desc_by_autotest',
+ custom_key: 'custom_key',
+ new_key: 'new_key',
+ ip: '127.0.0.1',
+ port: '7000',
+ weight: '1',
+ createUpstreamSuccess: 'Create Upstream Successfully',
+ configureUpstreamSuccess: 'Configure Upstream Successfully',
+ deleteUpstreamSuccess: 'Delete Upstream Successfully',
+ };
+
+ beforeEach(() => {
+ cy.login();
+ });
+
+ it('should create upstream with custom chash key', function () {
+ cy.visit('/');
+ cy.contains('Upstream').click();
+ cy.contains('Create').click();
+
+ cy.get(selector.name).type(data.upstreamName);
+ cy.get(selector.description).type(data.description);
+
+ cy.get(selector.roundRobinSelect).click();
+ cy.get(selector.upstreamType).within(() => {
+ cy.contains('CHash').click();
+ });
+ cy.get(selector.varSelect).click();
+ cy.get(selector.hashPosition).within(() => {
+ cy.contains('cookie').click();
+ });
+ cy.get(selector.defaultCHashKey).click();
+ cy.get(selector.defaultCHashKey).clear().type(data.custom_key);
+ cy.get(selector.nodes_0_host).click();
+ cy.get(selector.nodes_0_host).type(data.ip);
+ cy.get(selector.nodes_0_port).clear().type(data.port);
+ cy.get(selector.nodes_0_weight).clear().type(data.weight);
+
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.get(selector.notification).should('contain', data.createUpstreamSuccess);
+ cy.url().should('contains', 'upstream/list');
+ });
+
+ it('should configure the upstream', function () {
+ cy.visit('/');
+ cy.contains('Upstream').click();
+
+ cy.get(selector.nameSelector).type(data.upstreamName);
+ cy.contains('Search').click();
+ cy.contains(data.upstreamName).siblings().contains('Configure').click();
+
+ cy.get(selector.chash_key).should('value', data.custom_key);
+ cy.get(selector.chash_key).clear().type(data.new_key);
+
+ cy.contains('Next').click();
+ cy.contains('Submit').click({
+ force: true,
+ });
+
+ cy.get(selector.notification).should('contain', data.configureUpstreamSuccess);
+ cy.url().should('contains', 'upstream/list');
+ });
+
+ it('should delete the upstream', function () {
+ cy.visit('/');
+ cy.contains('Upstream').click();
+ cy.contains(data.upstreamName).siblings().contains('Delete').click();
+ cy.contains('button', 'Confirm').click();
+ cy.get(selector.notification).should('contain', data.deleteUpstreamSuccess);
+ });
+});
diff --git a/web/src/components/Upstream/components/Type.tsx b/web/src/components/Upstream/components/Type.tsx
index 8788ebb..ed65670 100644
--- a/web/src/components/Upstream/components/Type.tsx
+++ b/web/src/components/Upstream/components/Type.tsx
@@ -14,8 +14,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React from 'react'
-import { Form, Select } from 'antd'
+import React, { useState } from 'react'
+import { AutoComplete, Form, Select } from 'antd'
import { useIntl } from 'umi'
import type { FormInstance } from 'antd/es/form'
@@ -28,6 +28,11 @@ type Props = {
const CHash: React.FC<Pick<Props, 'readonly'>> = ({ readonly }) => {
const { formatMessage } = useIntl()
+ const [keySearchWord, setKeySearchWord] = useState('');
+
+ const handleSearch = (search: string) => {
+ setKeySearchWord(search);
+ };
return (
<React.Fragment>
<Form.Item name="hash_on" rules={[{ required: true }]} label={formatMessage({ id: 'component.upstream.fields.hash_on' })} tooltip={formatMessage({ id: 'component.upstream.fields.hash_on.tooltip' })} initialValue="vars">
@@ -39,14 +44,18 @@ const CHash: React.FC<Pick<Props, 'readonly'>> = ({ readonly }) => {
))}
</Select>
</Form.Item>
- <Form.Item name="key" rules={[{ required: true }]} label={formatMessage({ id: 'component.upstream.fields.key' })} tooltip={formatMessage({ id: 'component.upstream.fields.key.tooltip' })} initialValue="remote_addr">
- <Select disabled={readonly}>
- {Object.entries(CommonHashKeyEnum).map(([label, value]) => (
- <Select.Option value={value} key={value}>
- {label}
- </Select.Option>
- ))}
- </Select>
+ <Form.Item name="key" rules={[{ required: true }]}
+ label={formatMessage({ id: 'component.upstream.fields.key' })}
+ tooltip={formatMessage({ id: 'component.upstream.fields.key.tooltip' })} initialValue="remote_addr">
+ <AutoComplete disabled={readonly} onSearch={handleSearch}>
+ {Object.entries(CommonHashKeyEnum)
+ .filter((([label, value]) => label.startsWith(keySearchWord) || value.startsWith(keySearchWord)))
+ .map(([label, value]) => (
+ <Select.Option value={value} key={value}>
+ {label}
+ </Select.Option>
+ ))}
+ </AutoComplete>
</Form.Item>
</React.Fragment>
)