Created Overview page as default page after connecting to a server

This commit is contained in:
Alejandro Celaya 2020-12-06 18:32:24 +01:00
parent 920effb4c6
commit dba0ac6442
13 changed files with 73 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import {
faLink as createIcon, faLink as createIcon,
faTags as tagsIcon, faTags as tagsIcon,
faPen as editIcon, faPen as editIcon,
faHome as overviewIcon,
} from '@fortawesome/free-solid-svg-icons'; } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { FC } from 'react'; import { FC } from 'react';
@ -48,6 +49,10 @@ const AsideMenu = (DeleteServerButton: FC<DeleteServerButtonProps>) => (
return ( return (
<aside className={asideClass}> <aside className={asideClass}>
<nav className="nav flex-column aside-menu__nav"> <nav className="nav flex-column aside-menu__nav">
<AsideMenuItem to={buildPath('/overview')}>
<FontAwesomeIcon icon={overviewIcon} />
<span className="aside-menu__item-text">Overview</span>
</AsideMenuItem>
<AsideMenuItem to={buildPath('/list-short-urls/1')} isActive={shortUrlsIsActive}> <AsideMenuItem to={buildPath('/list-short-urls/1')} isActive={shortUrlsIsActive}>
<FontAwesomeIcon icon={listIcon} /> <FontAwesomeIcon icon={listIcon} />
<span className="aside-menu__item-text">List short URLs</span> <span className="aside-menu__item-text">List short URLs</span>

View File

@ -20,6 +20,7 @@ const MenuLayout = (
ShortUrlVisits: FC, ShortUrlVisits: FC,
TagVisits: FC, TagVisits: FC,
ServerError: FC, ServerError: FC,
Overview: FC,
) => withSelectedServer(({ location, selectedServer }) => { ) => withSelectedServer(({ location, selectedServer }) => {
const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle(); const [ sidebarVisible, toggleSidebar, showSidebar, hideSidebar ] = useToggle();
@ -60,6 +61,7 @@ const MenuLayout = (
<div className="col-lg-10 offset-lg-2 col-md-9 offset-md-3" onClick={() => hideSidebar()}> <div className="col-lg-10 offset-lg-2 col-md-9 offset-md-3" onClick={() => hideSidebar()}>
<div className="menu-layout__container"> <div className="menu-layout__container">
<Switch> <Switch>
<Route exact path="/server/:serverId/overview" component={Overview} />
<Route exact path="/server/:serverId/list-short-urls/:page" component={ShortUrls} /> <Route exact path="/server/:serverId/list-short-urls/:page" component={ShortUrls} />
<Route exact path="/server/:serverId/create-short-url" component={CreateShortUrl} /> <Route exact path="/server/:serverId/create-short-url" component={CreateShortUrl} />
<Route exact path="/server/:serverId/short-code/:shortCode/visits" component={ShortUrlVisits} /> <Route exact path="/server/:serverId/short-code/:shortCode/visits" component={ShortUrlVisits} />

View File

@ -33,6 +33,7 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter:
'ShortUrlVisits', 'ShortUrlVisits',
'TagVisits', 'TagVisits',
'ServerError', 'ServerError',
'Overview',
); );
bottle.decorator('MenuLayout', connect([ 'selectedServer', 'shortUrlsListParams' ], [ 'selectServer' ])); bottle.decorator('MenuLayout', connect([ 'selectedServer', 'shortUrlsListParams' ], [ 'selectServer' ]));
bottle.decorator('MenuLayout', withRouter); bottle.decorator('MenuLayout', withRouter);

View File

@ -39,7 +39,7 @@ const CreateServer = (ImportServersBtn: FC<ImportServersBtnProps>, useStateFlagT
const id = uuid(); const id = uuid();
createServer({ ...serverData, id }); createServer({ ...serverData, id });
push(`/server/${id}/list-short-urls/1`); push(`/server/${id}/overview`);
}; };
return ( return (

View File

@ -26,7 +26,7 @@ const DeleteServerModal = ({ server, toggle, isOpen, deleteServer, history }: De
<p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p> <p>Are you sure you want to remove <b>{server ? server.name : ''}</b>?</p>
<p> <p>
<i> <i>
No data will be deleted, only the access to this server will be removed from this host. No data will be deleted, only the access to this server will be removed from this device.
You can create it again at any moment. You can create it again at any moment.
</i> </i>
</p> </p>

View File

@ -18,7 +18,7 @@ export const EditServer = (ServerError: FC) => withSelectedServer<EditServerProp
const handleSubmit = (serverData: ServerData) => { const handleSubmit = (serverData: ServerData) => {
editServer(selectedServer.id, serverData); editServer(selectedServer.id, serverData);
push(`/server/${selectedServer.id}/list-short-urls/1`); push(`/server/${selectedServer.id}/overview`);
}; };
return ( return (

50
src/servers/Overview.tsx Normal file
View File

@ -0,0 +1,50 @@
import { useEffect } from 'react';
import { Card, CardText, CardTitle } from 'reactstrap';
import { ShortUrlsListParams } from '../short-urls/reducers/shortUrlsListParams';
import { ShortUrlsList as ShortUrlsListState } from '../short-urls/reducers/shortUrlsList';
import { prettify } from '../utils/helpers/numbers';
import { TagsList } from '../tags/reducers/tagsList';
interface OverviewConnectProps {
shortUrlsList: ShortUrlsListState;
listShortUrls: (params: ShortUrlsListParams) => void;
listTags: Function;
tagsList: TagsList;
}
export const Overview = ({ shortUrlsList, listShortUrls, listTags, tagsList }: OverviewConnectProps) => {
const { loading, error, shortUrls } = shortUrlsList;
const { loading: loadingTags } = tagsList;
useEffect(() => {
listShortUrls({ itemsPerPage: 5 });
listTags();
}, []);
return (
<div className="row">
<div className="col-sm-4">
<Card className="text-center mb-2 mb-sm-0" body>
<CardTitle tag="h5">Visits</CardTitle>
<CardText tag="h2">?</CardText>
</Card>
</div>
<div className="col-sm-4">
<Card className="text-center mb-2 mb-sm-0" body>
<CardTitle tag="h5">Short URLs</CardTitle>
<CardText tag="h2">
{loading && !error && 'Loading...'}
{error && !loading && 'Failed :('}
{!error && !loading && prettify(shortUrls?.pagination.totalItems ?? 0)}
</CardText>
</Card>
</div>
<div className="col-sm-4">
<Card className="text-center" body>
<CardTitle tag="h5">Tags</CardTitle>
<CardText tag="h2">{loadingTags ? 'Loading... ' : prettify(tagsList.tags.length)}</CardText>
</Card>
</div>
</div>
);
};

View File

@ -23,7 +23,7 @@ const ServersDropdown = (serversExporter: ServersExporter) => ({ servers, select
<DropdownItem <DropdownItem
key={id} key={id}
tag={Link} tag={Link}
to={`/server/${id}/list-short-urls/1`} to={`/server/${id}/overview`}
active={isServerWithId(selectedServer) && selectedServer.id === id} active={isServerWithId(selectedServer) && selectedServer.id === id}
> >
{name} {name}

View File

@ -11,7 +11,7 @@ interface ServersListGroup {
} }
const ServerListItem = ({ id, name }: { id: string; name: string }) => ( const ServerListItem = ({ id, name }: { id: string; name: string }) => (
<ListGroupItem tag={Link} to={`/server/${id}/list-short-urls/1`} className="servers-list__server-item"> <ListGroupItem tag={Link} to={`/server/${id}/overview`} className="servers-list__server-item">
{name} {name}
<FontAwesomeIcon icon={chevronIcon} className="servers-list__server-item-icon" /> <FontAwesomeIcon icon={chevronIcon} className="servers-list__server-item-icon" />
</ListGroupItem> </ListGroupItem>

View File

@ -13,6 +13,7 @@ import ForServerVersion from '../helpers/ForServerVersion';
import { ServerError } from '../helpers/ServerError'; import { ServerError } from '../helpers/ServerError';
import { ConnectDecorator } from '../../container/types'; import { ConnectDecorator } from '../../container/types';
import { withoutSelectedServer } from '../helpers/withoutSelectedServer'; import { withoutSelectedServer } from '../helpers/withoutSelectedServer';
import { Overview } from '../Overview';
import ServersImporter from './ServersImporter'; import ServersImporter from './ServersImporter';
import ServersExporter from './ServersExporter'; import ServersExporter from './ServersExporter';
@ -43,6 +44,12 @@ const provideServices = (bottle: Bottle, connect: ConnectDecorator, withRouter:
bottle.serviceFactory('ServerError', ServerError, 'DeleteServerButton'); bottle.serviceFactory('ServerError', ServerError, 'DeleteServerButton');
bottle.decorator('ServerError', connect([ 'servers', 'selectedServer' ])); bottle.decorator('ServerError', connect([ 'servers', 'selectedServer' ]));
bottle.serviceFactory('Overview', () => Overview);
bottle.decorator('Overview', connect(
[ 'shortUrlsList', 'tagsList' ],
[ 'listShortUrls', 'listTags' ],
));
// Services // Services
bottle.constant('csvjson', csvjson); bottle.constant('csvjson', csvjson);
bottle.constant('fileReaderFactory', () => new FileReader()); bottle.constant('fileReaderFactory', () => new FileReader());

View File

@ -15,6 +15,7 @@ export type OrderableFields = keyof typeof SORTABLE_FIELDS;
export interface ShortUrlsListParams { export interface ShortUrlsListParams {
page?: string; page?: string;
itemsPerPage?: number;
tags?: string[]; tags?: string[];
searchTerm?: string; searchTerm?: string;
startDate?: string; startDate?: string;

View File

@ -36,6 +36,7 @@ export interface ShlinkTagsResponse {
export interface ShlinkPaginator { export interface ShlinkPaginator {
currentPage: number; currentPage: number;
pagesCount: number; pagesCount: number;
totalItems: number;
} }
export interface ShlinkVisits { export interface ShlinkVisits {

View File

@ -17,7 +17,7 @@ describe('<AsideMenu />', () => {
it('contains links to different sections', () => { it('contains links to different sections', () => {
const links = wrapped.find('[to]'); const links = wrapped.find('[to]');
expect(links).toHaveLength(4); expect(links).toHaveLength(5);
links.forEach((link) => expect(link.prop('to')).toContain('abc123')); links.forEach((link) => expect(link.prop('to')).toContain('abc123'));
}); });