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/01 01:46:52 UTC
[apisix-dashboard] branch master updated: feat: add new route
matching param position (#1984)
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 d3e1861 feat: add new route matching param position (#1984)
d3e1861 is described below
commit d3e1861f7578c7db42732758b19ff37a0562a175
Author: lookbrook <86...@users.noreply.github.com>
AuthorDate: Wed Sep 1 09:46:48 2021 +0800
feat: add new route matching param position (#1984)
Co-authored-by: penghui.yang <pe...@megatronix.co>
---
...route-with-advanced-matching-conditions.spec.js | 188 +++++++++++++++++++++
.../Route/components/Step1/MatchingRulesView.tsx | 4 +
web/src/pages/Route/locales/en-US.ts | 1 +
web/src/pages/Route/locales/zh-CN.ts | 1 +
web/src/pages/Route/transform.ts | 15 +-
web/src/pages/Route/typing.d.ts | 2 +-
6 files changed, 208 insertions(+), 3 deletions(-)
diff --git a/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
new file mode 100644
index 0000000..5f7c771
--- /dev/null
+++ b/web/cypress/integration/route/create-route-with-advanced-matching-conditions.spec.js
@@ -0,0 +1,188 @@
+/*
+ * 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 Route with advanced matching conditions', () => {
+ const selector = {
+ name: '#name',
+ nodes_0_host: '#nodes_0_host',
+ nodes_0_port: '#nodes_0_port',
+ nodes_0_weight: '#nodes_0_weight',
+ deleteAlert: '.ant-modal-body',
+ notificationCloseIcon: '.ant-notification-close-icon',
+ notification: '.ant-notification-notice-message',
+ parameterPosition: '#position',
+ ruleCard: '.ant-modal',
+ operator: '#operator',
+ value: '#value',
+ advancedMatchingTable: '.ant-table-row.ant-table-row-level-0',
+ advancedMatchingTableOperation: '.ant-space',
+ advancedMatchingTableCell: '.ant-table-cell',
+ };
+
+ const data = {
+ routeName: `test_route_${new Date().valueOf()}`,
+ submitSuccess: 'Submit Successfully',
+ ip1: '127.0.0.1',
+ port: '80',
+ weight: 1,
+ matchingParamName: 'server_port',
+ deleteRouteSuccess: 'Delete Route Successfully',
+ };
+
+ const opreatorList = [
+ // 'Equal(==)' : '1234',
+ 'Unequal(~=)',
+ 'Greater Than(>)',
+ 'Less Than(<)',
+ // 'Regex Match(~~)',
+ 'IN',
+ ];
+
+ const matchingValueList1 = ['1000', '800', '2000', '["1800","1888"]'];
+
+ const matchingValueList2 = ['2000', '1800', '3000', '["2800","2888"]'];
+
+ beforeEach(() => {
+ cy.login();
+ });
+
+ it('should create route with advanced matching conditions', function () {
+ cy.visit('/routes/list');
+ cy.contains('Create').click();
+ cy.contains('Next').click().click();
+ cy.get(selector.name).type(data.routeName);
+
+ // All Of Operational Character Should Exist And Can be Created
+ cy.wrap(opreatorList).each((opreator, index) => {
+ cy.contains('Advanced Routing Matching Conditions')
+ .parent()
+ .siblings()
+ .contains('Add')
+ .click()
+ .then(() => {
+ cy.get(selector.parameterPosition)
+ .click()
+ .then(() => {
+ cy.get('.ant-select-dropdown').within(() => {
+ cy.contains('Build-in').should('be.visible').click();
+ });
+ });
+ cy.get(selector.ruleCard).within(() => {
+ cy.get(selector.name).type(data.matchingParamName);
+ });
+ cy.get(selector.operator).click();
+ cy.get(`[title="${opreator}"]`).should('be.visible').click();
+ cy.get(selector.value).type(matchingValueList1[index]);
+ cy.contains('Confirm').click();
+ });
+ });
+ cy.get(selector.advancedMatchingTable).should('exist');
+ cy.wrap(opreatorList).each((operator, index) => {
+ cy.get(selector.advancedMatchingTableCell).within(() => {
+ cy.contains('td', 'Build-in Parameter').should('be.visible');
+ cy.contains('td', data.matchingParamName).should('be.visible');
+ cy.contains('td', matchingValueList1[index]).should('be.visible');
+ });
+ });
+ cy.contains('Next').click();
+ cy.get(selector.nodes_0_host).clear().type(data.ip1);
+ cy.get(selector.nodes_0_port).type(data.port);
+ cy.get(selector.nodes_0_weight).type(data.weight);
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.contains(data.submitSuccess).should('be.visible');
+ cy.contains('Goto List').click();
+ cy.url().should('contains', 'routes/list');
+ });
+
+ it('should edit this route matching conditions', function () {
+ cy.visit('/routes/list');
+ cy.get(selector.name).clear().type(data.routeName);
+ cy.contains('Search').click();
+ cy.contains(data.routeName).siblings().contains('Configure').click();
+ cy.get(selector.advancedMatchingTable).should('exist');
+ cy.wrap(opreatorList).each((opreator, index) => {
+ cy.get(selector.advancedMatchingTableCell).within(() => {
+ cy.contains(`${opreator}`)
+ .parent('tr')
+ .within(() => {
+ cy.get(selector.advancedMatchingTableOperation).within(() => {
+ cy.contains('Configure').click();
+ });
+ });
+ });
+ cy.get(selector.ruleCard).within(() => {
+ cy.get(`[title="Build-in Parameter"]`).should('have.class', 'ant-select-selection-item');
+ cy.get(selector.name).clear().type(data.matchingParamName);
+ cy.get(`[title="${opreator}"]`).should('have.class', 'ant-select-selection-item');
+ cy.get(selector.value).clear().type(matchingValueList2[index]);
+ cy.contains('Confirm').click();
+ });
+ cy.get(selector.advancedMatchingTableCell).within(() => {
+ cy.contains('td', 'Build-in Parameter').should('be.visible');
+ cy.contains('td', data.matchingParamName).should('be.visible');
+ cy.contains('td', matchingValueList2[index]).should('be.visible');
+ });
+ });
+ cy.contains('Next').click();
+ cy.get(selector.nodes_0_port).focus();
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.contains(data.submitSuccess);
+ cy.contains('Goto List').click();
+ cy.url().should('contains', 'routes/list');
+ });
+
+ it('should delete route matching conditions', function () {
+ cy.visit('/routes/list');
+ cy.get(selector.name).clear().type(data.routeName);
+ cy.contains('Search').click();
+ cy.contains(data.routeName).siblings().contains('Configure').click();
+ cy.get(selector.name).should('value', data.routeName);
+ cy.get(selector.advancedMatchingTable).should('exist');
+ cy.wrap(opreatorList).each(() => {
+ cy.get(selector.advancedMatchingTableOperation).within(() => {
+ cy.contains('Delete').click().should('not.exist');
+ });
+ });
+ cy.get(selector.advancedMatchingTable).should('not.exist');
+ cy.contains('Next').click();
+ cy.get(selector.nodes_0_port).focus();
+ cy.contains('Next').click();
+ cy.contains('Next').click();
+ cy.contains('Submit').click();
+ cy.contains(data.submitSuccess);
+ cy.contains('Goto List').click();
+ cy.url().should('contains', 'routes/list');
+
+ 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();
+ });
+});
diff --git a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
index ad55b39..ccbb97c 100644
--- a/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
+++ b/web/src/pages/Route/components/Step1/MatchingRulesView.tsx
@@ -116,6 +116,9 @@ const MatchingRulesView: React.FC<RouteModule.Step1PassProps> = ({
case 'cookie':
renderText = 'Cookie';
break;
+ case 'buildin':
+ renderText = formatMessage({ id: 'page.route.buildinParameter' });
+ break;
default:
renderText = '';
}
@@ -206,6 +209,7 @@ const MatchingRulesView: React.FC<RouteModule.Step1PassProps> = ({
<Option value="http">{formatMessage({ id: 'page.route.httpRequestHeader' })}</Option>
<Option value="arg">{formatMessage({ id: 'page.route.requestParameter' })}</Option>
<Option value="cookie">Cookie</Option>
+ <Option value="buildin">{formatMessage({ id: 'page.route.buildinParameter' })}</Option>
</Select>
</Form.Item>
<Form.Item
diff --git a/web/src/pages/Route/locales/en-US.ts b/web/src/pages/Route/locales/en-US.ts
index 5370584..39b97e1 100644
--- a/web/src/pages/Route/locales/en-US.ts
+++ b/web/src/pages/Route/locales/en-US.ts
@@ -23,6 +23,7 @@ export default {
'page.route.parameterPosition': 'Parameter Position',
'page.route.httpRequestHeader': 'HTTP Request Header',
'page.route.requestParameter': 'Request Parameter',
+ 'page.route.buildinParameter': 'Build-in Parameter',
'page.route.parameterName': 'Parameter Name',
'page.route.operationalCharacter': 'Operational Character',
'page.route.equal': 'Equal(==)',
diff --git a/web/src/pages/Route/locales/zh-CN.ts b/web/src/pages/Route/locales/zh-CN.ts
index 0d520be..86105e4 100644
--- a/web/src/pages/Route/locales/zh-CN.ts
+++ b/web/src/pages/Route/locales/zh-CN.ts
@@ -19,6 +19,7 @@ export default {
'page.route.parameterPosition': '参数位置',
'page.route.httpRequestHeader': 'HTTP 请求头',
'page.route.requestParameter': '请求参数',
+ 'page.route.buildinParameter': '内置参数',
'page.route.parameterName': '参数名称',
'page.route.operationalCharacter': '运算符',
'page.route.equal': '等于(==)',
diff --git a/web/src/pages/Route/transform.ts b/web/src/pages/Route/transform.ts
index f5aa94e..24a9926 100644
--- a/web/src/pages/Route/transform.ts
+++ b/web/src/pages/Route/transform.ts
@@ -157,8 +157,11 @@ export const transformStepData = ({
case 'http':
key = `http_${name}`;
break;
- default:
+ case 'arg':
key = `arg_${name}`;
+ break;
+ default:
+ key = `${name}`;
}
let finalValue = value;
if (operator === 'IN') {
@@ -266,7 +269,15 @@ const transformVarsToRules = (
data: [string, RouteModule.Operator, string | any[]][] = [],
): RouteModule.MatchingRule[] =>
data.map(([key, operator, value]) => {
- const [, position, name] = key.split(/^(cookie|http|arg)_/);
+ let position = '';
+ let name = '';
+ const regex = new RegExp('^(cookie|http|arg)_.+');
+ if (regex.test(key)) {
+ [, position, name] = key.split(/^(cookie|http|arg)_/);
+ }else {
+ position = "buildin";
+ name = key;
+ }
return {
position: position as RouteModule.VarPosition,
name,
diff --git a/web/src/pages/Route/typing.d.ts b/web/src/pages/Route/typing.d.ts
index 77bce06..4870e38 100644
--- a/web/src/pages/Route/typing.d.ts
+++ b/web/src/pages/Route/typing.d.ts
@@ -17,7 +17,7 @@
declare namespace RouteModule {
type Operator = '==' | '~=' | '>' | '<' | '~~' | '~*' | 'IN' | 'HAS' | '!';
- type VarPosition = 'arg' | 'http' | 'cookie';
+ type VarPosition = 'arg' | 'http' | 'cookie' | 'buildin';
type RequestProtocol = 'https' | 'http' | 'websocket';