diff --git a/scm-ui/src/containers/Main.js b/scm-ui/src/containers/Main.js index 021110a075..0ee8126efd 100644 --- a/scm-ui/src/containers/Main.js +++ b/scm-ui/src/containers/Main.js @@ -10,6 +10,8 @@ import Logout from "../containers/Logout"; import { Switch } from "react-router-dom"; import ProtectedRoute from "../components/ProtectedRoute"; +import EditUser from "../users/containers/EditUser"; +import AddUser from "../users/containers/AddUser"; type Props = { authenticated?: boolean @@ -30,10 +32,21 @@ class Main extends React.Component { + + ); diff --git a/scm-ui/src/users/containers/AddUser.js b/scm-ui/src/users/containers/AddUser.js new file mode 100644 index 0000000000..4c4752e12c --- /dev/null +++ b/scm-ui/src/users/containers/AddUser.js @@ -0,0 +1,41 @@ +//@flow +import React from "react"; +import { connect } from "react-redux"; +import UserForm from "./UserForm"; +import type { User } from "../types/User"; + +import { addUser } from "../modules/users"; +import { Route, Link } from "react-router-dom"; + +type Props = { + addUser: User => void +}; + +class AddUser extends React.Component { + render() { + const addUser = this.props.addUser; + + return ( +
+ addUser(user)} /> +
+ ); + } +} + +const mapDispatchToProps = dispatch => { + return { + addUser: (user: User) => { + dispatch(addUser(user)); + } + }; +}; + +const mapStateToProps = (state, ownProps) => { + return {}; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(AddUser); diff --git a/scm-ui/src/users/containers/EditUser.js b/scm-ui/src/users/containers/EditUser.js new file mode 100644 index 0000000000..4eb7db212d --- /dev/null +++ b/scm-ui/src/users/containers/EditUser.js @@ -0,0 +1,67 @@ +//@flow +import React from "react"; +import { connect } from "react-redux"; +import UserForm from "./UserForm"; +import type { User } from "../types/User"; + +import { + updateUser, + deleteUser, + editUser, + fetchUser, + getUsersFromState +} from "../modules/users"; +import { Route, Link } from "react-router-dom"; + +type Props = { + name: string, + fetchUser: string => void, + usersByNames: Map, + updateUser: User => void +}; + +class EditUser extends React.Component { + componentDidMount() { + this.props.fetchUser(this.props.name); + } + + render() { + const submitUser = this.props.updateUser; + + const { usersByNames, name } = this.props; + + if (!usersByNames || usersByNames[name].loading) { + return
Loading...
; + } else { + const user = usersByNames[name].entry; + return ( +
+ submitUser(user)} user={user} /> +
+ ); + } + } +} + +const mapDispatchToProps = dispatch => { + return { + fetchUser: (name: string) => { + dispatch(fetchUser(name)); + }, + updateUser: (user: User) => { + dispatch(updateUser(user)); + } + }; +}; + +const mapStateToProps = (state, ownProps) => { + return { + usersByNames: state.users.usersByNames, + name: ownProps.match.params.name + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(EditUser); diff --git a/scm-ui/src/users/containers/EditUserButton.js b/scm-ui/src/users/containers/EditUserButton.js index 3ec2661b30..118e0e753b 100644 --- a/scm-ui/src/users/containers/EditUserButton.js +++ b/scm-ui/src/users/containers/EditUserButton.js @@ -3,24 +3,24 @@ import React from "react"; import EditButton from "../../components/EditButton"; import type { User } from "../types/User"; import type { UserEntry } from "../types/UserEntry"; +import { Link } from "react-router-dom"; type Props = { - entry: UserEntry, - editUser: User => void + entry: UserEntry }; class EditUserButton extends React.Component { render() { + const { entry } = this.props; + const link = "/users/edit/" + entry.entry.name; + if (!this.isEditable()) { return ""; } - const { entry, editUser } = this.props; return ( - editUser(entry.entry)} - loading={entry.loading} - /> + + {}} loading={entry.loading} /> + ); } diff --git a/scm-ui/src/users/containers/UserForm.js b/scm-ui/src/users/containers/UserForm.js index 23df3c568f..6382088239 100644 --- a/scm-ui/src/users/containers/UserForm.js +++ b/scm-ui/src/users/containers/UserForm.js @@ -23,55 +23,59 @@ class UserForm extends React.Component { }; } + componentDidMount() { + this.setState({ ...this.props.user }); + } + submit = (event: Event) => { event.preventDefault(); this.props.submitForm(this.state); }; - componentWillReceiveProps() { - this.setState(this.props.user); - } - render() { const user = this.state; - return ( -
-
- - - - - - - - -
- ); + if (user) { + return ( +
+
+ + + + + + + + +
+ ); + } else { + return
Loading...
; + } } handleUsernameChange = (name: string) => { diff --git a/scm-ui/src/users/containers/Users.js b/scm-ui/src/users/containers/Users.js index eb91b14866..6c9793b89c 100644 --- a/scm-ui/src/users/containers/Users.js +++ b/scm-ui/src/users/containers/Users.js @@ -2,17 +2,9 @@ import React from "react"; import { connect } from "react-redux"; -import { - fetchUsers, - addUser, - updateUser, - deleteUser, - editUser, - getUsersFromState -} from "../modules/users"; +import { fetchUsers, deleteUser, getUsersFromState } from "../modules/users"; import Loading from "../../components/Loading"; import ErrorNotification from "../../components/ErrorNotification"; -import UserForm from "./UserForm"; import UserTable from "./UserTable"; import type { User } from "../types/User"; import type { UserEntry } from "../types/UserEntry"; @@ -22,11 +14,7 @@ type Props = { error: Error, userEntries: Array, fetchUsers: () => void, - deleteUser: User => void, - addUser: User => void, - updateUser: User => void, - editUser: User => void, - userToEdit: User + deleteUser: User => void }; class Users extends React.Component { @@ -34,28 +22,6 @@ class Users extends React.Component { this.props.fetchUsers(); } - addUser = (user: User) => { - this.props.addUser(user); - }; - - updateUser = (user: User) => { - this.props.updateUser(user); - }; - - componentDidUpdate(prevProps: Props) { - if (prevProps.userToEdit !== this.props.userToEdit) { - this.setState(this.props.userToEdit); - } - } - - submitUser = (user: User) => { - if (user._links && user._links.update) { - this.updateUser(user); - } else { - this.addUser(user); - } - }; - render() { return (
@@ -69,20 +35,12 @@ class Users extends React.Component { } renderContent() { - const { userEntries, deleteUser, editUser, userToEdit, error } = this.props; + const { userEntries, deleteUser, error } = this.props; if (userEntries) { return (
- editUser(user)} - /> - this.submitUser(user)} - user={userToEdit} - /> +
); } else { @@ -93,13 +51,8 @@ class Users extends React.Component { const mapStateToProps = state => { const userEntries = getUsersFromState(state); - const userToEdit = state.users.editUser; - if (!userEntries) { - return { userToEdit }; - } return { userEntries, - userToEdit, error: state.users.error }; }; @@ -109,17 +62,8 @@ const mapDispatchToProps = dispatch => { fetchUsers: () => { dispatch(fetchUsers()); }, - addUser: (user: User) => { - dispatch(addUser(user)); - }, - updateUser: (user: User) => { - dispatch(updateUser(user)); - }, deleteUser: (user: User) => { dispatch(deleteUser(user)); - }, - editUser: (user: User) => { - dispatch(editUser(user)); } }; }; diff --git a/scm-ui/src/users/modules/users.js b/scm-ui/src/users/modules/users.js index e89ce3358b..e198cccfb3 100644 --- a/scm-ui/src/users/modules/users.js +++ b/scm-ui/src/users/modules/users.js @@ -9,6 +9,9 @@ export const FETCH_USERS_SUCCESS = "scm/users/FETCH_SUCCESS"; export const FETCH_USERS_FAILURE = "scm/users/FETCH_FAILURE"; export const FETCH_USERS_NOTFOUND = "scm/users/FETCH_NOTFOUND"; +export const FETCH_USER = "scm/users/FETCH_USER"; +export const FETCH_USER_SUCCESS = "scm/users/FETCH_USER_SUCCESS"; + export const ADD_USER = "scm/users/ADD"; export const ADD_USER_SUCCESS = "scm/users/ADD_SUCCESS"; export const ADD_USER_FAILURE = "scm/users/ADD_FAILURE"; @@ -24,6 +27,7 @@ export const DELETE_USER_SUCCESS = "scm/users/DELETE_SUCCESS"; export const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE"; const USERS_URL = "users"; +const USER_URL = "users/"; const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2"; @@ -81,6 +85,47 @@ function fetchUsersSuccess(users: any) { }; } +function requestUser(name: string) { + return { + type: FETCH_USER, + payload: { name } + }; +} + +export function fetchUser(name: string) { + const userUrl = USER_URL + name; + return function(dispatch: any) { + dispatch(requestUsers()); + return apiClient + .get(userUrl) + .then(response => { + return response; + }) + .then(response => { + if (response.ok) { + return response.json(); + } + }) + .then(data => { + dispatch(fetchUserSuccess(data)); + }) + .catch(err => { + if (err === NOT_FOUND_ERROR) { + dispatch(usersNotFound(userUrl)); + } else { + dispatch(failedToFetchUsers(userUrl, err)); + } + }); + }; +} + +function fetchUserSuccess(user: User) { + return { + type: FETCH_USER_SUCCESS, + payload: user + }; +} + function requestAddUser(user: User) { return { type: ADD_USER, @@ -258,7 +303,13 @@ export default function reducer(state: any = {}, action: any = {}) { error: null, entry: action.payload }); + case FETCH_USER: + return reduceUsersByNames(state, action.payload.name, { + loading: true, + error: null + }); case FETCH_USERS_SUCCESS: + // return red(state, action.payload._embedded.users); const users = action.payload._embedded.users; const userNames = users.map(user => user.name); const usersByNames = extractUsersByNames( @@ -266,7 +317,6 @@ export default function reducer(state: any = {}, action: any = {}) { userNames, state.usersByNames ); - return { ...state, users: { @@ -276,6 +326,21 @@ export default function reducer(state: any = {}, action: any = {}) { }, usersByNames }; + case FETCH_USER_SUCCESS: + const ubn = extractUsersByNames( + [action.payload], + [action.payload.name], + state.usersByNames + ); + return { + ...state, + users: { + error: null, + entries: [action.payload.name], + loading: false + }, + usersByNames: ubn + }; case FETCH_USERS_FAILURE: case DELETE_USER_FAILURE: