mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
feat: not found page (#1208)
* refator: added 404 page * fix: fixed lint errors * fix: fixed test * refactor: add async import
This commit is contained in:
parent
b12bfe8a3e
commit
752b870aba
10 changed files with 261 additions and 50 deletions
|
@ -9,7 +9,7 @@ import VError from 'verror';
|
|||
import chalk from 'chalk';
|
||||
import express from 'express';
|
||||
|
||||
import { combineBaseUrl, getWebProtocol } from '../../lib/utils';
|
||||
import { combineBaseUrl, getWebProtocol, spliceURL } from '../../lib/utils';
|
||||
import Search from '../../lib/search';
|
||||
import { HEADERS, HTTP_STATUS, WEB_TITLE } from '../../lib/constants';
|
||||
import { spliceURL } from '../../utils/string';
|
||||
|
|
|
@ -17,8 +17,6 @@ class Developers extends Component<Props, any> {
|
|||
};
|
||||
|
||||
render() {
|
||||
const { visibleDevs } = this.state;
|
||||
console.log('aqui', visibleDevs);
|
||||
return (
|
||||
<DetailContextConsumer>
|
||||
{({ packageMeta }) => {
|
||||
|
|
|
@ -9,7 +9,9 @@ export const Content = styled.div`
|
|||
&& {
|
||||
background-color: #ffffff;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
1
src/webui/components/NotFound/img/package.svg
Normal file
1
src/webui/components/NotFound/img/package.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 495.2 495.2"><path fill="#d38c0d" d="M325.6 224.4L495.2 126 325.6 28.4l-168.8 99.2z"/><g fill="#efbb67"><path d="M170.4 224.4l168-97.6-168-98.4L0 126.8z"/><path d="M416 368.4l-168 98.4-168-98.4v-196L248 74l168 98.4z"/></g><path fill="#d38c0d" d="M248 74l168 98.4v196l-168 98.4"/><path fill="#efbb67" d="M326.4 314.8L495.2 218l-169.6-98.4L156 218z"/><path fill="#d38c0d" d="M170.4 316.4l168.8-99.2-168.8-97.6L0 218z"/><path fill="#704a0e" d="M248.8 270.8L416 172.4 248.8 74 78.4 172.4z"/><path fill="#513307" d="M248.8 270.8L416 172.4 248.8 74"/><path fill="#2d1c05" d="M248.8 270.8l36-21.6-36-20.8-36 20.8z"/><g fill="#0dd396"><path d="M368 379.6l40-23.2v-12.8l-40 23.2zM368 356.4l40-23.2v-12.8l-40 23.2zM368 333.2l40-23.2v-13.6l-40 24z"/></g></svg>
|
After Width: | Height: | Size: 802 B |
|
@ -1,21 +1,53 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { Wrapper } from './styles';
|
||||
import { IProps } from './types';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import withWidth, { isWidthUp } from '@material-ui/core/withWidth/index';
|
||||
import ListItem from '@material-ui/core/ListItem/index';
|
||||
import Typography from '@material-ui/core/Typography/index';
|
||||
import { Wrapper, Inner, EmptyPackage, Heading, Card, List } from './styles';
|
||||
import PackageImg from './img/package.svg';
|
||||
|
||||
const NotFound = ({ pkg }: IProps) => (
|
||||
<Wrapper>
|
||||
<h1>
|
||||
{'Error 404 - '}
|
||||
{pkg}
|
||||
</h1>
|
||||
<hr />
|
||||
<p>{'Oops, The package you are trying to access does not exist.'}</p>
|
||||
</Wrapper>
|
||||
);
|
||||
// eslint-disable-next-line react/prop-types
|
||||
const NotFound = ({ history, width }) => {
|
||||
const handleGoTo = to => () => {
|
||||
history.push(to);
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
const handleGoBack = () => () => {
|
||||
history.goBack();
|
||||
};
|
||||
|
||||
const renderList = () => (
|
||||
<List>
|
||||
<ListItem button={true} divider={true} onClick={handleGoTo('/')}>
|
||||
{'Home'}
|
||||
</ListItem>
|
||||
<ListItem button={true} divider={true} onClick={handleGoBack()}>
|
||||
{'Back'}
|
||||
</ListItem>
|
||||
</List>
|
||||
);
|
||||
|
||||
const renderSubTitle = () => (
|
||||
<Typography variant={'subtitle1'}>
|
||||
<div>{"The page you're looking for doesn't exist."}</div>
|
||||
<div>{'Perhaps these links will help find what you are looking for:'}</div>
|
||||
</Typography>
|
||||
);
|
||||
|
||||
return (
|
||||
<Wrapper>
|
||||
<Inner>
|
||||
<EmptyPackage alt={'404 - Page not found'} src={PackageImg} />
|
||||
<Heading variant={isWidthUp('sm', width) ? 'h2' : 'h4'}>{"Sorry, we couldn't find it..."}</Heading>
|
||||
{renderSubTitle()}
|
||||
<Card>{renderList()}</Card>
|
||||
</Inner>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
|
||||
export default withRouter(withWidth()(NotFound));
|
||||
|
|
|
@ -4,16 +4,43 @@
|
|||
*/
|
||||
|
||||
import styled from 'react-emotion';
|
||||
import Typography from '@material-ui/core/Typography/index';
|
||||
import { default as MuiList } from '@material-ui/core/List/index';
|
||||
import { default as MuiCard } from '@material-ui/core/Card/index';
|
||||
|
||||
import { fontSize, lineHeight } from '../../utils/styles/sizes';
|
||||
export const Wrapper = styled('div')`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
`;
|
||||
|
||||
export const Wrapper = styled.div`
|
||||
export const Inner = styled('div')`
|
||||
max-width: 650px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export const EmptyPackage = styled('img')`
|
||||
width: 150px;
|
||||
margin: 0 auto;
|
||||
`;
|
||||
|
||||
export const Heading = styled(Typography)`
|
||||
&& {
|
||||
font-size: ${fontSize.md};
|
||||
line-height: ${lineHeight.xl};
|
||||
border: none;
|
||||
outline: none;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #4b5e40;
|
||||
}
|
||||
`;
|
||||
|
||||
export const List = styled(MuiList)`
|
||||
&& {
|
||||
padding: 0;
|
||||
color: #4b5e40;
|
||||
}
|
||||
`;
|
||||
|
||||
export const Card = styled(MuiCard)`
|
||||
margin-top: 24px;
|
||||
`;
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
/**
|
||||
* @prettier
|
||||
* @flow
|
||||
*/
|
||||
|
||||
export interface IProps {
|
||||
pkg: string;
|
||||
}
|
|
@ -13,6 +13,7 @@ import { asyncComponent } from './utils/asyncComponent';
|
|||
import history from './history';
|
||||
import Header from './components/Header';
|
||||
|
||||
const NotFound = asyncComponent(() => import('./components/NotFound'));
|
||||
const DetailPackage = asyncComponent(() => import('./pages/detail'));
|
||||
const VersionPackage = asyncComponent(() => import('./pages/version'));
|
||||
const HomePage = asyncComponent(() => import('./pages/home'));
|
||||
|
@ -29,6 +30,7 @@ class RouterApp extends Component<any, any> {
|
|||
<Route exact={true} path={'/-/web/detail/:package'} render={this.renderDetailPage} />
|
||||
<Route exact={true} path={'/-/web/version/@:scope/:package'} render={this.renderVersionPage} />
|
||||
<Route exact={true} path={'/-/web/version/:package'} render={this.renderVersionPage} />
|
||||
<Route component={NotFound} />
|
||||
</Switch>
|
||||
</Fragment>
|
||||
</Router>
|
||||
|
|
|
@ -1,5 +1,163 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<NotFound /> component should load the component in default state 1`] = `"<div class=\\"css-24p7uw e1gvymku0\\"><h1>Error 404 - test</h1><hr><p>Oops, The package you are trying to access does not exist.</p></div>"`;
|
||||
|
||||
exports[`<NotFound /> component should set html from props 1`] = `"<div class=\\"css-24p7uw e1gvymku0\\"><h1>Error 404 - verdaccio</h1><hr/><p>Oops, The package you are trying to access does not exist.</p></div>"`;
|
||||
exports[`<NotFound /> component should load the component in default state 1`] = `
|
||||
ShallowWrapper {
|
||||
Symbol(enzyme.__root__): ShallowWrapper {
|
||||
Symbol(enzyme.__root__): [Circular],
|
||||
Symbol(enzyme.__unrendered__): <BrowserRouter>
|
||||
<withRouter(WithTheme(WithWidth(NotFound))) />
|
||||
</BrowserRouter>,
|
||||
Symbol(enzyme.__renderer__): Object {
|
||||
"batchedUpdates": [Function],
|
||||
"getNode": [Function],
|
||||
"render": [Function],
|
||||
"simulateError": [Function],
|
||||
"simulateEvent": [Function],
|
||||
"unmount": [Function],
|
||||
},
|
||||
Symbol(enzyme.__node__): Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <withRouter(WithTheme(WithWidth(NotFound))) />,
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "function",
|
||||
"props": Object {},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
Symbol(enzyme.__nodes__): Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "class",
|
||||
"props": Object {
|
||||
"children": <withRouter(WithTheme(WithWidth(NotFound))) />,
|
||||
"history": Object {
|
||||
"action": "POP",
|
||||
"block": [Function],
|
||||
"createHref": [Function],
|
||||
"go": [Function],
|
||||
"goBack": [Function],
|
||||
"goForward": [Function],
|
||||
"length": 1,
|
||||
"listen": [Function],
|
||||
"location": Object {
|
||||
"hash": "",
|
||||
"pathname": "/",
|
||||
"search": "",
|
||||
"state": undefined,
|
||||
},
|
||||
"push": [Function],
|
||||
"replace": [Function],
|
||||
},
|
||||
},
|
||||
"ref": null,
|
||||
"rendered": Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "function",
|
||||
"props": Object {},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
Symbol(enzyme.__options__): Object {
|
||||
"adapter": ReactSixteenAdapter {
|
||||
"options": Object {
|
||||
"enableComponentDidUpdateOnSetState": true,
|
||||
"lifecycles": Object {
|
||||
"componentDidUpdate": Object {
|
||||
"onSetState": true,
|
||||
},
|
||||
"getDerivedStateFromProps": true,
|
||||
"getSnapshotBeforeUpdate": true,
|
||||
"setState": Object {
|
||||
"skipsComponentDidUpdateOnNullish": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"attachTo": undefined,
|
||||
"hydrateIn": undefined,
|
||||
},
|
||||
},
|
||||
Symbol(enzyme.__unrendered__): null,
|
||||
Symbol(enzyme.__renderer__): Object {
|
||||
"batchedUpdates": [Function],
|
||||
"getNode": [Function],
|
||||
"render": [Function],
|
||||
"simulateError": [Function],
|
||||
"simulateEvent": [Function],
|
||||
"unmount": [Function],
|
||||
},
|
||||
Symbol(enzyme.__node__): Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "function",
|
||||
"props": Object {},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
Symbol(enzyme.__nodes__): Array [
|
||||
Object {
|
||||
"instance": null,
|
||||
"key": undefined,
|
||||
"nodeType": "function",
|
||||
"props": Object {},
|
||||
"ref": null,
|
||||
"rendered": null,
|
||||
"type": [Function],
|
||||
},
|
||||
],
|
||||
Symbol(enzyme.__options__): Object {
|
||||
"adapter": ReactSixteenAdapter {
|
||||
"options": Object {
|
||||
"enableComponentDidUpdateOnSetState": true,
|
||||
"lifecycles": Object {
|
||||
"componentDidUpdate": Object {
|
||||
"onSetState": true,
|
||||
},
|
||||
"getDerivedStateFromProps": true,
|
||||
"getSnapshotBeforeUpdate": true,
|
||||
"setState": Object {
|
||||
"skipsComponentDidUpdateOnNullish": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"attachTo": undefined,
|
||||
"hydrateIn": undefined,
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -3,26 +3,25 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallow, mount } from 'enzyme';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import { shallow } from 'enzyme';
|
||||
import NotFound from '../../../../src/webui/components/NotFound/index';
|
||||
|
||||
console.error = jest.fn();
|
||||
|
||||
describe('<NotFound /> component', () => {
|
||||
test('should load the component in default state', () => {
|
||||
const wrapper = mount(<NotFound pkg={"test"} />);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
let routerWrapper;
|
||||
beforeEach(() => {
|
||||
routerWrapper = shallow(
|
||||
<Router>
|
||||
<NotFound />
|
||||
</Router>
|
||||
);
|
||||
});
|
||||
|
||||
test('should set html from props', () => {
|
||||
const props = {
|
||||
pkg: 'verdaccio'
|
||||
};
|
||||
const wrapper = shallow(<NotFound {...props} />);
|
||||
expect(wrapper.find('h1').text()).toEqual('Error 404 - verdaccio');
|
||||
expect(wrapper.find('p').text()).toEqual(
|
||||
'Oops, The package you are trying to access does not exist.'
|
||||
);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
||||
test('should load the component in default state', () => {
|
||||
expect(routerWrapper.find(NotFound)).toMatchSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue