From 478209f50dea49adf675c9c449db3b8f64e0882e Mon Sep 17 00:00:00 2001
From: Alejandro Celaya <alejandro@alejandrocelaya.com>
Date: Fri, 22 Oct 2021 18:53:00 +0200
Subject: [PATCH] Improvements on ManageServers

---
 src/servers/CreateServer.tsx                  |  3 +-
 src/servers/EditServer.tsx                    |  4 +--
 src/servers/ManageServers.tsx                 | 24 +++++++------
 src/servers/ManageServersRow.tsx              |  2 +-
 src/servers/helpers/ImportServersBtn.tsx      |  4 ++-
 test/servers/EditServer.test.tsx              |  6 ++--
 .../servers/helpers/ImportServersBtn.test.tsx | 35 ++++++++++++++-----
 7 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/src/servers/CreateServer.tsx b/src/servers/CreateServer.tsx
index 2ee329cd..e24e548c 100644
--- a/src/servers/CreateServer.tsx
+++ b/src/servers/CreateServer.tsx
@@ -27,7 +27,7 @@ const ImportResult = ({ type }: { type: 'error' | 'success' }) => (
 );
 
 const CreateServer = (ImportServersBtn: FC<ImportServersBtnProps>, useStateFlagTimeout: StateFlagTimeout) => (
-  { servers, createServer, history: { push } }: CreateServerProps,
+  { servers, createServer, history: { push, goBack } }: CreateServerProps,
 ) => {
   const hasServers = !!Object.keys(servers).length;
   const [ serversImported, setServersImported ] = useStateFlagTimeout(false, SHOW_IMPORT_MSG_TIME);
@@ -44,6 +44,7 @@ const CreateServer = (ImportServersBtn: FC<ImportServersBtnProps>, useStateFlagT
       <ServerForm title={<h5 className="mb-0">Add new server</h5>} onSubmit={handleSubmit}>
         {!hasServers &&
           <ImportServersBtn tooltipPlacement="top" onImport={setServersImported} onImportError={setErrorImporting} />}
+        {hasServers && <Button outline onClick={goBack}>Cancel</Button>}
         <Button outline color="primary" className="ml-2">Create server</Button>
       </ServerForm>
 
diff --git a/src/servers/EditServer.tsx b/src/servers/EditServer.tsx
index f18c788d..f6576066 100644
--- a/src/servers/EditServer.tsx
+++ b/src/servers/EditServer.tsx
@@ -10,7 +10,7 @@ interface EditServerProps {
 }
 
 export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>((
-  { editServer, selectedServer, history: { push, goBack } },
+  { editServer, selectedServer, history: { goBack } },
 ) => {
   if (!isServerWithId(selectedServer)) {
     return null;
@@ -18,7 +18,7 @@ export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProp
 
   const handleSubmit = (serverData: ServerData) => {
     editServer(selectedServer.id, serverData);
-    push(`/server/${selectedServer.id}`);
+    goBack();
   };
 
   return (
diff --git a/src/servers/ManageServers.tsx b/src/servers/ManageServers.tsx
index 78d1259b..3f69e43a 100644
--- a/src/servers/ManageServers.tsx
+++ b/src/servers/ManageServers.tsx
@@ -1,5 +1,5 @@
 import { FC, useEffect, useState } from 'react';
-import { Button } from 'reactstrap';
+import { Button, Row } from 'reactstrap';
 import { faFileDownload as exportIcon, faPlus as plusIcon } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Link } from 'react-router-dom';
@@ -41,15 +41,19 @@ export const ManageServers = (
     <NoMenuLayout>
       <SearchField className="mb-3" onChange={filterServers} />
 
-      <div className="mb-3 d-flex flex-row">
-        <ImportServersBtn onImportError={setErrorImporting} />
-        <Button outline className="ml-2" onClick={async () => serversExporter.exportServers()}>
-          <FontAwesomeIcon icon={exportIcon} fixedWidth /> Export servers
-        </Button>
-        <Button outline color="primary" className="ml-auto" tag={Link} to="/server/create">
-          <FontAwesomeIcon icon={plusIcon} fixedWidth /> Add a server
-        </Button>
-      </div>
+      <Row className="mb-3">
+        <div className="col-md-6 d-flex d-md-block mb-2 mb-md-0">
+          <ImportServersBtn className="flex-fill" onImportError={setErrorImporting} />
+          <Button outline className="ml-2 flex-fill" onClick={async () => serversExporter.exportServers()}>
+            <FontAwesomeIcon icon={exportIcon} fixedWidth /> Export servers
+          </Button>
+        </div>
+        <div className="col-md-6 text-md-right d-flex d-md-block">
+          <Button outline color="primary" className="flex-fill" tag={Link} to="/server/create">
+            <FontAwesomeIcon icon={plusIcon} fixedWidth /> Add a server
+          </Button>
+        </div>
+      </Row>
 
       <SimpleCard title="Shlink servers">
         <table className="table table-hover mb-0">
diff --git a/src/servers/ManageServersRow.tsx b/src/servers/ManageServersRow.tsx
index 306ef719..03ca9cae 100644
--- a/src/servers/ManageServersRow.tsx
+++ b/src/servers/ManageServersRow.tsx
@@ -54,7 +54,7 @@ export const ManageServersRow = (
             <FontAwesomeIcon icon={editIcon} fixedWidth /> Edit server
           </DropdownItem>
           <DropdownItem>
-            <FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Unset' : 'Set'} auto-connect
+            <FontAwesomeIcon icon={autoConnectIcon} fixedWidth /> {isAutoConnect ? 'Do not a' : 'A'}uto-connect
           </DropdownItem>
           <DropdownItem divider />
           <DropdownItem className="dropdown-item--danger" onClick={showModal}>
diff --git a/src/servers/helpers/ImportServersBtn.tsx b/src/servers/helpers/ImportServersBtn.tsx
index 869b661f..c9e150a5 100644
--- a/src/servers/helpers/ImportServersBtn.tsx
+++ b/src/servers/helpers/ImportServersBtn.tsx
@@ -12,6 +12,7 @@ export interface ImportServersBtnProps {
   onImport?: () => void;
   onImportError?: (error: Error) => void;
   tooltipPlacement?: 'top' | 'bottom';
+  className?: string;
 }
 
 interface ImportServersBtnConnectProps extends ImportServersBtnProps {
@@ -25,6 +26,7 @@ const ImportServersBtn = ({ importServersFromFile }: ServersImporter) => ({
   onImport = () => {},
   onImportError = () => {},
   tooltipPlacement = 'bottom',
+  className = '',
 }: ImportServersBtnConnectProps) => {
   const ref = fileRef ?? useRef<HTMLInputElement>();
   const onChange = async ({ target }: ChangeEvent<HTMLInputElement>) =>
@@ -39,7 +41,7 @@ const ImportServersBtn = ({ importServersFromFile }: ServersImporter) => ({
 
   return (
     <>
-      <Button outline id="importBtn" onClick={() => ref.current?.click()}>
+      <Button outline id="importBtn" className={className} onClick={() => ref.current?.click()}>
         <FontAwesomeIcon icon={importIcon} fixedWidth /> Import from file
       </Button>
       <UncontrolledTooltip placement={tooltipPlacement} target="importBtn">
diff --git a/test/servers/EditServer.test.tsx b/test/servers/EditServer.test.tsx
index c74cb72c..4f6a65da 100644
--- a/test/servers/EditServer.test.tsx
+++ b/test/servers/EditServer.test.tsx
@@ -10,8 +10,8 @@ describe('<EditServer />', () => {
   let wrapper: ReactWrapper;
   const ServerError = jest.fn();
   const editServerMock = jest.fn();
-  const push = jest.fn();
-  const historyMock = Mock.of<History>({ push });
+  const goBack = jest.fn();
+  const historyMock = Mock.of<History>({ goBack });
   const match = Mock.of<match<{ serverId: string }>>({
     params: { serverId: 'abc123' },
   });
@@ -50,6 +50,6 @@ describe('<EditServer />', () => {
     form.simulate('submit', {});
 
     expect(editServerMock).toHaveBeenCalledTimes(1);
-    expect(push).toHaveBeenCalledTimes(1);
+    expect(goBack).toHaveBeenCalledTimes(1);
   });
 });
diff --git a/test/servers/helpers/ImportServersBtn.test.tsx b/test/servers/helpers/ImportServersBtn.test.tsx
index da5b4941..dd8471be 100644
--- a/test/servers/helpers/ImportServersBtn.test.tsx
+++ b/test/servers/helpers/ImportServersBtn.test.tsx
@@ -15,25 +15,43 @@ describe('<ImportServersBtn />', () => {
   const fileRef = {
     current: Mock.of<HTMLInputElement>({ click }),
   };
-
-  beforeEach(() => {
-    jest.clearAllMocks();
-
-    const ImportServersBtn = importServersBtnConstruct(serversImporterMock);
-
+  const ImportServersBtn = importServersBtnConstruct(serversImporterMock);
+  const createWrapper = (className?: string) => {
     wrapper = shallow(
-      <ImportServersBtn createServers={createServersMock} fileRef={fileRef} onImport={onImportMock} />,
+      <ImportServersBtn
+        createServers={createServersMock}
+        className={className}
+        fileRef={fileRef}
+        onImport={onImportMock}
+      />,
     );
-  });
+
+    return wrapper;
+  };
+
+  afterEach(jest.clearAllMocks);
   afterEach(() => wrapper.unmount());
 
   it('renders a button, a tooltip and a file input', () => {
+    const wrapper = createWrapper();
+
     expect(wrapper.find('#importBtn')).toHaveLength(1);
     expect(wrapper.find(UncontrolledTooltip)).toHaveLength(1);
     expect(wrapper.find('.import-servers-btn__csv-select')).toHaveLength(1);
   });
 
+  it.each([
+    [ undefined, '' ],
+    [ 'foo', 'foo' ],
+    [ 'bar', 'bar' ],
+  ])('allows a class name to be provided', (providedClassName, expectedClassName) => {
+    const wrapper = createWrapper(providedClassName);
+
+    expect(wrapper.find('#importBtn').prop('className')).toEqual(expectedClassName);
+  });
+
   it('triggers click on file ref when button is clicked', () => {
+    const wrapper = createWrapper();
     const btn = wrapper.find('#importBtn');
 
     btn.simulate('click');
@@ -42,6 +60,7 @@ describe('<ImportServersBtn />', () => {
   });
 
   it('imports servers when file input changes', (done) => {
+    const wrapper = createWrapper();
     const file = wrapper.find('.import-servers-btn__csv-select');
 
     file.simulate('change', { target: { files: [ '' ] } });