From 3c28d365ae2033363fc3a28f718a56c902dc7ba4 Mon Sep 17 00:00:00 2001 From: nozalr Date: Sun, 22 Dec 2019 19:03:46 +0100 Subject: [PATCH 01/38] Bugfix in Routes when setting the component. There were errors in Routes like this: Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`. in Route (created by AppView) in AppView (created by Context.Consumer) in Connect(AppView) (created by Route) in Route (created by Routes) in Switch (created by Routes) in Routes in Router (created by HashRouter) in HashRouter in Provider in ThemeProvider Bugfixed doing what is said here: https://github.com/ReactTraining/react-router/issues/6471 --- render/App.jsx | 4 ++-- render/components/__tests__/Navbar.spec.jsx | 4 ++-- render/views/AppView.jsx | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/render/App.jsx b/render/App.jsx index f08aaa0b..22466e58 100644 --- a/render/App.jsx +++ b/render/App.jsx @@ -54,8 +54,8 @@ export default class Routes extends Component { render() { return ( - - + } /> + } /> ); } diff --git a/render/components/__tests__/Navbar.spec.jsx b/render/components/__tests__/Navbar.spec.jsx index 983700fe..d3103ddd 100644 --- a/render/components/__tests__/Navbar.spec.jsx +++ b/render/components/__tests__/Navbar.spec.jsx @@ -23,7 +23,7 @@ describe('Navbar component', () => { const tree = renderer.create( - + } /> ); @@ -41,7 +41,7 @@ describe('Navbar component', () => { const wrapper = mount( - + } /> ); diff --git a/render/views/AppView.jsx b/render/views/AppView.jsx index 1cf8c017..db42f328 100644 --- a/render/views/AppView.jsx +++ b/render/views/AppView.jsx @@ -85,8 +85,8 @@ class AppView extends Component { { (!userId || !api_key) ? () : null } - - + } /> + } /> Date: Sun, 22 Dec 2019 21:17:15 +0100 Subject: [PATCH 02/38] Added Login mode to the LoginView (User+Password as default, API Key as alternative method). --- render/actions/user.actions.js | 13 ++- render/views/LoginView.jsx | 141 ++++++++++++++++++++++----------- 2 files changed, 105 insertions(+), 49 deletions(-) diff --git a/render/actions/user.actions.js b/render/actions/user.actions.js index b9d60e36..686dc3e6 100644 --- a/render/actions/user.actions.js +++ b/render/actions/user.actions.js @@ -11,17 +11,22 @@ const signout = () => (dispatch) => { dispatch({ type: USER_LOGOUT }); }; -const checkLogin = ({ username, password, redmineEndpoint }) => (dispatch) => { +const checkLogin = ({ useApiKey, apiKey, username, password, redmineEndpoint }) => (dispatch) => { if (!redmineEndpoint) throw new Error('Unable to login to an undefined redmine endpoint'); dispatch(notify.start(USER_LOGIN)); + const headers = {}; + if (useApiKey) { + headers['X-Redmine-API-Key'] = apiKey; + } else { + headers['Authorization'] = `Basic ${btoa(`${username}:${password}`)}`; + } + return login({ redmineEndpoint, url: '/users/current.json', - headers: { - Authorization: `Basic ${btoa(`${username}:${password}`)}` - } + headers, }).then(({ data }) => { Object.assign(data.user, { redmineEndpoint }); dispatch(notify.ok(USER_LOGIN, data)); diff --git a/render/views/LoginView.jsx b/render/views/LoginView.jsx index 8baa7b88..700e3c6a 100644 --- a/render/views/LoginView.jsx +++ b/render/views/LoginView.jsx @@ -30,6 +30,7 @@ const LoginForm = styled.form` grid-column: 2 / 6; grid-row: 2 / 4; min-width: 300px; + min-height: 500px; `; const Headline = styled.h1` @@ -50,7 +51,14 @@ const SubmitButton = styled(Button)` margin: 25px auto 0px auto; `; -class LoginView extends Component { +class LoginView extends Component { + constructor(props) { + super(props); + this.state = { + useApiKey: false + }; + } + componentDidMount() { const { userId, api_key } = this.props; if (userId && api_key) { @@ -58,12 +66,16 @@ class LoginView extends Component { } } - validate = ({ username, password, redmineEndpoint }) => { + validate = ({ apiKey, username, password, redmineEndpoint }) => { const errors = { - username: Joi.validate(username, Joi.string().required()), - password: Joi.validate(password, Joi.string().required()), redmineEndpoint: Joi.validate(redmineEndpoint, Joi.string().uri().required()) }; + if (this.state.useApiKey){ + errors.apiKey = Joi.validate(apiKey, Joi.string().required()); + } else { + errors.username = Joi.validate(username, Joi.string().required()); + errors.password = Joi.validate(password, Joi.string().required()); + } const results = {}; for (const [prop, validation] of Object.entries(errors)) { if (validation.error) { @@ -75,7 +87,7 @@ class LoginView extends Component { onSubmit = (values, { setSubmitting }) => { const { checkLogin } = this.props; - checkLogin(values).then(() => { + checkLogin({...values, useApiKey: this.state.useApiKey}).then(() => { const { loginError, userId } = this.props; if (!loginError && userId) { this.props.history.push('/app/summary'); @@ -84,57 +96,32 @@ class LoginView extends Component { }); } + onToggleLoginMode = () => { + this.setState({useApiKey: !this.state.useApiKey}) + } + render() { - const { loginError } = this.props; + const { loginError } = this.props; return ( {({ - values, - errors, - touched, - handleChange, - handleBlur, - handleSubmit, - isSubmitting - }) => ( + values, + errors, + touched, + handleChange, + handleBlur, + handleSubmit, + isSubmitting + }) => ( Redshape - - - {errors.username} - - - - {errors.password} - +