mirror of
https://github.com/shlinkio/shlink-web-client.git
synced 2024-12-23 09:30:31 +03:00
Finished migrating servers module to TS
This commit is contained in:
parent
ef630af154
commit
c0f5d9c12c
8 changed files with 130 additions and 142 deletions
|
@ -1,5 +1,5 @@
|
|||
import React, { FC, useEffect } from 'react';
|
||||
import { Route, RouteChildrenProps, Switch } from 'react-router-dom';
|
||||
import { Route, Switch } from 'react-router-dom';
|
||||
import { EventData, Swipeable } from 'react-swipeable';
|
||||
import { faBars as burgerIcon } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
@ -7,15 +7,11 @@ import classNames from 'classnames';
|
|||
import { withSelectedServer } from '../servers/helpers/withSelectedServer';
|
||||
import { useToggle } from '../utils/helpers/hooks';
|
||||
import { versionMatch } from '../utils/helpers/version';
|
||||
import { isReachableServer, SelectedServer } from '../servers/data';
|
||||
import { isReachableServer } from '../servers/data';
|
||||
import NotFound from './NotFound';
|
||||
import { AsideMenuProps } from './AsideMenu';
|
||||
import './MenuLayout.scss';
|
||||
|
||||
interface MenuLayoutProps extends RouteChildrenProps {
|
||||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
const MenuLayout = (
|
||||
TagsList: FC,
|
||||
ShortUrls: FC,
|
||||
|
@ -25,7 +21,7 @@ const MenuLayout = (
|
|||
TagVisits: FC,
|
||||
ShlinkVersions: FC,
|
||||
ServerError: FC,
|
||||
) => withSelectedServer(({ location, selectedServer }: MenuLayoutProps) => {
|
||||
) => withSelectedServer(({ location, selectedServer }) => {
|
||||
const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle();
|
||||
|
||||
useEffect(() => hideSidebar(), [ location ]);
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Button } from 'reactstrap';
|
||||
import NoMenuLayout from '../common/NoMenuLayout';
|
||||
import { ServerForm } from './helpers/ServerForm';
|
||||
import { withSelectedServer } from './helpers/withSelectedServer';
|
||||
import { serverType } from './prop-types';
|
||||
|
||||
const propTypes = {
|
||||
editServer: PropTypes.func,
|
||||
selectedServer: serverType,
|
||||
history: PropTypes.shape({
|
||||
push: PropTypes.func,
|
||||
goBack: PropTypes.func,
|
||||
}),
|
||||
};
|
||||
|
||||
export const EditServer = (ServerError) => {
|
||||
const EditServerComp = ({ editServer, selectedServer, history: { push, goBack } }) => {
|
||||
const handleSubmit = (serverData) => {
|
||||
editServer(selectedServer.id, serverData);
|
||||
push(`/server/${selectedServer.id}/list-short-urls/1`);
|
||||
};
|
||||
|
||||
return (
|
||||
<NoMenuLayout>
|
||||
<ServerForm initialValues={selectedServer} onSubmit={handleSubmit}>
|
||||
<Button outline className="mr-2" onClick={goBack}>Cancel</Button>
|
||||
<Button outline color="primary">Save</Button>
|
||||
</ServerForm>
|
||||
</NoMenuLayout>
|
||||
);
|
||||
};
|
||||
|
||||
EditServerComp.propTypes = propTypes;
|
||||
|
||||
return withSelectedServer(EditServerComp, ServerError);
|
||||
};
|
32
src/servers/EditServer.tsx
Normal file
32
src/servers/EditServer.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
import React, { FC } from 'react';
|
||||
import { Button } from 'reactstrap';
|
||||
import NoMenuLayout from '../common/NoMenuLayout';
|
||||
import { ServerForm } from './helpers/ServerForm';
|
||||
import { withSelectedServer } from './helpers/withSelectedServer';
|
||||
import { isServerWithId, ServerData } from './data';
|
||||
|
||||
interface EditServerProps {
|
||||
editServer: (serverId: string, serverData: ServerData) => void;
|
||||
}
|
||||
|
||||
export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProps>((
|
||||
{ editServer, selectedServer, history: { push, goBack } },
|
||||
) => {
|
||||
if (!isServerWithId(selectedServer)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleSubmit = (serverData: ServerData) => {
|
||||
editServer(selectedServer.id, serverData);
|
||||
push(`/server/${selectedServer.id}/list-short-urls/1`);
|
||||
};
|
||||
|
||||
return (
|
||||
<NoMenuLayout>
|
||||
<ServerForm initialValues={selectedServer} onSubmit={handleSubmit}>
|
||||
<Button outline className="mr-2" onClick={goBack}>Cancel</Button>
|
||||
<Button outline color="primary">Save</Button>
|
||||
</ServerForm>
|
||||
</NoMenuLayout>
|
||||
);
|
||||
}, ServerError);
|
|
@ -1,55 +0,0 @@
|
|||
import { isEmpty, values } from 'ramda';
|
||||
import React from 'react';
|
||||
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { serverType } from './prop-types';
|
||||
|
||||
const propTypes = {
|
||||
servers: PropTypes.object,
|
||||
selectedServer: serverType,
|
||||
};
|
||||
|
||||
const ServersDropdown = (serversExporter) => {
|
||||
const ServersDropdownComp = ({ servers, selectedServer }) => {
|
||||
const serversList = values(servers);
|
||||
|
||||
const renderServers = () => {
|
||||
if (isEmpty(serversList)) {
|
||||
return <DropdownItem disabled><i>Add a server first...</i></DropdownItem>;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{serversList.map(({ name, id }) => (
|
||||
<DropdownItem
|
||||
key={id}
|
||||
tag={Link}
|
||||
to={`/server/${id}/list-short-urls/1`}
|
||||
active={selectedServer && selectedServer.id === id}
|
||||
>
|
||||
{name}
|
||||
</DropdownItem>
|
||||
))}
|
||||
<DropdownItem divider />
|
||||
<DropdownItem className="servers-dropdown__export-item" onClick={() => serversExporter.exportServers()}>
|
||||
Export servers
|
||||
</DropdownItem>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<UncontrolledDropdown nav inNavbar>
|
||||
<DropdownToggle nav caret>Servers</DropdownToggle>
|
||||
<DropdownMenu right>{renderServers()}</DropdownMenu>
|
||||
</UncontrolledDropdown>
|
||||
);
|
||||
};
|
||||
|
||||
ServersDropdownComp.propTypes = propTypes;
|
||||
|
||||
return ServersDropdownComp;
|
||||
};
|
||||
|
||||
export default ServersDropdown;
|
49
src/servers/ServersDropdown.tsx
Normal file
49
src/servers/ServersDropdown.tsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
import { isEmpty, values } from 'ramda';
|
||||
import React from 'react';
|
||||
import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledDropdown } from 'reactstrap';
|
||||
import { Link } from 'react-router-dom';
|
||||
import ServersExporter from './services/ServersExporter';
|
||||
import { isServerWithId, SelectedServer, ServersMap } from './data';
|
||||
|
||||
export interface ServersDropdownProps {
|
||||
servers: ServersMap;
|
||||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
const ServersDropdown = (serversExporter: ServersExporter) => ({ servers, selectedServer }: ServersDropdownProps) => {
|
||||
const serversList = values(servers);
|
||||
|
||||
const renderServers = () => {
|
||||
if (isEmpty(serversList)) {
|
||||
return <DropdownItem disabled><i>Add a server first...</i></DropdownItem>;
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{serversList.map(({ name, id }) => (
|
||||
<DropdownItem
|
||||
key={id}
|
||||
tag={Link}
|
||||
to={`/server/${id}/list-short-urls/1`}
|
||||
active={isServerWithId(selectedServer) && selectedServer.id === id}
|
||||
>
|
||||
{name}
|
||||
</DropdownItem>
|
||||
))}
|
||||
<DropdownItem divider />
|
||||
<DropdownItem className="servers-dropdown__export-item" onClick={async () => serversExporter.exportServers()}>
|
||||
Export servers
|
||||
</DropdownItem>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<UncontrolledDropdown nav inNavbar>
|
||||
<DropdownToggle nav caret>Servers</DropdownToggle>
|
||||
<DropdownMenu right>{renderServers()}</DropdownMenu>
|
||||
</UncontrolledDropdown>
|
||||
);
|
||||
};
|
||||
|
||||
export default ServersDropdown;
|
|
@ -8,22 +8,22 @@ interface WithSelectedServerProps extends RouteChildrenProps<{ serverId: string
|
|||
selectedServer: SelectedServer;
|
||||
}
|
||||
|
||||
export const withSelectedServer = (WrappedComponent: FC<WithSelectedServerProps>, ServerError: FC) => (
|
||||
props: WithSelectedServerProps,
|
||||
) => {
|
||||
const { selectServer, selectedServer, match } = props;
|
||||
export function withSelectedServer<T = {}>(WrappedComponent: FC<WithSelectedServerProps & T>, ServerError: FC) {
|
||||
return (props: WithSelectedServerProps & T) => {
|
||||
const { selectServer, selectedServer, match } = props;
|
||||
|
||||
useEffect(() => {
|
||||
match?.params?.serverId && selectServer(match?.params.serverId);
|
||||
}, [ match?.params.serverId ]);
|
||||
useEffect(() => {
|
||||
match?.params?.serverId && selectServer(match?.params.serverId);
|
||||
}, [ match?.params.serverId ]);
|
||||
|
||||
if (!selectedServer) {
|
||||
return <Message loading />;
|
||||
}
|
||||
if (!selectedServer) {
|
||||
return <Message loading />;
|
||||
}
|
||||
|
||||
if (isNotFoundServer(selectedServer)) {
|
||||
return <ServerError />;
|
||||
}
|
||||
if (isNotFoundServer(selectedServer)) {
|
||||
return <ServerError />;
|
||||
}
|
||||
|
||||
return <WrappedComponent {...props} />;
|
||||
};
|
||||
return <WrappedComponent {...props} />;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,22 +1,27 @@
|
|||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import { History, Location } from 'history';
|
||||
import { match } from 'react-router'; // eslint-disable-line @typescript-eslint/no-unused-vars
|
||||
import { EditServer as editServerConstruct } from '../../src/servers/EditServer';
|
||||
import { ServerForm } from '../../src/servers/helpers/ServerForm';
|
||||
import { ReachableServer } from '../../src/servers/data';
|
||||
|
||||
describe('<EditServer />', () => {
|
||||
let wrapper;
|
||||
let wrapper: ReactWrapper;
|
||||
const ServerError = jest.fn();
|
||||
const editServerMock = jest.fn();
|
||||
const historyMock = { push: jest.fn() };
|
||||
const match = {
|
||||
const push = jest.fn();
|
||||
const historyMock = Mock.of<History>({ push });
|
||||
const match = Mock.of<match<{ serverId: string }>>({
|
||||
params: { serverId: 'abc123' },
|
||||
};
|
||||
const selectedServer = {
|
||||
});
|
||||
const selectedServer = Mock.of<ReachableServer>({
|
||||
id: 'abc123',
|
||||
name: 'name',
|
||||
url: 'url',
|
||||
apiKey: 'apiKey',
|
||||
};
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
const EditServer = editServerConstruct(ServerError);
|
||||
|
@ -26,16 +31,15 @@ describe('<EditServer />', () => {
|
|||
editServer={editServerMock}
|
||||
history={historyMock}
|
||||
match={match}
|
||||
location={Mock.all<Location>()}
|
||||
selectedServer={selectedServer}
|
||||
selectServer={jest.fn()}
|
||||
/>,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
wrapper && wrapper.unmount();
|
||||
});
|
||||
afterEach(jest.resetAllMocks);
|
||||
afterEach(() => wrapper?.unmount());
|
||||
|
||||
it('renders components', () => {
|
||||
expect(wrapper.find(ServerForm)).toHaveLength(1);
|
||||
|
@ -47,6 +51,6 @@ describe('<EditServer />', () => {
|
|||
form.simulate('submit', {});
|
||||
|
||||
expect(editServerMock).toHaveBeenCalledTimes(1);
|
||||
expect(historyMock.push).toHaveBeenCalledTimes(1);
|
||||
expect(push).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
|
@ -1,24 +1,24 @@
|
|||
import { identity, values } from 'ramda';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { values } from 'ramda';
|
||||
import { Mock } from 'ts-mockery';
|
||||
import React, { FC } from 'react';
|
||||
import { shallow, ShallowWrapper } from 'enzyme';
|
||||
import { DropdownItem, DropdownToggle } from 'reactstrap';
|
||||
import serversDropdownCreator from '../../src/servers/ServersDropdown';
|
||||
import serversDropdownCreator, { ServersDropdownProps } from '../../src/servers/ServersDropdown';
|
||||
import { ServerWithId } from '../../src/servers/data';
|
||||
import ServersExporter from '../../src/servers/services/ServersExporter';
|
||||
|
||||
describe('<ServersDropdown />', () => {
|
||||
let wrapped;
|
||||
let ServersDropdown;
|
||||
let wrapped: ShallowWrapper;
|
||||
let ServersDropdown: FC<ServersDropdownProps>;
|
||||
const servers = {
|
||||
'1a': { name: 'foo', id: 1 },
|
||||
'2b': { name: 'bar', id: 2 },
|
||||
'3c': { name: 'baz', id: 3 },
|
||||
};
|
||||
const history = {
|
||||
push: jest.fn(),
|
||||
'1a': Mock.of<ServerWithId>({ name: 'foo', id: '1a' }),
|
||||
'2b': Mock.of<ServerWithId>({ name: 'bar', id: '2b' }),
|
||||
'3c': Mock.of<ServerWithId>({ name: 'baz', id: '3c' }),
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
ServersDropdown = serversDropdownCreator({});
|
||||
wrapped = shallow(<ServersDropdown servers={servers} listServers={identity} history={history} />);
|
||||
ServersDropdown = serversDropdownCreator(Mock.of<ServersExporter>());
|
||||
wrapped = shallow(<ServersDropdown servers={servers} selectedServer={null} />);
|
||||
});
|
||||
afterEach(() => wrapped.unmount());
|
||||
|
||||
|
@ -37,7 +37,7 @@ describe('<ServersDropdown />', () => {
|
|||
|
||||
it('shows a message when no servers exist yet', () => {
|
||||
wrapped = shallow(
|
||||
<ServersDropdown servers={{}} listServers={identity} history={history} />,
|
||||
<ServersDropdown servers={{}} selectedServer={null} />,
|
||||
);
|
||||
const item = wrapped.find(DropdownItem);
|
||||
|
Loading…
Reference in a new issue