From 0648586092165238dbee003fcd0ad2bb9a67f672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= Date: Tue, 10 Jul 2018 15:18:37 +0200 Subject: [PATCH] mockup delete button for user --- scm-ui/src/apiclient.js | 8 +- .../repositories/containers/Repositories.js | 2 +- .../src/users/containers/DeleteUserButton.js | 46 +++++++++ scm-ui/src/users/containers/UserRow.js | 8 ++ scm-ui/src/users/containers/Users.js | 10 +- scm-ui/src/users/modules/users.js | 95 ++++++++++++++++--- 6 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 scm-ui/src/users/containers/DeleteUserButton.js diff --git a/scm-ui/src/apiclient.js b/scm-ui/src/apiclient.js index f6b04a59a1..02d3263fec 100644 --- a/scm-ui/src/apiclient.js +++ b/scm-ui/src/apiclient.js @@ -1,16 +1,14 @@ // @flow // get api base url from environment -const apiUrl = process.env.API_URL || process.env.PUBLIC_URL || ""; +const apiUrl = process.env.API_URL || process.env.PUBLIC_URL || "/scm"; export const PAGE_NOT_FOUND_ERROR = Error("page not found"); -// fetch does not send the X-Requested-With header (https://github.com/github/fetch/issues/17), -// but we need the header to detect ajax request (AjaxAwareAuthenticationRedirectStrategy). const fetchOptions: RequestOptions = { credentials: "same-origin", headers: { - "X-Requested-With": "XMLHttpRequest" + Cache: "no-cache" } }; @@ -40,7 +38,7 @@ class ApiClient { return this.httpRequestWithJSONBody(url, payload, "POST"); } - delete(url: string, payload: any) { + delete(url: string) { let options: RequestOptions = { method: "DELETE" }; diff --git a/scm-ui/src/repositories/containers/Repositories.js b/scm-ui/src/repositories/containers/Repositories.js index a7cd59e7de..b1f01c5b5b 100644 --- a/scm-ui/src/repositories/containers/Repositories.js +++ b/scm-ui/src/repositories/containers/Repositories.js @@ -3,7 +3,7 @@ import React from 'react'; import { connect } from 'react-redux'; import { fetchRepositoriesIfNeeded } from '../modules/repositories'; -import { Link } from 'react-router-dom' +import { Link } from 'react-router-dom'; type Props = { diff --git a/scm-ui/src/users/containers/DeleteUserButton.js b/scm-ui/src/users/containers/DeleteUserButton.js new file mode 100644 index 0000000000..195e603ae8 --- /dev/null +++ b/scm-ui/src/users/containers/DeleteUserButton.js @@ -0,0 +1,46 @@ +// @flow +import React from "react"; +import { deleteUser } from '../modules/users'; +import {connect} from "react-redux"; + +type Props = { + user: any, + deleteUser: (username: string) => void +}; + +class DeleteUser extends React.Component { + + deleteUser = () => { + this.props.deleteUser(this.props.user.name); + }; + + render() { + if(this.props.user._links.delete) { + return ( + + + ); + } + } +} + +const mapStateToProps = state => { + return { + users: state.users.users + }; +}; + +const mapDispatchToProps = dispatch => { + return { + deleteUser: (username: string) => { + dispatch(deleteUser(username)); + } + }; +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(DeleteUser); diff --git a/scm-ui/src/users/containers/UserRow.js b/scm-ui/src/users/containers/UserRow.js index d9184d3586..077ffa7fc3 100644 --- a/scm-ui/src/users/containers/UserRow.js +++ b/scm-ui/src/users/containers/UserRow.js @@ -1,11 +1,15 @@ // @flow import React from "react"; +import DeleteUserButton from "./DeleteUserButton"; type Props = { user: any }; + + export default class UserRow extends React.Component { + render() { return ( @@ -14,7 +18,11 @@ export default class UserRow extends React.Component { + + + + ); } } diff --git a/scm-ui/src/users/containers/Users.js b/scm-ui/src/users/containers/Users.js index 9a628c6fc2..0702a56245 100644 --- a/scm-ui/src/users/containers/Users.js +++ b/scm-ui/src/users/containers/Users.js @@ -11,12 +11,18 @@ type Props = { error: any, users: any, fetchUsersIfNeeded: () => void, - fetchUsers: () => void + fetchUsers: () => void, + fetchUsersIfNeeded: (url: string) => void, + }; class Users extends React.Component { componentWillMount() { - this.props.fetchUsers(); + this.props.fetchUsersIfNeeded(); + } + + componentDidUpdate() { + this.props.fetchUsersIfNeeded(); } render() { diff --git a/scm-ui/src/users/modules/users.js b/scm-ui/src/users/modules/users.js index 192e13e0eb..a2a157d1c9 100644 --- a/scm-ui/src/users/modules/users.js +++ b/scm-ui/src/users/modules/users.js @@ -1,10 +1,16 @@ // @flow +import {apiClient, PAGE_NOT_FOUND_ERROR} from '../../apiclient'; const FETCH_USERS = "scm/users/FETCH"; const FETCH_USERS_SUCCESS = "scm/users/FETCH_SUCCESS"; const FETCH_USERS_FAILURE = "scm/users/FETCH_FAILURE"; +const FETCH_USERS_NOTFOUND = 'scm/users/FETCH_NOTFOUND'; -const USERS_URL = "/scm/api/rest/v2/users"; +const DELETE_USER = "scm/users/DELETE"; +const DELETE_USER_SUCCESS = "scm/users/DELETE_SUCCESS"; +const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE"; + +const USERS_URL = "users"; function requestUsers() { return { @@ -12,15 +18,29 @@ function requestUsers() { }; } +function failedToFetchUsers(url: string, err: Error) { + return { + type: FETCH_USERS_FAILURE, + payload: err, + url + }; +} + +function usersNotFound(url: string) { + return { + type: FETCH_USERS_NOTFOUND, + url + }; +} + export function fetchUsers() { + return function(dispatch) { - // dispatch(requestUsers()); - return fetch(USERS_URL, { - credentials: "same-origin", - headers: { - Cache: "no-cache" - } - }) + dispatch(requestUsers()); + return apiClient.get(USERS_URL) + .then(response => { + return response; + }) .then(response => { if (response.ok) { return response.json(); @@ -28,8 +48,15 @@ export function fetchUsers() { }) .then(data => { dispatch(fetchUsersSuccess(data)); + }) + .catch((err) => { + if (err === PAGE_NOT_FOUND_ERROR) { + dispatch(usersNotFound(USERS_URL)); + } else { + dispatch(failedToFetchUsers(USERS_URL, err)); + } }); - }; + } } function fetchUsersSuccess(users: any) { @@ -40,8 +67,10 @@ function fetchUsersSuccess(users: any) { } export function shouldFetchUsers(state: any): boolean { - const users = state.users; - return null; + if(state.users.users == null){ + return true; + } + return false; } export function fetchUsersIfNeeded() { @@ -52,17 +81,52 @@ export function fetchUsersIfNeeded() { }; } + + +function requestDeleteUser(url: string) { + return { + type: DELETE_USER, + url + }; +} + +function deleteUserSuccess() { + return { + type: DELETE_USER_SUCCESS, + }; +} + +function deleteUserFailure(url: string, err: Error) { + return { + type: DELETE_USER_FAILURE, + payload: err, + url + }; +} + +export function deleteUser(username: string) { + return function(dispatch) { + dispatch(requestDeleteUser(username)); + return apiClient.delete(USERS_URL + '/' + username) + .then(() => { + dispatch(deleteUserSuccess()); + }) + .catch((err) => dispatch(deleteUserFailure(username, err))); + } +} + + + export default function reducer(state: any = {}, action: any = {}) { switch (action.type) { case FETCH_USERS: return { ...state, - users: [{ name: "" }] + users: null }; case FETCH_USERS_SUCCESS: return { ...state, - timestamp: action.timestamp, error: null, users: action.payload._embedded.users }; @@ -72,6 +136,11 @@ export default function reducer(state: any = {}, action: any = {}) { login: false, error: action.payload }; + case DELETE_USER_SUCCESS: + return { + ...state, + users: null + }; default: return state;