Improvements on ManageServers

This commit is contained in:
Alejandro Celaya 2021-10-22 18:53:00 +02:00
parent 7f4263966e
commit 478209f50d
7 changed files with 52 additions and 26 deletions

View file

@ -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>

View file

@ -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 (

View file

@ -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">

View file

@ -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}>

View file

@ -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">

View file

@ -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);
});
});

View file

@ -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: [ '' ] } });