From 3267f05fdfde83f3bba87d533af793f51b1c1ad0 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 26 Jul 2018 08:32:46 +0200 Subject: [PATCH 1/4] removed fetchUsers on modify and introduced callbacks for modify and delete --- scm-ui/src/users/modules/users.js | 11 ++++++-- scm-ui/src/users/modules/users.test.js | 39 ++++++++++++++++++++++---- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/scm-ui/src/users/modules/users.js b/scm-ui/src/users/modules/users.js index 9cefdaec37..f6c01e7939 100644 --- a/scm-ui/src/users/modules/users.js +++ b/scm-ui/src/users/modules/users.js @@ -173,14 +173,16 @@ export function createUserFailure(user: User, err: Error): Action { //modify user -export function modifyUser(user: User) { +export function modifyUser(user: User, callback?: () => void) { return function(dispatch: Dispatch) { dispatch(modifyUserPending(user)); return apiClient .putWithContentType(user._links.update.href, user, CONTENT_TYPE_USER) .then(() => { dispatch(modifyUserSuccess(user)); - dispatch(fetchUsers()); + if (callback) { + callback(); + } }) .catch(err => { dispatch(modifyUserFailure(user, err)); @@ -214,13 +216,16 @@ export function modifyUserFailure(user: User, error: Error): Action { //delete user -export function deleteUser(user: User) { +export function deleteUser(user: User, callback?: () => void) { return function(dispatch: any) { dispatch(deleteUserPending(user)); return apiClient .delete(user._links.delete.href) .then(() => { dispatch(deleteUserSuccess(user)); + if (callback) { + callback(); + } }) .catch(cause => { const error = new Error( diff --git a/scm-ui/src/users/modules/users.test.js b/scm-ui/src/users/modules/users.test.js index 0dcca7e465..4c8a09d66d 100644 --- a/scm-ui/src/users/modules/users.test.js +++ b/scm-ui/src/users/modules/users.test.js @@ -258,15 +258,29 @@ describe("users fetch()", () => { fetchMock.putOnce("http://localhost:8081/scm/api/rest/v2/users/zaphod", { status: 204 }); - // after update, the users are fetched again - fetchMock.getOnce(USERS_URL, response); const store = mockStore({}); return store.dispatch(modifyUser(userZaphod)).then(() => { const actions = store.getActions(); + expect(actions.length).toBe(2); expect(actions[0].type).toEqual(MODIFY_USER_PENDING); expect(actions[1].type).toEqual(MODIFY_USER_SUCCESS); - expect(actions[2].type).toEqual(FETCH_USERS_PENDING); + }); + }); + + it("should call callback, after successful modified user", () => { + fetchMock.putOnce("http://localhost:8081/scm/api/rest/v2/users/zaphod", { + status: 204 + }); + + let called = false; + const callMe = () => { + called = true; + }; + + const store = mockStore({}); + return store.dispatch(modifyUser(userZaphod, callMe)).then(() => { + expect(called).toBeTruthy(); }); }); @@ -288,18 +302,33 @@ describe("users fetch()", () => { fetchMock.deleteOnce("http://localhost:8081/scm/api/rest/v2/users/zaphod", { status: 204 }); - // after update, the users are fetched again - fetchMock.getOnce(USERS_URL, response); const store = mockStore({}); return store.dispatch(deleteUser(userZaphod)).then(() => { const actions = store.getActions(); + expect(actions.length).toBe(2); expect(actions[0].type).toEqual(DELETE_USER); expect(actions[0].payload).toBe(userZaphod); expect(actions[1].type).toEqual(DELETE_USER_SUCCESS); }); }); + it("should call the callback, after successful delete", () => { + fetchMock.deleteOnce("http://localhost:8081/scm/api/rest/v2/users/zaphod", { + status: 204 + }); + + let called = false; + const callMe = () => { + called = true; + }; + + const store = mockStore({}); + return store.dispatch(deleteUser(userZaphod, callMe)).then(() => { + expect(called).toBeTruthy(); + }); + }); + it("should fail to delete user zaphod", () => { fetchMock.deleteOnce("http://localhost:8081/scm/api/rest/v2/users/zaphod", { status: 500 From b0f801be787beb4469c0784df2b84df9b1ee1092 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 26 Jul 2018 08:33:00 +0200 Subject: [PATCH 2/4] removed unused import --- scm-ui/src/users/components/UserForm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scm-ui/src/users/components/UserForm.js b/scm-ui/src/users/components/UserForm.js index 40ecf4504a..6c5cda7a53 100644 --- a/scm-ui/src/users/components/UserForm.js +++ b/scm-ui/src/users/components/UserForm.js @@ -4,7 +4,6 @@ import { translate } from "react-i18next"; import type { User } from "../types/User"; import { InputField, Checkbox } from "../../components/forms"; import { SubmitButton } from "../../components/buttons"; -import Loading from "../../components/Loading"; type Props = { submitForm: User => void, From 88dda4f98daf35644ba5430ba87ad414213cf126 Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 26 Jul 2018 08:33:22 +0200 Subject: [PATCH 3/4] navigate back to users page after delete --- scm-ui/src/users/containers/SingleUser.js | 28 +++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/scm-ui/src/users/containers/SingleUser.js b/scm-ui/src/users/containers/SingleUser.js index cac857a68a..215f78ae6e 100644 --- a/scm-ui/src/users/containers/SingleUser.js +++ b/scm-ui/src/users/containers/SingleUser.js @@ -7,6 +7,7 @@ import { Details } from "./../components/table"; import EditUser from "./EditUser"; import type { User } from "../types/User"; import type { UserEntry } from "../types/UserEntry"; +import type { History } from "history"; import { fetchUser, deleteUser } from "../modules/users"; import Loading from "../../components/Loading"; @@ -18,8 +19,9 @@ type Props = { name: string, userEntry?: UserEntry, match: any, - deleteUser: (user: User) => void, - fetchUser: string => void + deleteUser: (user: User, callback?: () => void) => void, + fetchUser: string => void, + history: History }; class SingleUser extends React.Component { @@ -27,6 +29,14 @@ class SingleUser extends React.Component { this.props.fetchUser(this.props.name); } + userDeleted = () => { + this.props.history.push("/users"); + }; + + deleteUser = (user: User) => { + this.props.deleteUser(user, this.userDeleted); + }; + stripEndingSlash = (url: string) => { if (url.endsWith("/")) { return url.substring(0, url.length - 2); @@ -34,8 +44,12 @@ class SingleUser extends React.Component { return url; }; + matchedUrl = () => { + return this.stripEndingSlash(this.props.match.url); + }; + render() { - const { userEntry, match, deleteUser } = this.props; + const { userEntry } = this.props; if (!userEntry || userEntry.loading) { return ; @@ -52,7 +66,7 @@ class SingleUser extends React.Component { } const user = userEntry.entry; - const url = this.stripEndingSlash(match.url); + const url = this.matchedUrl(); // TODO i18n @@ -73,7 +87,7 @@ class SingleUser extends React.Component {
- +
@@ -102,8 +116,8 @@ const mapDispatchToProps = dispatch => { fetchUser: (name: string) => { dispatch(fetchUser(name)); }, - deleteUser: (user: User) => { - dispatch(deleteUser(user)); + deleteUser: (user: User, callback?: () => void) => { + dispatch(deleteUser(user, callback)); } }; }; From 0d551de1472cee390f5c0061a77bfdc7971c47ee Mon Sep 17 00:00:00 2001 From: Sebastian Sdorra Date: Thu, 26 Jul 2018 08:51:05 +0200 Subject: [PATCH 4/4] go back to detail page after successfully modify --- scm-ui/src/users/containers/EditUser.js | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/scm-ui/src/users/containers/EditUser.js b/scm-ui/src/users/containers/EditUser.js index bb07424b14..3a9c4b0103 100644 --- a/scm-ui/src/users/containers/EditUser.js +++ b/scm-ui/src/users/containers/EditUser.js @@ -1,27 +1,38 @@ //@flow import React from "react"; import { connect } from "react-redux"; +import { withRouter } from "react-router-dom"; import UserForm from "./../components/UserForm"; import type { User } from "../types/User"; import { modifyUser } from "../modules/users"; +import type { History } from "history"; type Props = { user: User, - updateUser: User => void, - loading: boolean + modifyUser: (user: User, callback?: () => void) => void, + loading: boolean, + history: History }; class EditUser extends React.Component { + userModified = (user: User) => () => { + this.props.history.push(`/user/${user.name}`); + }; + + modifyUser = (user: User) => { + this.props.modifyUser(user, this.userModified(user)); + }; + render() { - const { user, updateUser } = this.props; - return updateUser(user)} user={user} />; + const { user } = this.props; + return this.modifyUser(user)} user={user} />; } } const mapDispatchToProps = dispatch => { return { - updateUser: (user: User) => { - dispatch(modifyUser(user)); + modifyUser: (user: User, callback?: () => void) => { + dispatch(modifyUser(user, callback)); } }; }; @@ -33,4 +44,4 @@ const mapStateToProps = (state, ownProps) => { export default connect( mapStateToProps, mapDispatchToProps -)(EditUser); +)(withRouter(EditUser));