You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2021/04/02 02:08:41 UTC

[apisix-dashboard] branch master updated: feat: Support duplicate one existing Route (#1558)

This is an automated email from the ASF dual-hosted git repository.

juzhiyuan 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 9cf91b7  feat: Support duplicate one existing Route (#1558)
9cf91b7 is described below

commit 9cf91b756f33cbddeac1adb912177f5b7762def6
Author: batman-ezio <80...@users.noreply.github.com>
AuthorDate: Fri Apr 2 10:08:34 2021 +0800

    feat: Support duplicate one existing Route (#1558)
---
 .gitignore                                         |  8 ++++
 web/config/routes.ts                               |  4 ++
 ... => create-edit-duplicate-delete-route.spec.js} | 45 +++++++++++++++++++---
 web/src/locales/en-US/component.ts                 |  1 +
 web/src/locales/zh-CN/component.ts                 |  1 +
 web/src/pages/Route/Create.tsx                     | 10 ++---
 web/src/pages/Route/List.tsx                       |  3 ++
 7 files changed, 62 insertions(+), 10 deletions(-)

diff --git a/.gitignore b/.gitignore
index ff01226..34a1868 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,3 +57,11 @@ web/.nyc_output
 web/coverage
 web/cypress/screenshots/
 web/cypress/videos/
+web/cypress/downloads/
+web/cypress/screenshots/
+web/cypress/videos/
+
+# vim
+*.swp
+*.swo
+
diff --git a/web/config/routes.ts b/web/config/routes.ts
index 7f01bc3..72057b5 100644
--- a/web/config/routes.ts
+++ b/web/config/routes.ts
@@ -40,6 +40,10 @@ const routes = [
     component: './Route/Create',
   },
   {
+    path: '/routes/:rid/duplicate',
+    component: './Route/Create',
+  },
+  {
     path: '/ssl/:id/edit',
     component: './SSL/Create',
   },
diff --git a/web/cypress/integration/route/create-edit-delete-route.spec.js b/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
similarity index 79%
rename from web/cypress/integration/route/create-edit-delete-route.spec.js
rename to web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
index 744e54d..85aad6f 100644
--- a/web/cypress/integration/route/create-edit-delete-route.spec.js
+++ b/web/cypress/integration/route/create-edit-duplicate-delete-route.spec.js
@@ -19,6 +19,7 @@
 context('Create and Delete Route', () => {
   const name = `routeName${new Date().valueOf()}`;
   const newName = `newName${new Date().valueOf()}`;
+  const duplicateNewName = `duplicateName${new Date().valueOf()}`;
   const sleepTime = 100;
   const timeout = 5000;
 
@@ -153,12 +154,46 @@ context('Create and Delete Route', () => {
     });
   });
 
-  it('should delete the route', function () {
-    cy.visit('/routes/list');
+
+  it('should duplicate the route', function () {
+    cy.visit('/');
+    cy.contains('Route').click();
+
     cy.get(this.domSelector.nameSelector).type(newName);
     cy.contains('Search').click();
-    cy.contains(newName).siblings().contains('Delete').click();
-    cy.contains('button', 'Confirm').click();
-    cy.get(this.domSelector.notification).should('contain', this.data.deleteRouteSuccess);
+    cy.contains(newName).siblings().contains('Duplicate').click();
+
+    cy.get(this.domSelector.name).clear().type(duplicateNewName);
+    cy.get(this.domSelector.description).clear().type(this.data.description2);
+    cy.contains('Next').click();
+    cy.contains('Next').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');
+    cy.contains(duplicateNewName).siblings().should('contain', this.data.description2);
+
+    // test view
+    cy.contains(duplicateNewName).siblings().contains('View').click();
+    cy.get(this.domSelector.drawer).should('be.visible');
+
+    cy.get(this.domSelector.codemirrorScroll).within(() => {
+      cy.contains('upstream').should("exist");
+      cy.contains(duplicateNewName).should('exist');
+    });
+  });
+
+  it('should delete the route', function () {
+    cy.visit('/routes/list');
+    const { domSelector, data } = this;
+    const routeNames = [newName, duplicateNewName];
+    routeNames.forEach(function (routeName) {
+      cy.get(domSelector.name).clear().type(routeName);
+      cy.contains('Search').click();
+      cy.contains(routeName).siblings().contains('Delete').click();
+      cy.contains('button', 'Confirm').click();
+      cy.get(domSelector.notification).should('contain', data.deleteRouteSuccess);
+    });
   });
 });
diff --git a/web/src/locales/en-US/component.ts b/web/src/locales/en-US/component.ts
index 061ce40..a6a4100 100644
--- a/web/src/locales/en-US/component.ts
+++ b/web/src/locales/en-US/component.ts
@@ -35,6 +35,7 @@ export default {
   'component.global.save': 'Save',
   'component.global.edit': 'Configure',
   'component.global.view': 'View',
+  'component.global.duplicate': 'Duplicate',
   'component.global.manage': 'Manage',
   'component.global.update': 'Update',
   'component.global.get': 'Get',
diff --git a/web/src/locales/zh-CN/component.ts b/web/src/locales/zh-CN/component.ts
index 190c51e..4cb43cf 100644
--- a/web/src/locales/zh-CN/component.ts
+++ b/web/src/locales/zh-CN/component.ts
@@ -37,6 +37,7 @@ export default {
   'component.global.save': '保存',
   'component.global.edit': '配置',
   'component.global.view': '查看',
+  'component.global.duplicate': '复制',
   'component.global.manage': '管理',
   'component.global.update': '更新',
   'component.global.get': '获取',
diff --git a/web/src/pages/Route/Create.tsx b/web/src/pages/Route/Create.tsx
index 30bb210..648546f 100644
--- a/web/src/pages/Route/Create.tsx
+++ b/web/src/pages/Route/Create.tsx
@@ -88,7 +88,7 @@ const Page: React.FC<Props> = (props) => {
   };
 
   useEffect(() => {
-    if (props.route.path.indexOf('edit') !== -1) {
+    if (props.route.path.indexOf('edit') !== -1 || props.route.path.indexOf('duplicate') !== -1) {
       setupRoute(props.match.params.rid);
     } else {
       onReset();
@@ -233,7 +233,7 @@ const Page: React.FC<Props> = (props) => {
             redirectOption === 'forceHttps' && filterHosts.length !== 0
               ? checkHostWithSSL(hosts)
               : Promise.resolve(),
-            checkUniqueName(value.name, (props as any).match.params.rid || ''),
+            checkUniqueName(value.name, props.route.path.indexOf('edit') > 0 ? (props as any).match.params.rid : ''),
           ]).then(() => {
             setStep(nextStep);
           });
@@ -269,9 +269,9 @@ const Page: React.FC<Props> = (props) => {
   return (
     <>
       <PageHeaderWrapper
-        title={(props as any).match.params.rid
-          ? formatMessage({ id: 'page.route.editRoute' })
-          : formatMessage({ id: 'page.route.createRoute' })}
+        title={`${
+          formatMessage({ id: `component.global.${props.route.path.split('/').slice(-1)[0]}`})
+        } ${formatMessage({ id: 'menu.routes' })}`}
       >
         <Card bordered={false}>
           <Steps current={step - 1} className={styles.steps}>
diff --git a/web/src/pages/Route/List.tsx b/web/src/pages/Route/List.tsx
index dc5c3d3..a9c1ba5 100644
--- a/web/src/pages/Route/List.tsx
+++ b/web/src/pages/Route/List.tsx
@@ -417,6 +417,9 @@ const Page: React.FC = () => {
             }}>
               {formatMessage({ id: 'component.global.view' })}
             </Button>
+            <Button type="primary" onClick={() => history.push(`/routes/${record.id}/duplicate`)}>
+              {formatMessage({ id: 'component.global.duplicate' })}
+            </Button>
             <Popconfirm
               title={formatMessage({ id: 'component.global.popconfirm.title.delete' })}
               onConfirm={() => {