mirror of
https://github.com/verdaccio/verdaccio.git
synced 2025-03-04 02:02:39 -05:00
* feat: added material-ui refactor: replaced element-react by material-ui refactor: updated snapshots refactor: updated tests * fix: modified validation.WIP * refactor: modified tests.WIP * test(fix): unit test for login and validat ecredentials * chore(fix): e2e update css selectors * test(fix): replace Object.values by supported syntax on node6
This commit is contained in:
parent
ec186794c6
commit
3639557118
22 changed files with 707 additions and 242 deletions
|
@ -15,6 +15,8 @@
|
|||
"verdaccio": "./bin/verdaccio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "3.0.2",
|
||||
"@material-ui/icons": "2.0.3",
|
||||
"@verdaccio/file-locking": "0.0.7",
|
||||
"@verdaccio/local-storage": "1.2.0",
|
||||
"@verdaccio/streams": "1.0.0",
|
||||
|
@ -82,7 +84,6 @@
|
|||
"codecov": "3.0.4",
|
||||
"cross-env": "5.1.4",
|
||||
"css-loader": "0.28.10",
|
||||
"element-react": "1.4.8",
|
||||
"element-theme-default": "1.4.13",
|
||||
"enzyme": "3.3.0",
|
||||
"enzyme-adapter-react-16": "1.1.1",
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
import React, {Component} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import isNil from 'lodash/isNil';
|
||||
import 'element-theme-default';
|
||||
import {i18n} from 'element-react';
|
||||
import locale from 'element-react/src/locale/lang/en';
|
||||
|
||||
import storage from './utils/storage';
|
||||
import logo from './utils/logo';
|
||||
import {makeLogin, isTokenExpire} from './utils/login';
|
||||
import { makeLogin, isTokenExpire } from './utils/login';
|
||||
|
||||
import Header from './components/Header';
|
||||
import Footer from './components/Footer';
|
||||
import LoginModal from './components/Login';
|
||||
|
||||
i18n.use(locale);
|
||||
|
||||
import Route from './router';
|
||||
|
||||
import './styles/main.scss';
|
||||
|
@ -52,7 +48,7 @@ export default class App extends Component {
|
|||
this.handleLogout();
|
||||
} else {
|
||||
this.setState({
|
||||
user: {username, token},
|
||||
user: { username, token },
|
||||
isUserLoggedIn: true
|
||||
});
|
||||
}
|
||||
|
@ -60,7 +56,7 @@ export default class App extends Component {
|
|||
|
||||
async loadLogo() {
|
||||
const logoUrl = await logo();
|
||||
this.setState({logoUrl});
|
||||
this.setState({ logoUrl });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -79,7 +75,7 @@ export default class App extends Component {
|
|||
* Required by: <Header />
|
||||
*/
|
||||
async doLogin(usernameValue, passwordValue) {
|
||||
const {username, token, error} = await makeLogin(
|
||||
const { username, token, error } = await makeLogin(
|
||||
usernameValue,
|
||||
passwordValue
|
||||
);
|
||||
|
@ -152,12 +148,12 @@ export default class App extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {isUserLoggedIn} = this.state;
|
||||
const { isUserLoggedIn } = this.state;
|
||||
return (
|
||||
<div className="page-full-height">
|
||||
{this.renderHeader()}
|
||||
{this.renderLoginModal()}
|
||||
<Route isUserLoggedIn={isUserLoggedIn} />
|
||||
{this.renderHeader()}
|
||||
{this.renderLoginModal()}
|
||||
<Route isUserLoggedIn={isUserLoggedIn} />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Button} from 'element-react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import capitalize from 'lodash/capitalize';
|
||||
import {getRegistryURL} from '../../utils/url';
|
||||
import { getRegistryURL } from '../../utils/url';
|
||||
import classes from './header.scss';
|
||||
import './logo.png';
|
||||
|
||||
|
@ -10,8 +10,8 @@ const Header = ({
|
|||
logo = '',
|
||||
scope = '',
|
||||
username = '',
|
||||
handleLogout = () => {},
|
||||
toggleLoginModal = () => {}
|
||||
handleLogout = () => { },
|
||||
toggleLoginModal = () => { }
|
||||
}) => {
|
||||
const registryUrl = getRegistryURL();
|
||||
return (
|
||||
|
@ -37,20 +37,21 @@ const Header = ({
|
|||
</span>
|
||||
<Button
|
||||
className={`${classes.headerButton} header-button-logout`}
|
||||
type="danger"
|
||||
color="primary"
|
||||
onClick={handleLogout}
|
||||
>
|
||||
Logout
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<Button
|
||||
className={`${classes.headerButton} header-button-login`}
|
||||
onClick={toggleLoginModal}
|
||||
>
|
||||
Login
|
||||
<Button
|
||||
className={`${classes.headerButton} header-button-login`}
|
||||
color="primary"
|
||||
onClick={toggleLoginModal}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
import React, {Component, createRef} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Form, Button, Dialog, Input, Alert} from 'element-react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import SnackbarContent from '@material-ui/core/SnackbarContent';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import InputLabel from '@material-ui/core/InputLabel';
|
||||
import Input from '@material-ui/core/Input';
|
||||
import FormControl from '@material-ui/core/FormControl';
|
||||
import FormHelperText from '@material-ui/core/FormHelperText';
|
||||
|
||||
import classes from "./login.scss";
|
||||
|
||||
export default class LoginModal extends Component {
|
||||
static propTypes = {
|
||||
|
@ -15,141 +27,174 @@ export default class LoginModal extends Component {
|
|||
error: {},
|
||||
onCancel: () => {},
|
||||
onSubmit: () => {}
|
||||
};
|
||||
|
||||
state = {
|
||||
form: {
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
rules: {
|
||||
username: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input the username',
|
||||
trigger: 'change'
|
||||
}
|
||||
],
|
||||
password: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input the password',
|
||||
trigger: 'change'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.formRef = createRef();
|
||||
this.submitCredentials = this.submitCredentials.bind(this);
|
||||
this.setCredentials = this.setCredentials.bind(this);
|
||||
this.validateCredentials = this.validateCredentials.bind(this);
|
||||
this.state = {
|
||||
form: {
|
||||
username: {
|
||||
required: true,
|
||||
pristine: true,
|
||||
helperText: 'Field required',
|
||||
value: ''
|
||||
},
|
||||
password: {
|
||||
required: true,
|
||||
pristine: true,
|
||||
helperText: 'Field required',
|
||||
value: ''
|
||||
},
|
||||
},
|
||||
error: props.error
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* set login modal's username and password to current state
|
||||
* Required by: <LoginModal />
|
||||
* Required to login
|
||||
*/
|
||||
setCredentials(key, value) {
|
||||
this.setState(
|
||||
(prevState) => ({
|
||||
form: {...prevState.form, [key]: value}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the username and password field.
|
||||
*/
|
||||
handleReset() {
|
||||
this.formRef.current.resetFields();
|
||||
}
|
||||
|
||||
submitCredentials(event) {
|
||||
// prevents default submit behavior
|
||||
event.preventDefault();
|
||||
this.formRef.current.validate((valid) => {
|
||||
if (valid) {
|
||||
const {username, password} = this.state.form;
|
||||
this.props.onSubmit(username, password);
|
||||
this.setState({
|
||||
form: {username}
|
||||
});
|
||||
setCredentials(name, e) {
|
||||
this.setState({
|
||||
form: {
|
||||
...this.state.form,
|
||||
[name]: {
|
||||
...this.state.form[name],
|
||||
value: e.target.value,
|
||||
pristine: false
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
renderLoginError({type, title, description} = {}) {
|
||||
return type ? (
|
||||
<Alert
|
||||
title={title}
|
||||
type={type}
|
||||
description={description}
|
||||
showIcon={true}
|
||||
closable={false}
|
||||
style={{lineHeight: '10px'}}
|
||||
validateCredentials(event) {
|
||||
// prevents default submit behavior
|
||||
event.preventDefault();
|
||||
|
||||
this.setState({
|
||||
form: Object.keys(this.state.form).reduce((acc, key) => ({
|
||||
...acc,
|
||||
...{ [key]: {...this.state.form[key], pristine: false } }
|
||||
}), {})
|
||||
}, () => {
|
||||
if (!Object.keys(this.state.form).some(id => !this.state.form[id])) {
|
||||
this.submitCredentials();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async submitCredentials() {
|
||||
const { form: { username, password } } = this.state;
|
||||
await this.props.onSubmit(username.value, password.value);
|
||||
// let's wait for API response and then set
|
||||
// username and password filed to empty state
|
||||
this.setState({
|
||||
form: Object.keys(this.state.form).reduce((acc, key) => ({
|
||||
...acc,
|
||||
...{ [key]: {...this.state.form[key], value: "", pristine: true } }
|
||||
}), {})
|
||||
});
|
||||
}
|
||||
|
||||
renderLoginError({ type, title, description } = {}) {
|
||||
return type === 'error' && (
|
||||
<SnackbarContent
|
||||
className={classes.loginError}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<div
|
||||
id="client-snackbar"
|
||||
className={classes.loginErrorMsg}
|
||||
>
|
||||
<ErrorIcon className={classes.loginIcon} />
|
||||
<span>
|
||||
<div><strong>{title}</strong></div>
|
||||
<div>{description}</div>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {visibility, onCancel, error} = this.props;
|
||||
const {username, password} = this.state.form;
|
||||
const { visibility, onCancel, error } = this.props;
|
||||
const { form: { username, password } } = this.state;
|
||||
return (
|
||||
<div className="login-dialog">
|
||||
<div className="login">
|
||||
<Dialog
|
||||
title="Login"
|
||||
size="tiny"
|
||||
visible={visibility}
|
||||
onCancel={onCancel}
|
||||
onClose={onCancel}
|
||||
open={visibility}
|
||||
className="login-dialog"
|
||||
maxWidth="xs"
|
||||
aria-labelledby="login-dialog"
|
||||
fullWidth
|
||||
>
|
||||
<Dialog.Body>
|
||||
<Form
|
||||
className="login-form"
|
||||
ref={this.formRef}
|
||||
model={this.state.form}
|
||||
rules={this.state.rules}
|
||||
<DialogTitle id="login-dialog">Login</DialogTitle>
|
||||
<DialogContent>
|
||||
{this.renderLoginError(error)}
|
||||
<FormControl
|
||||
error={!username.value && !username.pristine}
|
||||
aria-describedby='username'
|
||||
required={username.required}
|
||||
fullWidth
|
||||
>
|
||||
<Form.Item>
|
||||
{this.renderLoginError(error)}
|
||||
</Form.Item>
|
||||
<Form.Item prop="username" labelPosition="top">
|
||||
<Input
|
||||
name="username"
|
||||
placeholder="Type your username"
|
||||
value={username}
|
||||
onChange={this.setCredentials.bind(this, 'username')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item prop="password">
|
||||
<Input
|
||||
name="password"
|
||||
type="password"
|
||||
placeholder="Type your password"
|
||||
value={password}
|
||||
onChange={this.setCredentials.bind(this, 'password')}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item style={{float: 'right'}}>
|
||||
<Button onClick={onCancel} className="cancel-login-button">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
nativeType="submit"
|
||||
className="login-button"
|
||||
onClick={this.submitCredentials}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Dialog.Body>
|
||||
<InputLabel htmlFor="username">Username</InputLabel>
|
||||
<Input
|
||||
id="username"
|
||||
value={username.value}
|
||||
onChange={this.setCredentials.bind(this, 'username')}
|
||||
placeholder="Your username"
|
||||
/>
|
||||
{!username.value && !username.pristine && (
|
||||
<FormHelperText id='username-error'>
|
||||
{username.helperText}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormControl
|
||||
error={!password.value && !password.pristine}
|
||||
aria-describedby='password'
|
||||
required={password.required}
|
||||
style={{ marginTop: '8px' }}
|
||||
fullWidth
|
||||
>
|
||||
<InputLabel htmlFor="password">Password</InputLabel>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
value={password.value}
|
||||
onChange={this.setCredentials.bind(this, 'password')}
|
||||
placeholder="Your strong password"
|
||||
/>
|
||||
{!password.value && !password.pristine && (
|
||||
<FormHelperText id='password-error'>
|
||||
{password.helperText}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
</DialogContent>
|
||||
<DialogActions className="dialog-footer">
|
||||
<Button
|
||||
onClick={onCancel}
|
||||
className="cancel-login-button"
|
||||
color="inherit"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
className="login-button"
|
||||
onClick={this.validateCredentials.bind(this)}
|
||||
color="inherit"
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
22
src/webui/components/Login/login.scss
Normal file
22
src/webui/components/Login/login.scss
Normal file
|
@ -0,0 +1,22 @@
|
|||
@import '../../styles/variables';
|
||||
|
||||
.loginDialog {
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.loginError {
|
||||
background-color: $red !important;
|
||||
min-width: inherit !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
|
||||
.loginErrorMsg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loginIcon {
|
||||
opacity: 0.9;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Tag} from 'element-react';
|
||||
import {Link} from 'react-router-dom';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {formatDateDistance} from '../../utils/package';
|
||||
import { formatDateDistance } from '../../utils/package';
|
||||
|
||||
import classes from './package.scss';
|
||||
|
||||
const Package = ({name, version, author, description, license, time, keywords}) => {
|
||||
const Package = ({ name, version, author, description, license, time, keywords }) => {
|
||||
return (<section className={classes.package}>
|
||||
<Link to={`detail/${name}`}>
|
||||
<div className={classes.header}>
|
||||
<div className={classes.title}>
|
||||
<h1>
|
||||
{name} <Tag type="gray">v{version}</Tag>
|
||||
{name} <Chip label={`v${version}`} />
|
||||
</h1>
|
||||
</div>
|
||||
<div role="author" className={classes.author}>
|
||||
{ author ? `By: ${author}`: ''}
|
||||
{author ? `By: ${author}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.footer}>
|
||||
|
@ -27,9 +27,11 @@ const Package = ({name, version, author, description, license, time, keywords})
|
|||
</div>
|
||||
<div className={classes.tags}>
|
||||
{keywords && keywords.map((keyword, index) => (
|
||||
<Tag key={index} type="gray">
|
||||
{keyword}
|
||||
</Tag>
|
||||
<Chip
|
||||
key={index}
|
||||
label={keyword}
|
||||
className={classes.tag}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className={classes.details}>
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
.tag {
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React, {Component} from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Loading} from 'element-react';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import PackageDetail from '../../components/PackageDetail';
|
||||
|
@ -10,8 +10,6 @@ import API from '../../utils/api';
|
|||
import classes from './detail.scss';
|
||||
import PackageSidebar from '../../components/PackageSidebar/index';
|
||||
|
||||
const loadingMessage = 'Loading...';
|
||||
|
||||
export default class Detail extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
|
@ -66,12 +64,12 @@ export default class Detail extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {notFound, readMe} = this.state;
|
||||
const { notFound, readMe } = this.state;
|
||||
|
||||
if (notFound) {
|
||||
return <NotFound pkg={this.packageName} />;
|
||||
} else if (isEmpty(readMe)) {
|
||||
return <Loading text={loadingMessage} />;
|
||||
return <CircularProgress size={50} />;
|
||||
}
|
||||
return (
|
||||
<div className={classes.twoColumn}>
|
||||
|
|
16
src/webui/modules/home/home.scss
Normal file
16
src/webui/modules/home/home.scss
Normal file
|
@ -0,0 +1,16 @@
|
|||
@import '../../styles/variables';
|
||||
|
||||
.alertError {
|
||||
background-color: $red !important;
|
||||
min-width: inherit !important;
|
||||
}
|
||||
|
||||
.alertErrorMsg {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.alertIcon {
|
||||
opacity: 0.9;
|
||||
margin-right: 8px;
|
||||
}
|
|
@ -1,6 +1,13 @@
|
|||
import React, {Component, Fragment} from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Loading, MessageBox} from 'element-react';
|
||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
import DialogContent from '@material-ui/core/DialogContent';
|
||||
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||
import SnackbarContent from '@material-ui/core/SnackbarContent';
|
||||
import ErrorIcon from '@material-ui/icons/Error';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
|
@ -9,13 +16,20 @@ import API from '../../utils/api';
|
|||
import PackageList from '../../components/PackageList';
|
||||
import Search from '../../components/Search';
|
||||
|
||||
export default class Home extends Component {
|
||||
import classes from "./home.scss";
|
||||
|
||||
class Home extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.element,
|
||||
isUserLoggedIn: PropTypes.bool
|
||||
};
|
||||
|
||||
state = {
|
||||
showAlertDialog: false,
|
||||
alertDialogContent: {
|
||||
title: '',
|
||||
message: ''
|
||||
},
|
||||
loading: true,
|
||||
fistTime: true,
|
||||
query: ''
|
||||
|
@ -24,6 +38,8 @@ export default class Home extends Component {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
this.handleSearchInput = this.handleSearchInput.bind(this);
|
||||
this.handleShowAlertDialog = this.handleShowAlertDialog.bind(this);
|
||||
this.handleCloseAlertDialog = this.handleCloseAlertDialog.bind(this);
|
||||
this.searchPackage = debounce(this.searchPackage, 800);
|
||||
}
|
||||
|
||||
|
@ -61,8 +77,7 @@ export default class Home extends Component {
|
|||
});
|
||||
}
|
||||
} catch (error) {
|
||||
MessageBox.msgbox({
|
||||
type: 'error',
|
||||
this.handleShowAlertDialog({
|
||||
title: 'Warning',
|
||||
message: `Unable to load package list: ${error.message}`
|
||||
});
|
||||
|
@ -82,14 +97,66 @@ export default class Home extends Component {
|
|||
});
|
||||
}
|
||||
} catch (err) {
|
||||
MessageBox.msgbox({
|
||||
type: 'error',
|
||||
this.handleShowAlertDialog({
|
||||
title: 'Warning',
|
||||
message: 'Unable to get search result, please try again later.'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renderAlertDialog() {
|
||||
return (
|
||||
<Dialog
|
||||
open={this.state.showAlertDialog}
|
||||
onClose={this.handleCloseAlertDialog}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{this.state.alertDialogContent.title}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<SnackbarContent
|
||||
className={classes.alertError}
|
||||
aria-describedby="client-snackbar"
|
||||
message={
|
||||
<div
|
||||
id="client-snackbar"
|
||||
className={classes.alertErrorMsg}
|
||||
>
|
||||
<ErrorIcon className={classes.alertIcon} />
|
||||
<span>
|
||||
{this.state.alertDialogContent.message}
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
onClick={this.handleCloseAlertDialog}
|
||||
color="primary"
|
||||
autoFocus
|
||||
>
|
||||
Ok
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
handleShowAlertDialog(content) {
|
||||
this.setState({
|
||||
showAlertDialog: true,
|
||||
alertDialogContent: content
|
||||
});
|
||||
};
|
||||
|
||||
handleCloseAlertDialog() {
|
||||
this.setState({
|
||||
showAlertDialog: false
|
||||
});
|
||||
};
|
||||
|
||||
handleSearchInput(e) {
|
||||
this.setState({
|
||||
query: e.target.value.trim()
|
||||
|
@ -101,15 +168,16 @@ export default class Home extends Component {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {packages, loading} = this.state;
|
||||
const { packages, loading } = this.state;
|
||||
return (
|
||||
<Fragment>
|
||||
{this.renderSearchBar()}
|
||||
{loading ? (
|
||||
<Loading text="Loading..." />
|
||||
<CircularProgress size={50} />
|
||||
) : (
|
||||
<PackageList help={isEmpty(packages) === true} packages={packages} />
|
||||
)}
|
||||
<PackageList help={isEmpty(packages) === true} packages={packages} />
|
||||
)}
|
||||
{this.renderAlertDialog()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
@ -121,3 +189,5 @@ export default class Home extends Component {
|
|||
return <Search handleSearchInput={this.handleSearchInput} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default Home;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
$black: #000;
|
||||
$white: #fff;
|
||||
$red: #d32f2f;
|
||||
$grey: #808080;
|
||||
$grey-light: #d3d3d3;
|
||||
$grey-dark: #a9a9a9;
|
||||
|
|
|
@ -1,16 +1,25 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<link rel="icon" type="image/png" href="<%= htmlWebpackPlugin.options.verdaccioURL %>/-/static/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>
|
||||
<%= htmlWebpackPlugin.options.title %>
|
||||
</title>
|
||||
<link rel="icon" type="image/png" href="<%= htmlWebpackPlugin.options.verdaccioURL %>/-/static/favicon.ico" />
|
||||
<!-- Robot Font -->
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" />
|
||||
<!-- Material Icons Font -->
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<script>
|
||||
window.VERDACCIO_API_URL = '<%= htmlWebpackPlugin.options.verdaccioURL %>/-/verdaccio/';
|
||||
window.VERDACCIO_SCOPE = '<%= htmlWebpackPlugin.options.scope %>';
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="body">
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -25,10 +25,10 @@ describe('/ (Verdaccio Page)', () => {
|
|||
await clickElement('header button');
|
||||
await page.waitFor(500);
|
||||
// we fill the sign in form
|
||||
const signInDialog = await page.$('.el-dialog');
|
||||
const userInput = await signInDialog.$('input[type=text]');
|
||||
const signInDialog = await page.$('.login-dialog');
|
||||
const userInput = await signInDialog.$('#username');
|
||||
expect(userInput).not.toBeNull();
|
||||
const passInput = await signInDialog.$('input[type=password]');
|
||||
const passInput = await signInDialog.$('#password');
|
||||
expect(passInput).not.toBeNull();
|
||||
await userInput.type('test', {delay: 100});
|
||||
await passInput.type('test', {delay: 100});
|
||||
|
@ -86,7 +86,7 @@ describe('/ (Verdaccio Page)', () => {
|
|||
it('should click on sign in button', async () => {
|
||||
const signInButton = await page.$('header button');
|
||||
await signInButton.click();
|
||||
const signInDialog = await page.$('.login-dialog .el-dialog__wrapper');
|
||||
const signInDialog = await page.$('#login-dialog');
|
||||
|
||||
expect(signInDialog).not.toBeNull();
|
||||
})
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('basic system test', () => {
|
|||
url: 'http://localhost:' + port + '/',
|
||||
}, function(err, res, body) {
|
||||
expect(err).toBeNull();
|
||||
expect(body).toMatch(/<title>Verdaccio<\/title>/);
|
||||
expect(body).toMatch(/Verdaccio/);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,7 @@ 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';
|
||||
import { generateTokenWithTimeRange } from './components/__mocks__/token';
|
||||
|
||||
jest.mock('../../../src/webui/utils/storage', () => {
|
||||
class LocalStorageMock {
|
||||
|
@ -29,8 +29,6 @@ jest.mock('../../../src/webui/utils/storage', () => {
|
|||
|
||||
jest.mock('element-theme-default', () => ({}));
|
||||
|
||||
jest.mock('element-react/src/locale/lang/en', () => ({}));
|
||||
|
||||
jest.mock('../../../src/webui/utils/api', () => ({
|
||||
request: require('./components/__mocks__/api').default.request
|
||||
}));
|
||||
|
@ -58,7 +56,7 @@ describe('App', () => {
|
|||
});
|
||||
|
||||
it('isUserAlreadyLoggedIn: token already available in storage', async () => {
|
||||
|
||||
|
||||
storage.setItem('username', 'verdaccio');
|
||||
storage.setItem('token', generateTokenWithTimeRange(24));
|
||||
const { isUserAlreadyLoggedIn } = wrapper.instance();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Header /> component shallow should load header component in login state 1`] = `"<header class=\\"header\\"><div class=\\"headerWrap\\"><a href=\\"/#/\\"><img src=\\"logo.png\\" class=\\"logo\\"/></a><figure>npm set scope:registry http://localhost<br/>npm adduser --registry http://localhost</figure><div class=\\"headerRight\\"><div class=\\"user-logged\\"><span class=\\"user-logged-greetings usernameField\\">Hi, Verdaccio</span><button class=\\"el-button el-button--danger headerButton header-button-logout\\" type=\\"button\\"><span>Logout</span></button></div></div></div></header>"`;
|
||||
exports[`<Header /> component shallow should load header component in login state 1`] = `"<header class=\\"header\\"><div class=\\"headerWrap\\"><a href=\\"/#/\\"><img src=\\"logo.png\\" class=\\"logo\\"/></a><figure>npm set scope:registry http://localhost<br/>npm adduser --registry http://localhost</figure><div class=\\"headerRight\\"><div class=\\"user-logged\\"><span class=\\"user-logged-greetings usernameField\\">Hi, Verdaccio</span><button tabindex=\\"0\\" class=\\"MuiButtonBase-root-27 MuiButton-root-1 MuiButton-text-3 MuiButton-textPrimary-4 MuiButton-flat-6 MuiButton-flatPrimary-7 headerButton header-button-logout\\" type=\\"button\\"><span class=\\"MuiButton-label-2\\">Logout</span><span class=\\"MuiTouchRipple-root-30\\"></span></button></div></div></div></header>"`;
|
||||
|
||||
exports[`<Header /> component shallow should load header component in logout state 1`] = `"<header class=\\"header\\"><div class=\\"headerWrap\\"><a href=\\"/#/\\"><img src=\\"logo.png\\" class=\\"logo\\"/></a><figure>npm set scope:registry http://localhost<br/>npm adduser --registry http://localhost</figure><div class=\\"headerRight\\"><button class=\\"el-button el-button--default headerButton header-button-login\\" type=\\"button\\"><span>Login</span></button></div></div></header>"`;
|
||||
exports[`<Header /> component shallow should load header component in logout state 1`] = `"<header class=\\"header\\"><div class=\\"headerWrap\\"><a href=\\"/#/\\"><img src=\\"logo.png\\" class=\\"logo\\"/></a><figure>npm set scope:registry http://localhost<br/>npm adduser --registry http://localhost</figure><div class=\\"headerRight\\"><button tabindex=\\"0\\" class=\\"MuiButtonBase-root-27 MuiButton-root-1 MuiButton-text-3 MuiButton-textPrimary-4 MuiButton-flat-6 MuiButton-flatPrimary-7 headerButton header-button-login\\" type=\\"button\\"><span class=\\"MuiButton-label-2\\">Login</span><span class=\\"MuiTouchRipple-root-30\\"></span></button></div></div></header>"`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<LoginModal /> should load the component in default state 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><div class=\\"el-dialog__body\\"><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Type your username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div style=\\"float: right;\\" class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></div></form></div></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
exports[`<LoginModal /> should load the component in default state 1`] = `"<div class=\\"login\\"></div>"`;
|
||||
|
||||
exports[`<LoginModal /> should load the component with props 1`] = `"<div class=\\"login-dialog\\"><div><div style=\\"z-index: 1013;\\" class=\\"el-dialog__wrapper\\"><div style=\\"top: 15%;\\" class=\\"el-dialog el-dialog--tiny\\"><div class=\\"el-dialog__header\\"><span class=\\"el-dialog__title\\">Login</span><button type=\\"button\\" class=\\"el-dialog__headerbtn\\"><i class=\\"el-dialog__close el-icon el-icon-close\\"></i></button></div><div class=\\"el-dialog__body\\"><form class=\\"el-form el-form--label-right login-form\\"><div class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><div style=\\"line-height: 10px;\\" class=\\"el-alert el-alert--error\\"><i class=\\"el-alert__icon el-icon-circle-cross is-big\\"></i><div class=\\"el-alert__content\\"><span class=\\"el-alert__title is-bold\\">Error Title</span><p class=\\"el-alert__description\\">Error Description</p><i class=\\"el-alert__closebtn el-icon-close\\" style=\\"display: none;\\"></i></div></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"username\\" placeholder=\\"Type your username\\" type=\\"text\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div class=\\"el-form-item is-required\\"><div class=\\"el-form-item__content\\"><div class=\\"el-input\\"><input name=\\"password\\" placeholder=\\"Type your password\\" type=\\"password\\" class=\\"el-input__inner\\" autocomplete=\\"off\\" value=\\"\\"></div></div></div><div style=\\"float: right;\\" class=\\"el-form-item\\"><div class=\\"el-form-item__content\\"><button class=\\"el-button el-button--default cancel-login-button\\" type=\\"button\\"><span>Cancel</span></button><button class=\\"el-button el-button--default login-button\\" type=\\"submit\\"><span>Login</span></button></div></div></form></div></div></div><div class=\\"v-modal\\" style=\\"z-index: 1012;\\"></div></div></div>"`;
|
||||
exports[`<LoginModal /> should load the component with props 1`] = `"<div class=\\"login\\"></div>"`;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Package /> component should load the component 1`] = `"<section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <span class=\\"el-tag el-tag--gray\\">v1.0.0</span></h1></div><div role=\\"author\\" class=\\"author\\">By: Sam</div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published about 1 month ago</div><div class=\\"license\\">MIT</div></div></a></section>"`;
|
||||
exports[`<Package /> component should load the component 1`] = `"<section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <div role=\\"button\\" class=\\"MuiChip-root-1\\" tabindex=\\"-1\\"><span class=\\"MuiChip-label-17\\">v1.0.0</span></div></h1></div><div role=\\"author\\" class=\\"author\\">By: Sam</div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published about 1 month ago</div><div class=\\"license\\">MIT</div></div></a></section>"`;
|
||||
|
||||
exports[`<Package /> component should load the component without author 1`] = `"<section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <span class=\\"el-tag el-tag--gray\\">v1.0.0</span></h1></div><div role=\\"author\\" class=\\"author\\"></div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published about 1 month ago</div><div class=\\"license\\">MIT</div></div></a></section>"`;
|
||||
exports[`<Package /> component should load the component without author 1`] = `"<section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <div role=\\"button\\" class=\\"MuiChip-root-1\\" tabindex=\\"-1\\"><span class=\\"MuiChip-label-17\\">v1.0.0</span></div></h1></div><div role=\\"author\\" class=\\"author\\"></div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published about 1 month ago</div><div class=\\"license\\">MIT</div></div></a></section>"`;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<PackageList /> component should load the component with packages 1`] = `"<div class=\\"package-list-items\\"><div class=\\"pkgContainer\\"><h1 class=\\"listTitle\\">Available Packages</h1><li><section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <span class=\\"el-tag el-tag--gray\\">v1.0.0</span></h1></div><div role=\\"author\\" class=\\"author\\">By: Sam</div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published less than a minute ago</div><div class=\\"license\\"></div></div></a></section></li><li><section class=\\"package\\"><a href=\\"detail/abc\\"><div class=\\"header\\"><div class=\\"title\\"><h1>abc <span class=\\"el-tag el-tag--gray\\">v1.0.1</span></h1></div><div role=\\"author\\" class=\\"author\\">By: Rose</div></div><div class=\\"footer\\"><p class=\\"description\\">abc description</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published less than a minute ago</div><div class=\\"license\\"></div></div></a></section></li><li><section class=\\"package\\"><a href=\\"detail/xyz\\"><div class=\\"header\\"><div class=\\"title\\"><h1>xyz <span class=\\"el-tag el-tag--gray\\">v1.1.0</span></h1></div><div role=\\"author\\" class=\\"author\\">By: Martin</div></div><div class=\\"footer\\"><p class=\\"description\\">xyz description</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\"></div><div class=\\"license\\"></div></div></a></section></li></div></div>"`;
|
||||
exports[`<PackageList /> component should load the component with packages 1`] = `"<div class=\\"package-list-items\\"><div class=\\"pkgContainer\\"><h1 class=\\"listTitle\\">Available Packages</h1><li><section class=\\"package\\"><a href=\\"detail/verdaccio\\"><div class=\\"header\\"><div class=\\"title\\"><h1>verdaccio <div role=\\"button\\" class=\\"MuiChip-root-1\\" tabindex=\\"-1\\"><span class=\\"MuiChip-label-17\\">v1.0.0</span></div></h1></div><div role=\\"author\\" class=\\"author\\">By: Sam</div></div><div class=\\"footer\\"><p class=\\"description\\">Private NPM repository</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published less than a minute ago</div><div class=\\"license\\"></div></div></a></section></li><li><section class=\\"package\\"><a href=\\"detail/abc\\"><div class=\\"header\\"><div class=\\"title\\"><h1>abc <div role=\\"button\\" class=\\"MuiChip-root-1\\" tabindex=\\"-1\\"><span class=\\"MuiChip-label-17\\">v1.0.1</span></div></h1></div><div role=\\"author\\" class=\\"author\\">By: Rose</div></div><div class=\\"footer\\"><p class=\\"description\\">abc description</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\">Published less than a minute ago</div><div class=\\"license\\"></div></div></a></section></li><li><section class=\\"package\\"><a href=\\"detail/xyz\\"><div class=\\"header\\"><div class=\\"title\\"><h1>xyz <div role=\\"button\\" class=\\"MuiChip-root-1\\" tabindex=\\"-1\\"><span class=\\"MuiChip-label-17\\">v1.1.0</span></div></h1></div><div role=\\"author\\" class=\\"author\\">By: Martin</div></div><div class=\\"footer\\"><p class=\\"description\\">xyz description</p></div><div class=\\"tags\\"></div><div class=\\"details\\"><div class=\\"homepage\\"></div><div class=\\"license\\"></div></div></a></section></li></div></div>"`;
|
||||
|
|
|
@ -2,6 +2,22 @@ import React from 'react';
|
|||
import { mount } from 'enzyme';
|
||||
import LoginModal from '../../../../src/webui/components/Login';
|
||||
|
||||
const eventUsername = {
|
||||
target: {
|
||||
value: 'xyz'
|
||||
}
|
||||
}
|
||||
|
||||
const eventPassword = {
|
||||
target: {
|
||||
value: '1234'
|
||||
}
|
||||
}
|
||||
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
|
||||
describe('<LoginModal />', () => {
|
||||
it('should load the component in default state', () => {
|
||||
const wrapper = mount(<LoginModal />);
|
||||
|
@ -16,8 +32,8 @@ describe('<LoginModal />', () => {
|
|||
title: 'Error Title',
|
||||
description: 'Error Description'
|
||||
},
|
||||
onCancel: () => {},
|
||||
onSubmit: () => {}
|
||||
onCancel: () => { },
|
||||
onSubmit: () => { }
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
|
@ -32,12 +48,12 @@ describe('<LoginModal />', () => {
|
|||
description: 'Error Description'
|
||||
},
|
||||
onCancel: jest.fn(),
|
||||
onSubmit: () => {}
|
||||
onSubmit: () => { }
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
wrapper.find('button.cancel-login-button').simulate('click');
|
||||
wrapper.find('.dialog-footer > .cancel-login-button').simulate('click');
|
||||
expect(props.onCancel).toHaveBeenCalled();
|
||||
wrapper.find('.el-dialog__headerbtn > .el-dialog__close').simulate('click');
|
||||
wrapper.find('.dialog-footer > .login-button').simulate('click');
|
||||
expect(props.onCancel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -51,14 +67,14 @@ describe('<LoginModal />', () => {
|
|||
const wrapper = mount(<LoginModal {...props} />);
|
||||
const { setCredentials } = wrapper.instance();
|
||||
|
||||
expect(setCredentials('username', 'xyz')).toBeUndefined();
|
||||
expect(wrapper.state('form').username).toEqual('xyz');
|
||||
expect(setCredentials('username', eventUsername)).toBeUndefined();
|
||||
expect(wrapper.state('form').username.value).toEqual('xyz');
|
||||
|
||||
expect(setCredentials('password', '1234')).toBeUndefined();
|
||||
expect(wrapper.state('form').password).toEqual('1234');
|
||||
expect(setCredentials('password', eventPassword)).toBeUndefined();
|
||||
expect(wrapper.state('form').password.value).toEqual('1234');
|
||||
});
|
||||
|
||||
it('submitCredential: should call the onSubmit', () => {
|
||||
it('validateCredentials: should validate credentials', async () => {
|
||||
const props = {
|
||||
visibility: true,
|
||||
error: {},
|
||||
|
@ -66,19 +82,46 @@ describe('<LoginModal />', () => {
|
|||
onSubmit: jest.fn()
|
||||
};
|
||||
|
||||
const event = {
|
||||
preventDefault: jest.fn()
|
||||
};
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
const { submitCredentials } = wrapper.instance();
|
||||
wrapper
|
||||
.find('input[type="text"]')
|
||||
.simulate('change', { target: { value: 'sam' } });
|
||||
wrapper
|
||||
.find('input[type="password"]')
|
||||
.simulate('change', { target: { value: '1234' } });
|
||||
submitCredentials(event);
|
||||
const instance = wrapper.instance();
|
||||
|
||||
instance.submitCredentials = jest.fn();
|
||||
const { validateCredentials, setCredentials, submitCredentials } = instance;
|
||||
|
||||
expect(setCredentials('username', eventUsername)).toBeUndefined();
|
||||
expect(wrapper.state('form').username.value).toEqual('xyz');
|
||||
|
||||
expect(setCredentials('password', eventPassword)).toBeUndefined();
|
||||
expect(wrapper.state('form').password.value).toEqual('1234');
|
||||
|
||||
validateCredentials(event);
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
expect(props.onSubmit).toHaveBeenCalledWith('sam', '1234');
|
||||
expect(wrapper.state('form').username.pristine).toEqual(false);
|
||||
expect(wrapper.state('form').password.pristine).toEqual(false);
|
||||
|
||||
expect(submitCredentials).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
|
||||
it('submitCredentials: should submit credentials', async () => {
|
||||
const props = {
|
||||
onSubmit: jest.fn()
|
||||
};
|
||||
|
||||
const wrapper = mount(<LoginModal {...props} />);
|
||||
const { setCredentials, submitCredentials } = wrapper.instance();
|
||||
expect(setCredentials('username', eventUsername)).toBeUndefined();
|
||||
expect(wrapper.state('form').username.value).toEqual('xyz');
|
||||
|
||||
expect(setCredentials('password', eventPassword)).toBeUndefined();
|
||||
expect(wrapper.state('form').password.value).toEqual('1234');
|
||||
|
||||
await submitCredentials();
|
||||
expect(props.onSubmit).toHaveBeenCalledWith('xyz', '1234');
|
||||
expect(wrapper.state('form').username.value).toEqual('');
|
||||
expect(wrapper.state('form').username.pristine).toEqual(true);
|
||||
expect(wrapper.state('form').password.value).toEqual('');
|
||||
expect(wrapper.state('form').password.pristine).toEqual(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ import React from 'react';
|
|||
import { mount } from 'enzyme';
|
||||
import Package from '../../../../src/webui/components/Package/index';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import Chip from '@material-ui/core/Chip';
|
||||
|
||||
/**
|
||||
* Generates one month back date from current time
|
||||
|
@ -29,14 +30,17 @@ describe('<Package /> component', () => {
|
|||
};
|
||||
const wrapper = mount(
|
||||
<BrowserRouter>
|
||||
<Package {...props}/>
|
||||
<Package {...props} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
const version =
|
||||
wrapper.findWhere(node => node.is(Chip) && node.prop('label') === 'v1.0.0');
|
||||
|
||||
// integration expectations
|
||||
expect(wrapper.find('a').prop('href')).toEqual('detail/verdaccio');
|
||||
expect(wrapper.find('h1').text()).toEqual('verdaccio v1.0.0');
|
||||
expect(wrapper.find('.el-tag--gray').text()).toEqual('v1.0.0');
|
||||
expect(version.exists()).toBe(true);
|
||||
expect(
|
||||
wrapper.find('div').filterWhere(n => n.prop('role') === 'author')
|
||||
.text()
|
||||
|
@ -68,4 +72,3 @@ describe('<Package /> component', () => {
|
|||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
325
yarn.lock
325
yarn.lock
|
@ -60,6 +60,24 @@
|
|||
esutils "^2.0.2"
|
||||
js-tokens "^3.0.0"
|
||||
|
||||
"@babel/runtime@7.0.0", "@babel/runtime@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@7.0.0-beta.56":
|
||||
version "7.0.0-beta.56"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.56.tgz#cda612dffd5b1719a7b8e91e3040bd6ae64de8b0"
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/runtime@7.0.0-rc.1":
|
||||
version "7.0.0-rc.1"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-rc.1.tgz#42f36fc5817911c89ea75da2b874054922967616"
|
||||
dependencies:
|
||||
regenerator-runtime "^0.12.0"
|
||||
|
||||
"@babel/template@7.0.0-beta.44":
|
||||
version "7.0.0-beta.44"
|
||||
resolved "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f"
|
||||
|
@ -222,6 +240,45 @@
|
|||
mkdirp "^0.5.1"
|
||||
rimraf "^2.5.2"
|
||||
|
||||
"@material-ui/core@3.0.2":
|
||||
version "3.0.2"
|
||||
resolved "https://registry.npmjs.org/@material-ui/core/-/core-3.0.2.tgz#a86ec4526dd0648ee9da4fc4deabffc0276de5f0"
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0"
|
||||
"@types/jss" "^9.5.3"
|
||||
"@types/react-transition-group" "^2.0.8"
|
||||
brcast "^3.0.1"
|
||||
classnames "^2.2.5"
|
||||
csstype "^2.5.2"
|
||||
debounce "^1.1.0"
|
||||
deepmerge "^2.0.1"
|
||||
dom-helpers "^3.2.1"
|
||||
hoist-non-react-statics "^2.5.0"
|
||||
is-plain-object "^2.0.4"
|
||||
jss "^9.3.3"
|
||||
jss-camel-case "^6.0.0"
|
||||
jss-default-unit "^8.0.2"
|
||||
jss-global "^3.0.0"
|
||||
jss-nested "^6.0.1"
|
||||
jss-props-sort "^6.0.0"
|
||||
jss-vendor-prefixer "^7.0.0"
|
||||
keycode "^2.1.9"
|
||||
normalize-scroll-left "^0.1.2"
|
||||
popper.js "^1.14.1"
|
||||
prop-types "^15.6.0"
|
||||
react-event-listener "^0.6.2"
|
||||
react-jss "^8.1.0"
|
||||
react-transition-group "^2.2.1"
|
||||
recompose "^0.29.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
"@material-ui/icons@2.0.3":
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/@material-ui/icons/-/icons-2.0.3.tgz#d3da9d6e31b1adfbc48efe33c7cb75b32b784096"
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0-rc.1"
|
||||
recompose "^0.28.0"
|
||||
|
||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||
version "2.2.1"
|
||||
resolved "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||
|
@ -239,10 +296,36 @@
|
|||
dependencies:
|
||||
any-observable "^0.3.0"
|
||||
|
||||
"@types/jss@^9.5.3":
|
||||
version "9.5.4"
|
||||
resolved "https://registry.npmjs.org/@types/jss/-/jss-9.5.4.tgz#89a4ee32a14a8d2937187b1a7f443750e964a74d"
|
||||
dependencies:
|
||||
csstype "^2.0.0"
|
||||
indefinite-observable "^1.0.1"
|
||||
|
||||
"@types/node@*":
|
||||
version "10.5.4"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-10.5.4.tgz#6eccc158504357d1da91434d75e86acde94bb10b"
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.5.5"
|
||||
resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.5.tgz#17038dd322c2325f5da650a94d5f9974943625e3"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@^2.0.8":
|
||||
version "2.0.13"
|
||||
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-2.0.13.tgz#7769fb61eb71d64d087a713956f086a42c3ee171"
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
version "16.4.11"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-16.4.11.tgz#330f3d864300f71150dc2d125e48644c098f8770"
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
csstype "^2.2.0"
|
||||
|
||||
"@verdaccio/file-locking@0.0.7", "@verdaccio/file-locking@^0.0.7":
|
||||
version "0.0.7"
|
||||
resolved "https://registry.npmjs.org/@verdaccio/file-locking/-/file-locking-0.0.7.tgz#5fd1b2bd391e54fa32d079002b5f7ba90844e344"
|
||||
|
@ -719,12 +802,6 @@ async-limiter@~1.0.0:
|
|||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
|
||||
|
||||
async-validator@^1.8.1:
|
||||
version "1.8.5"
|
||||
resolved "https://registry.npmjs.org/async-validator/-/async-validator-1.8.5.tgz#dc3e08ec1fd0dddb67e60842f02c0cd1cec6d7f0"
|
||||
dependencies:
|
||||
babel-runtime "6.x"
|
||||
|
||||
async@2.6.1, async@^2.1.4, async@^2.5.0:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.npmjs.org/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
|
||||
|
@ -1518,7 +1595,7 @@ babel-register@6.26.0, babel-register@^6.26.0:
|
|||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.15"
|
||||
|
||||
babel-runtime@6.26.0, babel-runtime@6.x, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
babel-runtime@6.26.0, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
|
@ -1726,6 +1803,10 @@ braces@^2.3.0, braces@^2.3.1:
|
|||
split-string "^3.0.2"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
brcast@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/brcast/-/brcast-3.0.1.tgz#6256a8349b20de9eed44257a9b24d71493cd48dd"
|
||||
|
||||
brorand@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
|
||||
|
@ -2072,6 +2153,10 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
|
|||
strip-ansi "^3.0.0"
|
||||
supports-color "^2.0.0"
|
||||
|
||||
change-emitter@^0.1.2:
|
||||
version "0.1.6"
|
||||
resolved "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515"
|
||||
|
||||
character-entities-html4@^1.0.0:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.2.tgz#c44fdde3ce66b52e8d321d6c1bf46101f0150610"
|
||||
|
@ -2868,6 +2953,12 @@ css-url-regex@^1.1.0:
|
|||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz#83834230cc9f74c457de59eebd1543feeb83b7ec"
|
||||
|
||||
css-vendor@^0.3.8:
|
||||
version "0.3.8"
|
||||
resolved "https://registry.npmjs.org/css-vendor/-/css-vendor-0.3.8.tgz#6421cfd3034ce664fe7673972fd0119fc28941fa"
|
||||
dependencies:
|
||||
is-in-browser "^1.0.2"
|
||||
|
||||
css-what@2.1:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd"
|
||||
|
@ -2998,6 +3089,10 @@ cssstyle@^1.0.0:
|
|||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
csstype@^2.0.0, csstype@^2.2.0, csstype@^2.5.2:
|
||||
version "2.5.6"
|
||||
resolved "https://registry.npmjs.org/csstype/-/csstype-2.5.6.tgz#2ae1db2319642d8b80a668d2d025c6196071e788"
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
|
@ -3046,6 +3141,10 @@ dateformat@^3.0.0:
|
|||
version "3.0.3"
|
||||
resolved "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
|
||||
debounce@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131"
|
||||
|
||||
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
|
@ -3101,6 +3200,10 @@ deep-is@~0.1.3:
|
|||
version "0.1.3"
|
||||
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
|
||||
deepmerge@^2.0.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.1.tgz#e862b4e45ea0555072bf51e7fd0d9845170ae768"
|
||||
|
||||
default-require-extensions@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz#f5f8fbb18a7d6d50b21f641f649ebb522cfe24f7"
|
||||
|
@ -3268,6 +3371,10 @@ dom-converter@~0.1:
|
|||
dependencies:
|
||||
utila "~0.3"
|
||||
|
||||
dom-helpers@^3.2.1, dom-helpers@^3.3.1:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
|
||||
|
||||
dom-serializer@0, dom-serializer@~0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
||||
|
@ -3396,17 +3503,6 @@ elegant-spinner@^1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
|
||||
|
||||
element-react@1.4.8:
|
||||
version "1.4.8"
|
||||
resolved "https://registry.npmjs.org/element-react/-/element-react-1.4.8.tgz#15d0e27081edb2c85984665144cc8ab2d440e626"
|
||||
dependencies:
|
||||
async-validator "^1.8.1"
|
||||
classnames "^2.2.5"
|
||||
prop-types "^15.6.0"
|
||||
raf "^3.4.0"
|
||||
react-click-outside "^3.0.0"
|
||||
throttle-debounce "^1.0.1"
|
||||
|
||||
element-theme-default@1.4.13:
|
||||
version "1.4.13"
|
||||
resolved "https://registry.npmjs.org/element-theme-default/-/element-theme-default-1.4.13.tgz#70f9b754f9a1059d20c3225fe12eb55cc1e8abf9"
|
||||
|
@ -4038,7 +4134,7 @@ fb-watchman@^2.0.0:
|
|||
dependencies:
|
||||
bser "^2.0.0"
|
||||
|
||||
fbjs@^0.8.16:
|
||||
fbjs@^0.8.1, fbjs@^0.8.16:
|
||||
version "0.8.17"
|
||||
resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd"
|
||||
dependencies:
|
||||
|
@ -4757,7 +4853,7 @@ hoek@2.x.x:
|
|||
version "2.16.3"
|
||||
resolved "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed"
|
||||
|
||||
hoist-non-react-statics@^2.1.1, hoist-non-react-statics@^2.5.0:
|
||||
hoist-non-react-statics@^2.3.1, hoist-non-react-statics@^2.5.0:
|
||||
version "2.5.5"
|
||||
resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
|
||||
|
||||
|
@ -4944,6 +5040,10 @@ husky@0.15.0-rc.8:
|
|||
run-node "^0.2.0"
|
||||
slash "^1.0.0"
|
||||
|
||||
hyphenate-style-name@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b"
|
||||
|
||||
iconv-lite@0.4.19:
|
||||
version "0.4.19"
|
||||
resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||
|
@ -5020,6 +5120,12 @@ in-publish@2.0.0, in-publish@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
|
||||
|
||||
indefinite-observable@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-1.0.1.tgz#09915423cc8d6f7eb1cb7882ad134633c9a6edc3"
|
||||
dependencies:
|
||||
symbol-observable "1.0.4"
|
||||
|
||||
indent-string@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
|
||||
|
@ -5285,6 +5391,10 @@ is-fullwidth-code-point@^2.0.0:
|
|||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
|
||||
|
||||
is-function@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
|
||||
|
||||
is-generator-fn@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a"
|
||||
|
@ -5311,6 +5421,10 @@ is-hexadecimal@^1.0.0:
|
|||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.2.tgz#b6e710d7d07bb66b98cb8cece5c9b4921deeb835"
|
||||
|
||||
is-in-browser@^1.0.2, is-in-browser@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
|
||||
|
||||
is-number-object@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799"
|
||||
|
@ -6010,6 +6124,81 @@ jsprim@^1.2.2:
|
|||
json-schema "0.2.3"
|
||||
verror "1.10.0"
|
||||
|
||||
jss-camel-case@^6.0.0, jss-camel-case@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.npmjs.org/jss-camel-case/-/jss-camel-case-6.1.0.tgz#ccb1ff8d6c701c02a1fed6fb6fb6b7896e11ce44"
|
||||
dependencies:
|
||||
hyphenate-style-name "^1.0.2"
|
||||
|
||||
jss-compose@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.npmjs.org/jss-compose/-/jss-compose-5.0.0.tgz#ce01b2e4521d65c37ea42cf49116e5f7ab596484"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-default-unit@^8.0.2:
|
||||
version "8.0.2"
|
||||
resolved "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz#cc1e889bae4c0b9419327b314ab1c8e2826890e6"
|
||||
|
||||
jss-expand@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/jss-expand/-/jss-expand-5.3.0.tgz#02be076efe650125c842f5bb6fb68786fe441ed6"
|
||||
|
||||
jss-extend@^6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.npmjs.org/jss-extend/-/jss-extend-6.2.0.tgz#4af09d0b72fb98ee229970f8ca852fec1ca2a8dc"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-global@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.npmjs.org/jss-global/-/jss-global-3.0.0.tgz#e19e5c91ab2b96353c227e30aa2cbd938cdaafa2"
|
||||
|
||||
jss-nested@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.npmjs.org/jss-nested/-/jss-nested-6.0.1.tgz#ef992b79d6e8f63d939c4397b9d99b5cbbe824ca"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-preset-default@^4.3.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.npmjs.org/jss-preset-default/-/jss-preset-default-4.5.0.tgz#d3a457012ccd7a551312014e394c23c4b301cadd"
|
||||
dependencies:
|
||||
jss-camel-case "^6.1.0"
|
||||
jss-compose "^5.0.0"
|
||||
jss-default-unit "^8.0.2"
|
||||
jss-expand "^5.3.0"
|
||||
jss-extend "^6.2.0"
|
||||
jss-global "^3.0.0"
|
||||
jss-nested "^6.0.1"
|
||||
jss-props-sort "^6.0.0"
|
||||
jss-template "^1.0.1"
|
||||
jss-vendor-prefixer "^7.0.0"
|
||||
|
||||
jss-props-sort@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.npmjs.org/jss-props-sort/-/jss-props-sort-6.0.0.tgz#9105101a3b5071fab61e2d85ea74cc22e9b16323"
|
||||
|
||||
jss-template@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/jss-template/-/jss-template-1.0.1.tgz#09aed9d86cc547b07f53ef355d7e1777f7da430a"
|
||||
dependencies:
|
||||
warning "^3.0.0"
|
||||
|
||||
jss-vendor-prefixer@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.npmjs.org/jss-vendor-prefixer/-/jss-vendor-prefixer-7.0.0.tgz#0166729650015ef19d9f02437c73667231605c71"
|
||||
dependencies:
|
||||
css-vendor "^0.3.8"
|
||||
|
||||
jss@^9.3.3, jss@^9.7.0:
|
||||
version "9.8.7"
|
||||
resolved "https://registry.npmjs.org/jss/-/jss-9.8.7.tgz#ed9763fc0f2f0260fc8260dac657af61e622ce05"
|
||||
dependencies:
|
||||
is-in-browser "^1.1.3"
|
||||
symbol-observable "^1.1.0"
|
||||
warning "^3.0.0"
|
||||
|
||||
jsx-ast-utils@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f"
|
||||
|
@ -6031,6 +6220,10 @@ jws@^3.1.5:
|
|||
jwa "^1.1.5"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
keycode@^2.1.9:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz#3d0af56dc7b8b8e5cba8d0a97f107204eec22b04"
|
||||
|
||||
keygrip@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91"
|
||||
|
@ -6842,7 +7035,7 @@ mute-stream@0.0.7:
|
|||
version "0.0.7"
|
||||
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||
|
||||
mv@^2.1.1, mv@~2:
|
||||
mv@2.1.1, mv@~2:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
|
||||
dependencies:
|
||||
|
@ -7100,6 +7293,10 @@ normalize-range@^0.1.2:
|
|||
version "0.1.2"
|
||||
resolved "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
|
||||
|
||||
normalize-scroll-left@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.1.2.tgz#6b79691ba79eb5fb107fa5edfbdc06b55caee2aa"
|
||||
|
||||
normalize-selector@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03"
|
||||
|
@ -7655,6 +7852,10 @@ pn@^1.1.0:
|
|||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
|
||||
|
||||
popper.js@^1.14.1:
|
||||
version "1.14.4"
|
||||
resolved "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz#8eec1d8ff02a5a3a152dd43414a15c7b79fd69b6"
|
||||
|
||||
portfinder@^1.0.9:
|
||||
version "1.0.13"
|
||||
resolved "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9"
|
||||
|
@ -8326,7 +8527,7 @@ prop-types@15.6.1:
|
|||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
prop-types@^15.5.4, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
|
||||
prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2:
|
||||
version "15.6.2"
|
||||
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||
dependencies:
|
||||
|
@ -8529,12 +8730,6 @@ rc@^1.1.6, rc@^1.2.7:
|
|||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
react-click-outside@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.npmjs.org/react-click-outside/-/react-click-outside-3.0.1.tgz#6e77e84d2f17afaaac26dbad743cbbf909f5e24c"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^2.1.1"
|
||||
|
||||
react-dom@16.4.2:
|
||||
version "16.4.2"
|
||||
resolved "https://registry.npmjs.org/react-dom/-/react-dom-16.4.2.tgz#4afed569689f2c561d2b8da0b819669c38a0bda4"
|
||||
|
@ -8544,6 +8739,14 @@ react-dom@16.4.2:
|
|||
object-assign "^4.1.1"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-event-listener@^0.6.2:
|
||||
version "0.6.3"
|
||||
resolved "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.6.3.tgz#8eab88129a76e095ed8aa684c29679eded1e843d"
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0-rc.1"
|
||||
prop-types "^15.6.0"
|
||||
warning "^4.0.1"
|
||||
|
||||
react-hot-loader@4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.2.0.tgz#4a2ec79114f872e28ea786e04889d643ad3dfb7c"
|
||||
|
@ -8559,7 +8762,17 @@ react-is@^16.4.1:
|
|||
version "16.4.1"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-16.4.1.tgz#d624c4650d2c65dbd52c72622bbf389435d9776e"
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
react-jss@^8.1.0:
|
||||
version "8.6.1"
|
||||
resolved "https://registry.npmjs.org/react-jss/-/react-jss-8.6.1.tgz#a06e2e1d2c4d91b4d11befda865e6c07fbd75252"
|
||||
dependencies:
|
||||
hoist-non-react-statics "^2.5.0"
|
||||
jss "^9.7.0"
|
||||
jss-preset-default "^4.3.0"
|
||||
prop-types "^15.6.0"
|
||||
theming "^1.3.0"
|
||||
|
||||
react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
|
||||
|
@ -8612,6 +8825,15 @@ react-test-renderer@^16.0.0-0:
|
|||
prop-types "^15.6.0"
|
||||
react-is "^16.4.1"
|
||||
|
||||
react-transition-group@^2.2.1:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.4.0.tgz#1d9391fabfd82e016f26fabd1eec329dbd922b5a"
|
||||
dependencies:
|
||||
dom-helpers "^3.3.1"
|
||||
loose-envify "^1.3.1"
|
||||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react@16.4.2:
|
||||
version "16.4.2"
|
||||
resolved "https://registry.npmjs.org/react/-/react-16.4.2.tgz#2cd90154e3a9d9dd8da2991149fdca3c260e129f"
|
||||
|
@ -8702,6 +8924,28 @@ realpath-native@^1.0.0:
|
|||
dependencies:
|
||||
util.promisify "^1.0.0"
|
||||
|
||||
recompose@^0.28.0:
|
||||
version "0.28.2"
|
||||
resolved "https://registry.npmjs.org/recompose/-/recompose-0.28.2.tgz#19e679227bdf979e0d31b73ffe7ae38c9194f4a7"
|
||||
dependencies:
|
||||
"@babel/runtime" "7.0.0-beta.56"
|
||||
change-emitter "^0.1.2"
|
||||
fbjs "^0.8.1"
|
||||
hoist-non-react-statics "^2.3.1"
|
||||
react-lifecycles-compat "^3.0.2"
|
||||
symbol-observable "^1.0.4"
|
||||
|
||||
recompose@^0.29.0:
|
||||
version "0.29.0"
|
||||
resolved "https://registry.npmjs.org/recompose/-/recompose-0.29.0.tgz#f1a4e20d5f24d6ef1440f83924e821de0b1bccef"
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
change-emitter "^0.1.2"
|
||||
fbjs "^0.8.1"
|
||||
hoist-non-react-statics "^2.3.1"
|
||||
react-lifecycles-compat "^3.0.2"
|
||||
symbol-observable "^1.0.4"
|
||||
|
||||
redent@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
|
||||
|
@ -8749,6 +8993,10 @@ regenerator-runtime@^0.11.0:
|
|||
version "0.11.1"
|
||||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
|
||||
regenerator-runtime@^0.12.0:
|
||||
version "0.12.1"
|
||||
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
||||
|
||||
regenerator-transform@^0.10.0:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
|
||||
|
@ -9951,7 +10199,11 @@ symbol-observable@1.0.1:
|
|||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4"
|
||||
|
||||
symbol-observable@^1.1.0:
|
||||
symbol-observable@1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
|
||||
|
||||
symbol-observable@^1.0.4, symbol-observable@^1.1.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||
|
||||
|
@ -10033,14 +10285,19 @@ text-table@^0.2.0:
|
|||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
|
||||
|
||||
theming@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.npmjs.org/theming/-/theming-1.3.0.tgz#286d5bae80be890d0adc645e5ca0498723725bdc"
|
||||
dependencies:
|
||||
brcast "^3.0.1"
|
||||
is-function "^1.0.1"
|
||||
is-plain-object "^2.0.1"
|
||||
prop-types "^15.5.8"
|
||||
|
||||
throat@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a"
|
||||
|
||||
throttle-debounce@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-1.1.0.tgz#51853da37be68a155cb6e827b3514a3c422e89cd"
|
||||
|
||||
through2@^2.0.0, through2@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be"
|
||||
|
|
Loading…
Add table
Reference in a new issue