238 lines
7.6 KiB
JavaScript
238 lines
7.6 KiB
JavaScript
/**
|
|
* Copyright 2017 Red Hat Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
* not use this file except in compliance with the License. You may obtain
|
|
* a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
|
import { connect } from 'react-redux';
|
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
import Formsy from 'formsy-react';
|
|
import PropTypes from 'prop-types';
|
|
import React from 'react';
|
|
import ReactDOM from 'react-dom';
|
|
import { Redirect } from 'react-router-dom';
|
|
|
|
import FormErrorList from '../ui/forms/FormErrorList';
|
|
import { getCurrentLanguage, getEnabledLanguages } from '../../selectors/i18n';
|
|
import I18nActions from '../../actions/I18nActions';
|
|
import { GlobalLoader } from '../ui/Loader';
|
|
import LoginInput from '../ui/forms/LoginInput';
|
|
import LanguageInput from './LanguageInput';
|
|
import LoginActions from '../../actions/LoginActions';
|
|
|
|
import LogoSvg from '../../../img/logo.svg';
|
|
import TripleoOwlSvg from '../../../img/tripleo-owl.svg';
|
|
|
|
const messages = defineMessages({
|
|
authenticating: {
|
|
id: 'UserAuthenticator.authenticating',
|
|
defaultMessage: 'Authenticating...'
|
|
},
|
|
username: {
|
|
id: 'Login.username',
|
|
defaultMessage: 'Username'
|
|
},
|
|
usernameRequired: {
|
|
id: 'Login.usernameRequired',
|
|
defaultMessage: 'Username is required.'
|
|
},
|
|
password: {
|
|
id: 'Login.password',
|
|
defaultMessage: 'Password'
|
|
},
|
|
passwordRequired: {
|
|
id: 'Login.passwordRequired',
|
|
defaultMessage: 'Password is required.'
|
|
},
|
|
login: {
|
|
id: 'Login.login',
|
|
defaultMessage: 'Log In'
|
|
},
|
|
welcome: {
|
|
id: 'Login.welcome',
|
|
defaultMessage: 'Welcome!'
|
|
},
|
|
description: {
|
|
id: 'Login.description',
|
|
defaultMessage:
|
|
'This tool will walk you through the process of configuring and ' +
|
|
'deploying an OpenStack environment.'
|
|
}
|
|
});
|
|
|
|
class Login extends React.Component {
|
|
constructor() {
|
|
super();
|
|
this.state = {
|
|
canSubmit: false
|
|
};
|
|
}
|
|
componentWillMount() {
|
|
ReactDOM.findDOMNode(document.documentElement).className = 'login-pf';
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
if (!this.props.isAuthenticated || this.props.isAuthenticating) {
|
|
this.invalidateLoginForm(this.props.formFieldErrors.toJS());
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
ReactDOM.findDOMNode(document.documentElement).className = '';
|
|
}
|
|
|
|
invalidateLoginForm(formFieldErrors) {
|
|
this.refs.form.updateInputsWithError(formFieldErrors);
|
|
}
|
|
|
|
_enableButton() {
|
|
this.setState({ canSubmit: true });
|
|
}
|
|
|
|
_disableButton() {
|
|
this.setState({ canSubmit: false });
|
|
}
|
|
|
|
handleLogin(formData, resetForm, invalidateForm) {
|
|
const formFields = Object.keys(this.refs.form.inputs);
|
|
this.props.authenticateUser(formData, formFields);
|
|
}
|
|
|
|
render() {
|
|
const { from } = this.props.location.state || { from: { pathname: '/' } };
|
|
const {
|
|
formErrors,
|
|
isAuthenticating,
|
|
isAuthenticated,
|
|
intl: { formatMessage }
|
|
} = this.props;
|
|
|
|
if (!isAuthenticated) {
|
|
return (
|
|
<div>
|
|
<span id="badge">
|
|
<img src={LogoSvg} alt="TripleO" />
|
|
</span>
|
|
<GlobalLoader
|
|
content={formatMessage(messages.authenticating)}
|
|
loaded={!isAuthenticating}
|
|
/>
|
|
<div className="container">
|
|
<div className="row">
|
|
<div className="col-sm-12">
|
|
<div id="brand">
|
|
<img src={TripleoOwlSvg} alt="TripleO" />
|
|
</div>
|
|
</div>
|
|
<div className="col-sm-7 col-md-6 col-lg-5 login">
|
|
<FormErrorList errors={formErrors.toJS()} />
|
|
<Formsy.Form
|
|
ref="form"
|
|
role="form"
|
|
className="form-horizontal"
|
|
onSubmit={this.handleLogin.bind(this)}
|
|
onValid={this._enableButton.bind(this)}
|
|
onInvalid={this._disableButton.bind(this)}
|
|
>
|
|
<LanguageInput
|
|
name="language"
|
|
chooseLanguage={this.props.chooseLanguage}
|
|
language={this.props.language}
|
|
languages={this.props.languages}
|
|
/>
|
|
<LoginInput
|
|
name="username"
|
|
placeholder={formatMessage(messages.username)}
|
|
title={formatMessage(messages.username)}
|
|
validationError={formatMessage(messages.usernameRequired)}
|
|
required
|
|
autoFocus
|
|
/>
|
|
<LoginInput
|
|
type="password"
|
|
name="password"
|
|
placeholder={formatMessage(messages.password)}
|
|
title={formatMessage(messages.password)}
|
|
validationError={formatMessage(messages.passwordRequired)}
|
|
required
|
|
/>
|
|
<div className="form-group">
|
|
<div className="col-xs-offset-8 col-xs-4 col-sm-4 col-md-4 submit">
|
|
<button
|
|
type="submit"
|
|
disabled={!this.state.canSubmit || isAuthenticating}
|
|
className="btn btn-primary btn-lg"
|
|
tabIndex="4"
|
|
id="Login__loginButton"
|
|
>
|
|
<FormattedMessage {...messages.login} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</Formsy.Form>
|
|
</div>
|
|
<div className="col-sm-5 col-md-6 col-lg-7 details">
|
|
<p>
|
|
<strong>
|
|
<FormattedMessage {...messages.welcome} />
|
|
</strong>
|
|
<br />
|
|
<FormattedMessage {...messages.description} />
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} else {
|
|
return <Redirect to={from} />;
|
|
}
|
|
}
|
|
}
|
|
Login.propTypes = {
|
|
authenticateUser: PropTypes.func.isRequired,
|
|
chooseLanguage: PropTypes.func.isRequired,
|
|
formErrors: ImmutablePropTypes.list.isRequired,
|
|
formFieldErrors: ImmutablePropTypes.map.isRequired,
|
|
intl: PropTypes.object,
|
|
isAuthenticated: PropTypes.bool.isRequired,
|
|
isAuthenticating: PropTypes.bool.isRequired,
|
|
language: PropTypes.string,
|
|
languages: ImmutablePropTypes.map.isRequired,
|
|
location: PropTypes.object,
|
|
userLoggedIn: PropTypes.bool.isRequired
|
|
};
|
|
|
|
function mapStateToProps(state) {
|
|
return {
|
|
formErrors: state.login.getIn(['loginForm', 'formErrors']),
|
|
formFieldErrors: state.login.getIn(['loginForm', 'formFieldErrors']),
|
|
isAuthenticated: state.login.isAuthenticated,
|
|
isAuthenticating: state.login.get('isAuthenticating'),
|
|
language: getCurrentLanguage(state),
|
|
languages: getEnabledLanguages(state),
|
|
userLoggedIn: state.login.hasIn(['keystoneAccess', 'user'])
|
|
};
|
|
}
|
|
|
|
const mapDispatchToProps = dispatch => {
|
|
return {
|
|
chooseLanguage: language => dispatch(I18nActions.chooseLanguage(language)),
|
|
authenticateUser: (formData, formFields, nextPath) =>
|
|
dispatch(LoginActions.authenticateUser(formData, formFields, nextPath))
|
|
};
|
|
};
|
|
|
|
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Login));
|