mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-03-25 02:32:52 -05:00
refactor: package list
This commit is contained in:
parent
c9858c85e3
commit
5aff7bc1a8
11 changed files with 88 additions and 86 deletions
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import isNil from 'lodash/isNil';
|
||||
|
||||
|
@ -16,7 +20,6 @@ import 'normalize.css';
|
|||
import Footer from './components/Footer';
|
||||
|
||||
export const AppContext = React.createContext();
|
||||
|
||||
export const AppContextProvider = AppContext.Provider;
|
||||
export const AppContextConsumer = AppContext.Consumer;
|
||||
|
||||
|
@ -25,12 +28,12 @@ export default class App extends Component {
|
|||
error: {},
|
||||
logoUrl: window.VERDACCIO_LOGO,
|
||||
user: {},
|
||||
scope: (window.VERDACCIO_SCOPE) ? `${window.VERDACCIO_SCOPE}:` : '',
|
||||
scope: window.VERDACCIO_SCOPE ? `${window.VERDACCIO_SCOPE}:` : '',
|
||||
showLoginModal: false,
|
||||
isUserLoggedIn: false,
|
||||
packages: [],
|
||||
isLoading: true,
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.isUserAlreadyLoggedIn();
|
||||
|
@ -45,19 +48,36 @@ export default class App extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isLoading, isUserLoggedIn, packages, logoUrl, user, scope } = this.state;
|
||||
|
||||
return (
|
||||
<Container isLoading={isLoading}>
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Fragment>
|
||||
<AppContextProvider value={{ isUserLoggedIn, packages, logoUrl, user, scope }}>{this.renderContent()}</AppContextProvider>
|
||||
</Fragment>
|
||||
)}
|
||||
{this.renderLoginModal()}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
isUserAlreadyLoggedIn = () => {
|
||||
// checks for token validity
|
||||
const token = storage.getItem('token');
|
||||
const username = storage.getItem('username');
|
||||
if (isTokenExpire(token) || isNil(username)) {
|
||||
this.handleLogout();
|
||||
this.handleLogout();
|
||||
} else {
|
||||
this.setState({
|
||||
user: { username, token },
|
||||
isUserLoggedIn: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
loadOnHandler = async () => {
|
||||
try {
|
||||
|
@ -74,34 +94,30 @@ export default class App extends Component {
|
|||
});
|
||||
this.setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setLoading = isLoading => (
|
||||
setLoading = isLoading =>
|
||||
this.setState({
|
||||
isLoading,
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
/**
|
||||
* Toggles the login modal
|
||||
* Required by: <LoginModal /> <Header />
|
||||
*/
|
||||
handleToggleLoginModal = () => {
|
||||
this.setState((prevState) => ({
|
||||
this.setState(prevState => ({
|
||||
showLoginModal: !prevState.showLoginModal,
|
||||
error: {},
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* handles login
|
||||
* Required by: <Header />
|
||||
*/
|
||||
handleDoLogin = async (usernameValue, passwordValue) => {
|
||||
const { username, token, error } = await makeLogin(
|
||||
usernameValue,
|
||||
passwordValue
|
||||
);
|
||||
const { username, token, error } = await makeLogin(usernameValue, passwordValue);
|
||||
|
||||
if (username && token) {
|
||||
this.setLoggedUser(username, token);
|
||||
|
@ -115,7 +131,7 @@ export default class App extends Component {
|
|||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
setLoggedUser = (username, token) => {
|
||||
this.setState({
|
||||
|
@ -123,10 +139,11 @@ export default class App extends Component {
|
|||
username,
|
||||
token,
|
||||
},
|
||||
isUserLoggedIn: true, // close login modal after successful login
|
||||
showLoginModal: false, // set isUserLoggedIn to true
|
||||
isUserLoggedIn: true, // close login modal after successful login
|
||||
showLoginModal: false, // set isUserLoggedIn to true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Logouts user
|
||||
* Required by: <Header />
|
||||
|
@ -138,25 +155,7 @@ export default class App extends Component {
|
|||
user: {},
|
||||
isUserLoggedIn: false,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isLoading, isUserLoggedIn, packages, logoUrl, user, scope } = this.state;
|
||||
return (
|
||||
<Container isLoading={isLoading}>
|
||||
{isLoading ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<Fragment>
|
||||
<AppContextProvider value={{isUserLoggedIn, packages, logoUrl, user, scope}}>
|
||||
{this.renderContent()}
|
||||
</AppContextProvider>
|
||||
</Fragment>
|
||||
)}
|
||||
{this.renderLoginModal()}
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderLoginModal = () => {
|
||||
const { error, showLoginModal } = this.state;
|
||||
|
@ -169,34 +168,24 @@ export default class App extends Component {
|
|||
visibility={showLoginModal}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderContent = () => {
|
||||
return (
|
||||
<Fragment>
|
||||
<Content>
|
||||
<RouterApp
|
||||
onLogout={this.handleLogout}
|
||||
onToggleLoginModal={this.handleToggleLoginModal}>
|
||||
<RouterApp onLogout={this.handleLogout} onToggleLoginModal={this.handleToggleLoginModal}>
|
||||
{this.renderHeader()}
|
||||
</RouterApp>
|
||||
</Content>
|
||||
<Footer />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
renderHeader = () => {
|
||||
const { logoUrl, user, scope } = this.state;
|
||||
const { logoUrl, user: { username } = {}, scope } = this.state;
|
||||
|
||||
return (
|
||||
<Header
|
||||
logo={logoUrl}
|
||||
onLogout={this.handleLogout}
|
||||
onToggleLoginModal={this.handleToggleLoginModal}
|
||||
scope={scope}
|
||||
username={user.username}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return <Header logo={logoUrl} onLogout={this.handleLogout} onToggleLoginModal={this.handleToggleLoginModal} scope={scope} username={username} />;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" id="fileBinary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="filebinary">
|
||||
<path d="M8.5 1H1c-.55 0-1 .45-1 1v12c0 .55.45 1 1 1h10c.55 0 1-.45 1-1V4.5L8.5 1zM11 14H1V2h7l3 3v9zM5 6.98L3.5 8.5 5 10l-.5 1L2 8.5 4.5 6l.5.98zM7.5 6L10 8.5 7.5 11l-.5-.98L8.5 8.5 7 7l.5-1z"></path>
|
||||
</svg>
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 265 B |
|
@ -19,7 +19,7 @@ import austria from './img/austria.svg';
|
|||
import spain from './img/spain.svg';
|
||||
import earth from './img/earth.svg';
|
||||
import verdaccio from './img/verdaccio.svg';
|
||||
import fileBinary from './img/fileBinary.svg';
|
||||
import filebinary from './img/filebinary.svg';
|
||||
import law from './img/law.svg';
|
||||
import license from './img/license.svg';
|
||||
import time from './img/time.svg';
|
||||
|
@ -37,7 +37,7 @@ export const Icons: $Shape<IIconsMap> = {
|
|||
earth,
|
||||
verdaccio,
|
||||
// other icons
|
||||
fileBinary,
|
||||
filebinary,
|
||||
law,
|
||||
license,
|
||||
time,
|
||||
|
|
|
@ -19,7 +19,7 @@ export interface IIconsMap {
|
|||
time: string;
|
||||
law: string;
|
||||
version: string;
|
||||
fileBinary: string;
|
||||
filebinary: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ const Package = ({
|
|||
const renderFileSize = () =>
|
||||
unpackedSize && (
|
||||
<OverviewItem>
|
||||
<Icon name={'fileBinary'} />
|
||||
<Icon name={'filebinary'} />
|
||||
{fileSizeSI(unpackedSize)}
|
||||
</OverviewItem>
|
||||
);
|
||||
|
@ -157,4 +157,5 @@ const Package = ({
|
|||
</PackageList>
|
||||
);
|
||||
};
|
||||
|
||||
export default Package;
|
||||
|
|
|
@ -1,24 +1,32 @@
|
|||
/**
|
||||
* @prettier
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export function asyncComponent(getComponent) {
|
||||
return class AsyncComponent extends React.Component {
|
||||
static Component = null;
|
||||
state = {Component: AsyncComponent.Component};
|
||||
state = { Component: AsyncComponent.Component };
|
||||
|
||||
componentDidMount() {
|
||||
const {Component} = this.state;
|
||||
|
||||
const { Component } = this.state;
|
||||
if (!Component) {
|
||||
getComponent().then(({default: Component}) => {
|
||||
AsyncComponent.Component = Component;
|
||||
/* eslint react/no-did-mount-set-state:0 */
|
||||
this.setState({Component});
|
||||
});
|
||||
getComponent()
|
||||
.then(({ default: Component }) => {
|
||||
AsyncComponent.Component = Component;
|
||||
/* eslint react/no-did-mount-set-state:0 */
|
||||
this.setState({ Component });
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
render() {
|
||||
const {Component} = this.state;
|
||||
const { Component } = this.state;
|
||||
if (Component) {
|
||||
// eslint-disable-next-line verdaccio/jsx-spread
|
||||
return <Component {...this.props} />;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
|||
import { mount } from 'enzyme';
|
||||
import storage from '../../../src/webui/utils/storage';
|
||||
import App from '../../../src/webui/app';
|
||||
import { API_ERROR } from '../../../src/lib/constants';
|
||||
|
||||
import { generateTokenWithTimeRange } from './components/__mocks__/token';
|
||||
|
||||
|
@ -38,7 +37,7 @@ describe('App', () => {
|
|||
wrapper = mount(<App />);
|
||||
});
|
||||
|
||||
xtest('toggleLoginModal: should toggle the value in state', () => {
|
||||
test('toggleLoginModal: should toggle the value in state', () => {
|
||||
const { handleToggleLoginModal } = wrapper.instance();
|
||||
expect(wrapper.state().showLoginModal).toBeFalsy();
|
||||
handleToggleLoginModal();
|
||||
|
@ -46,7 +45,7 @@ describe('App', () => {
|
|||
expect(wrapper.state('error')).toEqual({});
|
||||
});
|
||||
|
||||
xtest('isUserAlreadyLoggedIn: token already available in storage', async () => {
|
||||
test('isUserAlreadyLoggedIn: token already available in storage', async () => {
|
||||
|
||||
storage.setItem('username', 'verdaccio');
|
||||
storage.setItem('token', generateTokenWithTimeRange(24));
|
||||
|
@ -57,7 +56,7 @@ describe('App', () => {
|
|||
expect(wrapper.state('user').username).toEqual('verdaccio');
|
||||
});
|
||||
|
||||
xtest('handleLogout - logouts the user and clear localstorage', async () => {
|
||||
test('handleLogout - logouts the user and clear localstorage', async () => {
|
||||
const { handleLogout } = wrapper.instance();
|
||||
storage.setItem('username', 'verdaccio');
|
||||
storage.setItem('token', 'xxxx.TOKEN.xxxx');
|
||||
|
@ -67,7 +66,7 @@ describe('App', () => {
|
|||
expect(wrapper.state('isUserLoggedIn')).toBeFalsy();
|
||||
});
|
||||
|
||||
xtest('handleDoLogin - login the user successfully', async () => {
|
||||
test('handleDoLogin - login the user successfully', async () => {
|
||||
const { handleDoLogin } = wrapper.instance();
|
||||
await handleDoLogin('sam', '1234');
|
||||
const result = {
|
||||
|
@ -81,10 +80,9 @@ describe('App', () => {
|
|||
expect(wrapper.state('user')).toEqual(result);
|
||||
});
|
||||
|
||||
xtest('handleDoLogin - authentication failure', async () => {
|
||||
test('handleDoLogin - authentication failure', async () => {
|
||||
const { handleDoLogin } = wrapper.instance();
|
||||
await handleDoLogin('sam', '12345');
|
||||
console.log(API_ERROR.BAD_USERNAME_PASSWORD);
|
||||
const result = {
|
||||
description: 'bad username/password, access denied',
|
||||
title: 'Unable to login',
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -21,7 +21,7 @@ describe('<PackageList /> component', () => {
|
|||
|
||||
});
|
||||
|
||||
xtest('should load the component with packages', () => {
|
||||
test('should load the component with packages', () => {
|
||||
const props = {
|
||||
packages: [
|
||||
{
|
||||
|
@ -29,20 +29,20 @@ describe('<PackageList /> component', () => {
|
|||
version: '1.0.0',
|
||||
time: new Date(1532211072138).getTime(),
|
||||
description: 'Private NPM repository',
|
||||
author: { name: 'Sam' }
|
||||
author: { name: 'Sam', avatar: 'test avatar' }
|
||||
},
|
||||
{
|
||||
name: 'abc',
|
||||
version: '1.0.1',
|
||||
time: new Date(1532211072138).getTime(),
|
||||
description: 'abc description',
|
||||
author: { name: 'Rose' }
|
||||
author: { name: 'Rose', avatar: 'test avatar' }
|
||||
},
|
||||
{
|
||||
name: 'xyz',
|
||||
version: '1.1.0',
|
||||
description: 'xyz description',
|
||||
author: { name: 'Martin' }
|
||||
author: { name: 'Martin', avatar: 'test avatar' }
|
||||
}
|
||||
],
|
||||
help: false
|
||||
|
|
|
@ -8,7 +8,8 @@ export const packageInformation = [
|
|||
homepage: 'https://jquery.com',
|
||||
author: {
|
||||
name: 'JS Foundation and other contributors',
|
||||
url: 'https://github.com/jquery/jquery/blob/master/AUTHORS.txt'
|
||||
url: 'https://github.com/jquery/jquery/blob/master/AUTHORS.txt',
|
||||
avatar: '',
|
||||
},
|
||||
repository: {
|
||||
type: 'git',
|
||||
|
@ -108,6 +109,11 @@ export const packageInformation = [
|
|||
license: 'MIT',
|
||||
private: true,
|
||||
main: 'lodash.js',
|
||||
author: {
|
||||
name: 'John david dalton',
|
||||
url: 'test url',
|
||||
avatar: 'test avatar',
|
||||
},
|
||||
engines: {
|
||||
node: '>=4.0.0'
|
||||
},
|
||||
|
|
|
@ -50,15 +50,15 @@ describe('formatDate', () => {
|
|||
});
|
||||
});
|
||||
|
||||
xdescribe('formatDateDistance', () => {
|
||||
describe('formatDateDistance', () => {
|
||||
test('should calculate the distance', () => {
|
||||
const dateOneMonthAgo = () => {
|
||||
const dateTwoMonthsAgo = () => {
|
||||
const date = new Date();
|
||||
date.setMonth(date.getMonth() - 1);
|
||||
date.setMonth(date.getMonth() - 2);
|
||||
return date;
|
||||
};
|
||||
const date = dateOneMonthAgo();
|
||||
expect(formatDateDistance(date)).toEqual('about 1 month');
|
||||
const date = dateTwoMonthsAgo();
|
||||
expect(formatDateDistance(date)).toEqual('about 2 months');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue