mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-09 06:55:47 +01:00
Improved flow coverage, fixed bugs and enabled deleting users
This commit is contained in:
@@ -5,7 +5,6 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"flow-bin": "^0.75.0",
|
|
||||||
"history": "^4.7.2",
|
"history": "^4.7.2",
|
||||||
"react": "^16.4.1",
|
"react": "^16.4.1",
|
||||||
"react-dom": "^16.4.1",
|
"react-dom": "^16.4.1",
|
||||||
@@ -34,6 +33,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"enzyme": "^3.3.0",
|
"enzyme": "^3.3.0",
|
||||||
"enzyme-adapter-react-16": "^1.1.1",
|
"enzyme-adapter-react-16": "^1.1.1",
|
||||||
|
"flow-bin": "^0.75.0",
|
||||||
|
"flow-typed": "^2.5.1",
|
||||||
"prettier": "^1.13.7",
|
"prettier": "^1.13.7",
|
||||||
"react-test-renderer": "^16.4.1"
|
"react-test-renderer": "^16.4.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
const apiUrl = process.env.API_URL || process.env.PUBLIC_URL || "/scm";
|
const apiUrl = process.env.API_URL || process.env.PUBLIC_URL || "/scm";
|
||||||
|
|
||||||
export const PAGE_NOT_FOUND_ERROR = Error("page not found");
|
export const PAGE_NOT_FOUND_ERROR = Error("page not found");
|
||||||
|
export const NOT_AUTHENTICATED_ERROR = Error("not authenticated");
|
||||||
|
|
||||||
const fetchOptions: RequestOptions = {
|
const fetchOptions: RequestOptions = {
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
@@ -15,7 +16,7 @@ const fetchOptions: RequestOptions = {
|
|||||||
function handleStatusCode(response: Response) {
|
function handleStatusCode(response: Response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
return response;
|
throw NOT_AUTHENTICATED_ERROR;
|
||||||
}
|
}
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
throw PAGE_NOT_FOUND_ERROR;
|
throw PAGE_NOT_FOUND_ERROR;
|
||||||
@@ -26,11 +27,14 @@ function handleStatusCode(response: Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createUrl(url: string) {
|
function createUrl(url: string) {
|
||||||
|
if (url.indexOf("://") > 0) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
return `${apiUrl}/api/rest/v2/${url}`;
|
return `${apiUrl}/api/rest/v2/${url}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
get(url: string) {
|
get(url: string): Promise<Response> {
|
||||||
return fetch(createUrl(url), fetchOptions).then(handleStatusCode);
|
return fetch(createUrl(url), fetchOptions).then(handleStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +42,7 @@ class ApiClient {
|
|||||||
return this.httpRequestWithJSONBody(url, payload, "POST");
|
return this.httpRequestWithJSONBody(url, payload, "POST");
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(url: string) {
|
delete(url: string): Promise<Response> {
|
||||||
let options: RequestOptions = {
|
let options: RequestOptions = {
|
||||||
method: "DELETE"
|
method: "DELETE"
|
||||||
};
|
};
|
||||||
@@ -46,7 +50,11 @@ class ApiClient {
|
|||||||
return fetch(createUrl(url), options).then(handleStatusCode);
|
return fetch(createUrl(url), options).then(handleStatusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
httpRequestWithJSONBody(url: string, payload: any, method: string) {
|
httpRequestWithJSONBody(
|
||||||
|
url: string,
|
||||||
|
payload: any,
|
||||||
|
method: string
|
||||||
|
): Promise<Response> {
|
||||||
let options: RequestOptions = {
|
let options: RequestOptions = {
|
||||||
method: method,
|
method: method,
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
|
|||||||
@@ -9,17 +9,19 @@ import { withRouter } from "react-router-dom";
|
|||||||
type Props = {
|
type Props = {
|
||||||
login: boolean,
|
login: boolean,
|
||||||
username: string,
|
username: string,
|
||||||
getAuthState: any
|
getAuthState: () => void,
|
||||||
|
loading: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component<Props> {
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.props.getAuthState();
|
this.props.getAuthState();
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { login, username } = this.props.login;
|
const { login, username, loading } = this.props;
|
||||||
|
if (loading) {
|
||||||
if (!login) {
|
return <div>Loading...</div>;
|
||||||
|
} else if (!login) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Login />
|
<Login />
|
||||||
@@ -44,7 +46,7 @@ const mapDispatchToProps = dispatch => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
return { login: state.login };
|
return state.login || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withRouter(
|
export default withRouter(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//@flow
|
//@flow
|
||||||
|
|
||||||
import { apiClient } from "../apiclient";
|
import { apiClient, NOT_AUTHENTICATED_ERROR } from "../apiclient";
|
||||||
|
|
||||||
const LOGIN_URL = "/auth/access_token";
|
const LOGIN_URL = "/auth/access_token";
|
||||||
const AUTHENTICATION_INFO_URL = "/me";
|
const AUTHENTICATION_INFO_URL = "/me";
|
||||||
@@ -21,7 +21,7 @@ export function getIsAuthenticatedRequest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getIsAuthenticated() {
|
export function getIsAuthenticated() {
|
||||||
return function(dispatch: (any) => void) {
|
return function(dispatch: any => void) {
|
||||||
dispatch(getIsAuthenticatedRequest());
|
dispatch(getIsAuthenticatedRequest());
|
||||||
return apiClient
|
return apiClient
|
||||||
.get(AUTHENTICATION_INFO_URL)
|
.get(AUTHENTICATION_INFO_URL)
|
||||||
@@ -32,6 +32,13 @@ export function getIsAuthenticated() {
|
|||||||
if (data) {
|
if (data) {
|
||||||
dispatch(isAuthenticated(data.username));
|
dispatch(isAuthenticated(data.username));
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch((error: Error) => {
|
||||||
|
if (error === NOT_AUTHENTICATED_ERROR) {
|
||||||
|
dispatch(isNotAuthenticated());
|
||||||
|
} else {
|
||||||
|
// TODO: Handle errors other than not_authenticated
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -60,9 +67,9 @@ export function login(username: string, password: string) {
|
|||||||
cookie: true,
|
cookie: true,
|
||||||
grant_type: "password",
|
grant_type: "password",
|
||||||
username,
|
username,
|
||||||
password,
|
password
|
||||||
};
|
};
|
||||||
return function(dispatch: (any) => void) {
|
return function(dispatch: any => void) {
|
||||||
dispatch(loginRequest());
|
dispatch(loginRequest());
|
||||||
return apiClient.post(LOGIN_URL, login_data).then(response => {
|
return apiClient.post(LOGIN_URL, login_data).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
@@ -79,23 +86,29 @@ export function loginSuccessful() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function reducer(state: any = {}, action: any = {}) {
|
export default function reducer(
|
||||||
|
state: any = { loading: true },
|
||||||
|
action: any = {}
|
||||||
|
) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
loading: true,
|
||||||
login: false,
|
login: false,
|
||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
case LOGIN_SUCCESSFUL:
|
case LOGIN_SUCCESSFUL:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
loading: false,
|
||||||
login: true,
|
login: true,
|
||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
case LOGIN_FAILED:
|
case LOGIN_FAILED:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
loading: false,
|
||||||
login: false,
|
login: false,
|
||||||
error: action.payload
|
error: action.payload
|
||||||
};
|
};
|
||||||
@@ -103,12 +116,14 @@ export default function reducer(state: any = {}, action: any = {}) {
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
login: true,
|
login: true,
|
||||||
|
loading: false,
|
||||||
username: action.username
|
username: action.username
|
||||||
};
|
};
|
||||||
case IS_NOT_AUTHENTICATED:
|
case IS_NOT_AUTHENTICATED:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
login: false,
|
login: false,
|
||||||
|
loading: false,
|
||||||
username: null,
|
username: null,
|
||||||
error: null
|
error: null
|
||||||
};
|
};
|
||||||
|
|||||||
6
scm-ui/src/types/hal.js
Normal file
6
scm-ui/src/types/hal.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// @flow
|
||||||
|
export type Link = {
|
||||||
|
href: string
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Links = { [string]: Link };
|
||||||
@@ -1,21 +1,17 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import type { User } from "../types/User";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: any,
|
user: User,
|
||||||
deleteUser: (link: string) => void
|
deleteUser: (link: string) => void
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteUser extends React.Component<Props> {
|
class DeleteUser extends React.Component<Props> {
|
||||||
|
|
||||||
deleteUser = () => {
|
deleteUser = () => {
|
||||||
this.props.deleteUser(this.props.user._links.delete.href);
|
this.props.deleteUser(this.props.user._links.delete.href);
|
||||||
};
|
};
|
||||||
|
|
||||||
if(deleteButtonClicked) {
|
|
||||||
let deleteButtonAsk = <div>You really want to remove this user?</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
isDeletable = () => {
|
isDeletable = () => {
|
||||||
return this.props.user._links.delete;
|
return this.props.user._links.delete;
|
||||||
};
|
};
|
||||||
@@ -28,7 +24,6 @@ class DeleteUser extends React.Component<Props> {
|
|||||||
<button type="button" onClick={this.deleteUser}>
|
<button type="button" onClick={this.deleteUser}>
|
||||||
Delete User
|
Delete User
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,39 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import {configure, shallow} from 'enzyme';
|
import { configure, shallow } from "enzyme";
|
||||||
import DeleteUserButton from "./DeleteUserButton";
|
import DeleteUserButton from "./DeleteUserButton";
|
||||||
import Adapter from 'enzyme-adapter-react-16';
|
import Adapter from "enzyme-adapter-react-16";
|
||||||
|
|
||||||
import 'raf/polyfill';
|
import "raf/polyfill";
|
||||||
|
|
||||||
configure({ adapter: new Adapter() });
|
configure({ adapter: new Adapter() });
|
||||||
|
|
||||||
it('should render nothing, if the delete link is missing', () => {
|
it("should render nothing, if the delete link is missing", () => {
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
_links: {}
|
_links: {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const button = shallow(<DeleteUserButton user={ user } />);
|
const button = shallow(<DeleteUserButton user={user} />);
|
||||||
expect(button.text()).toBe("");
|
expect(button.text()).toBe("");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render the button', () => {
|
it("should render the button", () => {
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
_links: {
|
_links: {
|
||||||
"delete": {
|
delete: {
|
||||||
"href": "/users"
|
href: "/users"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const button = shallow(<DeleteUserButton user={ user } />);
|
const button = shallow(<DeleteUserButton user={user} />);
|
||||||
expect(button.text()).not.toBe("");
|
expect(button.text()).not.toBe("");
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the delete user function with delete url', () => {
|
it("should call the delete user function with delete url", () => {
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
_links: {
|
_links: {
|
||||||
"delete": {
|
delete: {
|
||||||
"href": "/users"
|
href: "/users"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -47,7 +44,7 @@ it('should call the delete user function with delete url', () => {
|
|||||||
calledUrl = url;
|
calledUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
const button = shallow(<DeleteUserButton user={ user } deleteUser={ capture } />);
|
const button = shallow(<DeleteUserButton user={user} deleteUser={capture} />);
|
||||||
button.simulate("click");
|
button.simulate("click");
|
||||||
|
|
||||||
expect(calledUrl).toBe("/users");
|
expect(calledUrl).toBe("/users");
|
||||||
|
|||||||
@@ -1,22 +1,26 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import DeleteUserButton from "./DeleteUserButton";
|
import DeleteUserButton from "./DeleteUserButton";
|
||||||
|
import type { User } from "../types/User";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
user: any
|
user: User,
|
||||||
|
deleteUser: string => void
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class UserRow extends React.Component<Props> {
|
export default class UserRow extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
|
const { user, deleteUser } = this.props;
|
||||||
return (
|
return (
|
||||||
<tr>
|
<tr>
|
||||||
<td>{this.props.user.displayName}</td>
|
<td>{user.name}</td>
|
||||||
<td>{this.props.user.mail}</td>
|
<td>{user.displayName}</td>
|
||||||
|
<td>{user.mail}</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="checkbox" id="admin" checked={this.props.user.admin} />
|
<input type="checkbox" id="admin" checked={user.admin} readOnly />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<DeleteUserButton user={this.props.user} />
|
<DeleteUserButton user={user} deleteUser={deleteUser} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,27 +2,22 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { fetchUsersIfNeeded, fetchUsers } from "../modules/users";
|
import { fetchUsers, deleteUser } from "../modules/users";
|
||||||
import Login from "../../containers/Login";
|
import Login from "../../containers/Login";
|
||||||
import UserRow from "./UserRow";
|
import UserRow from "./UserRow";
|
||||||
|
import type { User } from "../types/User";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
login: boolean,
|
login: boolean,
|
||||||
error: any,
|
error: Error,
|
||||||
users: any,
|
users: Array<User>,
|
||||||
fetchUsersIfNeeded: () => void,
|
|
||||||
fetchUsers: () => void,
|
fetchUsers: () => void,
|
||||||
fetchUsersIfNeeded: (url: string) => void,
|
deleteUser: string => void
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Users extends React.Component<Props> {
|
class Users extends React.Component<Props> {
|
||||||
componentWillMount() {
|
componentDidMount() {
|
||||||
this.props.fetchUsersIfNeeded();
|
this.props.fetchUsers();
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate() {
|
|
||||||
this.props.fetchUsersIfNeeded();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@@ -35,13 +30,20 @@ class Users extends React.Component<Props> {
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Display Name</th>
|
||||||
<th>E-Mail</th>
|
<th>E-Mail</th>
|
||||||
<th>Admin</th>
|
<th>Admin</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{this.props.users.map((user, index) => {
|
{this.props.users.map((user, index) => {
|
||||||
return <UserRow key={index} user={user} />;
|
return (
|
||||||
|
<UserRow
|
||||||
|
key={index}
|
||||||
|
user={user}
|
||||||
|
deleteUser={this.props.deleteUser}
|
||||||
|
/>
|
||||||
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -61,11 +63,11 @@ const mapStateToProps = state => {
|
|||||||
|
|
||||||
const mapDispatchToProps = dispatch => {
|
const mapDispatchToProps = dispatch => {
|
||||||
return {
|
return {
|
||||||
fetchUsersIfNeeded: () => {
|
|
||||||
dispatch(fetchUsersIfNeeded());
|
|
||||||
},
|
|
||||||
fetchUsers: () => {
|
fetchUsers: () => {
|
||||||
dispatch(fetchUsers());
|
dispatch(fetchUsers());
|
||||||
|
},
|
||||||
|
deleteUser: (link: string) => {
|
||||||
|
dispatch(deleteUser(link));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { apiClient, PAGE_NOT_FOUND_ERROR } from "../../apiclient";
|
import { apiClient, PAGE_NOT_FOUND_ERROR } from "../../apiclient";
|
||||||
|
import { ThunkDispatch } from "redux-thunk";
|
||||||
|
|
||||||
const FETCH_USERS = "scm/users/FETCH";
|
const FETCH_USERS = "scm/users/FETCH";
|
||||||
const FETCH_USERS_SUCCESS = "scm/users/FETCH_SUCCESS";
|
const FETCH_USERS_SUCCESS = "scm/users/FETCH_SUCCESS";
|
||||||
@@ -34,7 +35,7 @@ function usersNotFound(url: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function fetchUsers() {
|
export function fetchUsers() {
|
||||||
return function(dispatch: any => void) {
|
return function(dispatch: ThunkDispatch) {
|
||||||
dispatch(requestUsers());
|
dispatch(requestUsers());
|
||||||
return apiClient
|
return apiClient
|
||||||
.get(USERS_URL)
|
.get(USERS_URL)
|
||||||
@@ -66,21 +67,6 @@ function fetchUsersSuccess(users: any) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldFetchUsers(state: any): boolean {
|
|
||||||
if (state.users.users == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fetchUsersIfNeeded() {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
if (shouldFetchUsers(getState())) {
|
|
||||||
dispatch(fetchUsers());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestDeleteUser(url: string) {
|
function requestDeleteUser(url: string) {
|
||||||
return {
|
return {
|
||||||
type: DELETE_USER,
|
type: DELETE_USER,
|
||||||
@@ -102,41 +88,42 @@ function deleteUserFailure(url: string, err: Error) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteUser(username: string) {
|
export function deleteUser(link: string) {
|
||||||
return function(dispatch) {
|
return function(dispatch: ThunkDispatch) {
|
||||||
dispatch(requestDeleteUser(username));
|
dispatch(requestDeleteUser(link));
|
||||||
return apiClient
|
return apiClient
|
||||||
.delete(USERS_URL + "/" + username)
|
.delete(link)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch(deleteUserSuccess());
|
dispatch(deleteUserSuccess());
|
||||||
|
dispatch(fetchUsers());
|
||||||
})
|
})
|
||||||
.catch(err => dispatch(deleteUserFailure(username, err)));
|
.catch(err => dispatch(deleteUserFailure(link, err)));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function reducer(state: any = {}, action: any = {}) {
|
export default function reducer(state: any = {}, action: any = {}) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case FETCH_USERS:
|
case FETCH_USERS:
|
||||||
|
case DELETE_USER:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
users: null
|
users: null,
|
||||||
|
loading: true
|
||||||
};
|
};
|
||||||
case FETCH_USERS_SUCCESS:
|
case FETCH_USERS_SUCCESS:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
error: null,
|
error: null,
|
||||||
users: action.payload._embedded.users
|
users: action.payload._embedded.users,
|
||||||
|
loading: false
|
||||||
};
|
};
|
||||||
case FETCH_USERS_FAILURE:
|
case FETCH_USERS_FAILURE:
|
||||||
|
case DELETE_USER_FAILURE:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
login: false,
|
login: false,
|
||||||
error: action.payload
|
error: action.payload,
|
||||||
};
|
loading: false
|
||||||
case DELETE_USER_SUCCESS:
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
users: null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
10
scm-ui/src/users/types/User.js
Normal file
10
scm-ui/src/users/types/User.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//@flow
|
||||||
|
import type { Link, Links } from "../../types/hal";
|
||||||
|
|
||||||
|
export type User = {
|
||||||
|
displayName: string,
|
||||||
|
name: string,
|
||||||
|
mail: string,
|
||||||
|
admin: boolean,
|
||||||
|
_links: Links
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user