mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
Implemented components for adding/editing users
This commit is contained in:
@@ -10,6 +10,8 @@ import Logout from "../containers/Logout";
|
|||||||
|
|
||||||
import { Switch } from "react-router-dom";
|
import { Switch } from "react-router-dom";
|
||||||
import ProtectedRoute from "../components/ProtectedRoute";
|
import ProtectedRoute from "../components/ProtectedRoute";
|
||||||
|
import EditUser from "../users/containers/EditUser";
|
||||||
|
import AddUser from "../users/containers/AddUser";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
authenticated?: boolean
|
authenticated?: boolean
|
||||||
@@ -30,10 +32,21 @@ class Main extends React.Component<Props> {
|
|||||||
<Route exact path="/login" component={Login} />
|
<Route exact path="/login" component={Login} />
|
||||||
<Route path="/logout" component={Logout} />
|
<Route path="/logout" component={Logout} />
|
||||||
<ProtectedRoute
|
<ProtectedRoute
|
||||||
|
exact
|
||||||
path="/users"
|
path="/users"
|
||||||
component={Users}
|
component={Users}
|
||||||
authenticated={authenticated}
|
authenticated={authenticated}
|
||||||
/>
|
/>
|
||||||
|
<ProtectedRoute
|
||||||
|
authenticated={authenticated}
|
||||||
|
path="/users/edit/:name"
|
||||||
|
component={EditUser}
|
||||||
|
/>
|
||||||
|
<ProtectedRoute
|
||||||
|
authenticated={authenticated}
|
||||||
|
path="/users/add"
|
||||||
|
component={AddUser}
|
||||||
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
41
scm-ui/src/users/containers/AddUser.js
Normal file
41
scm-ui/src/users/containers/AddUser.js
Normal file
@@ -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<Props> {
|
||||||
|
render() {
|
||||||
|
const addUser = this.props.addUser;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<UserForm submitForm={user => addUser(user)} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps = dispatch => {
|
||||||
|
return {
|
||||||
|
addUser: (user: User) => {
|
||||||
|
dispatch(addUser(user));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(AddUser);
|
||||||
67
scm-ui/src/users/containers/EditUser.js
Normal file
67
scm-ui/src/users/containers/EditUser.js
Normal file
@@ -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<string, any>,
|
||||||
|
updateUser: User => void
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditUser extends React.Component<Props> {
|
||||||
|
componentDidMount() {
|
||||||
|
this.props.fetchUser(this.props.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const submitUser = this.props.updateUser;
|
||||||
|
|
||||||
|
const { usersByNames, name } = this.props;
|
||||||
|
|
||||||
|
if (!usersByNames || usersByNames[name].loading) {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
} else {
|
||||||
|
const user = usersByNames[name].entry;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<UserForm submitForm={user => submitUser(user)} user={user} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
@@ -3,24 +3,24 @@ import React from "react";
|
|||||||
import EditButton from "../../components/EditButton";
|
import EditButton from "../../components/EditButton";
|
||||||
import type { User } from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import type { UserEntry } from "../types/UserEntry";
|
import type { UserEntry } from "../types/UserEntry";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
entry: UserEntry,
|
entry: UserEntry
|
||||||
editUser: User => void
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditUserButton extends React.Component<Props> {
|
class EditUserButton extends React.Component<Props> {
|
||||||
render() {
|
render() {
|
||||||
|
const { entry } = this.props;
|
||||||
|
const link = "/users/edit/" + entry.entry.name;
|
||||||
|
|
||||||
if (!this.isEditable()) {
|
if (!this.isEditable()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
const { entry, editUser } = this.props;
|
|
||||||
return (
|
return (
|
||||||
<EditButton
|
<Link to={link}>
|
||||||
label="Edit"
|
<EditButton label="Edit" action={() => {}} loading={entry.loading} />
|
||||||
action={e => editUser(entry.entry)}
|
</Link>
|
||||||
loading={entry.loading}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,18 @@ class UserForm extends React.Component<Props, User> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.setState({ ...this.props.user });
|
||||||
|
}
|
||||||
|
|
||||||
submit = (event: Event) => {
|
submit = (event: Event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.props.submitForm(this.state);
|
this.props.submitForm(this.state);
|
||||||
};
|
};
|
||||||
|
|
||||||
componentWillReceiveProps() {
|
|
||||||
this.setState(this.props.user);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const user = this.state;
|
const user = this.state;
|
||||||
|
if (user) {
|
||||||
return (
|
return (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<form onSubmit={this.submit}>
|
<form onSubmit={this.submit}>
|
||||||
@@ -72,6 +73,9 @@ class UserForm extends React.Component<Props, User> {
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUsernameChange = (name: string) => {
|
handleUsernameChange = (name: string) => {
|
||||||
|
|||||||
@@ -2,17 +2,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import {
|
import { fetchUsers, deleteUser, getUsersFromState } from "../modules/users";
|
||||||
fetchUsers,
|
|
||||||
addUser,
|
|
||||||
updateUser,
|
|
||||||
deleteUser,
|
|
||||||
editUser,
|
|
||||||
getUsersFromState
|
|
||||||
} from "../modules/users";
|
|
||||||
import Loading from "../../components/Loading";
|
import Loading from "../../components/Loading";
|
||||||
import ErrorNotification from "../../components/ErrorNotification";
|
import ErrorNotification from "../../components/ErrorNotification";
|
||||||
import UserForm from "./UserForm";
|
|
||||||
import UserTable from "./UserTable";
|
import UserTable from "./UserTable";
|
||||||
import type { User } from "../types/User";
|
import type { User } from "../types/User";
|
||||||
import type { UserEntry } from "../types/UserEntry";
|
import type { UserEntry } from "../types/UserEntry";
|
||||||
@@ -22,11 +14,7 @@ type Props = {
|
|||||||
error: Error,
|
error: Error,
|
||||||
userEntries: Array<UserEntry>,
|
userEntries: Array<UserEntry>,
|
||||||
fetchUsers: () => void,
|
fetchUsers: () => void,
|
||||||
deleteUser: User => void,
|
deleteUser: User => void
|
||||||
addUser: User => void,
|
|
||||||
updateUser: User => void,
|
|
||||||
editUser: User => void,
|
|
||||||
userToEdit: User
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Users extends React.Component<Props, User> {
|
class Users extends React.Component<Props, User> {
|
||||||
@@ -34,28 +22,6 @@ class Users extends React.Component<Props, User> {
|
|||||||
this.props.fetchUsers();
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<section className="section">
|
<section className="section">
|
||||||
@@ -69,20 +35,12 @@ class Users extends React.Component<Props, User> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderContent() {
|
renderContent() {
|
||||||
const { userEntries, deleteUser, editUser, userToEdit, error } = this.props;
|
const { userEntries, deleteUser, error } = this.props;
|
||||||
if (userEntries) {
|
if (userEntries) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ErrorNotification error={error} />
|
<ErrorNotification error={error} />
|
||||||
<UserTable
|
<UserTable entries={userEntries} deleteUser={deleteUser} />
|
||||||
entries={userEntries}
|
|
||||||
deleteUser={deleteUser}
|
|
||||||
editUser={user => editUser(user)}
|
|
||||||
/>
|
|
||||||
<UserForm
|
|
||||||
submitForm={user => this.submitUser(user)}
|
|
||||||
user={userToEdit}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -93,13 +51,8 @@ class Users extends React.Component<Props, User> {
|
|||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const userEntries = getUsersFromState(state);
|
const userEntries = getUsersFromState(state);
|
||||||
const userToEdit = state.users.editUser;
|
|
||||||
if (!userEntries) {
|
|
||||||
return { userToEdit };
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
userEntries,
|
userEntries,
|
||||||
userToEdit,
|
|
||||||
error: state.users.error
|
error: state.users.error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -109,17 +62,8 @@ const mapDispatchToProps = dispatch => {
|
|||||||
fetchUsers: () => {
|
fetchUsers: () => {
|
||||||
dispatch(fetchUsers());
|
dispatch(fetchUsers());
|
||||||
},
|
},
|
||||||
addUser: (user: User) => {
|
|
||||||
dispatch(addUser(user));
|
|
||||||
},
|
|
||||||
updateUser: (user: User) => {
|
|
||||||
dispatch(updateUser(user));
|
|
||||||
},
|
|
||||||
deleteUser: (user: User) => {
|
deleteUser: (user: User) => {
|
||||||
dispatch(deleteUser(user));
|
dispatch(deleteUser(user));
|
||||||
},
|
|
||||||
editUser: (user: User) => {
|
|
||||||
dispatch(editUser(user));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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_FAILURE = "scm/users/FETCH_FAILURE";
|
||||||
export const FETCH_USERS_NOTFOUND = "scm/users/FETCH_NOTFOUND";
|
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 = "scm/users/ADD";
|
||||||
export const ADD_USER_SUCCESS = "scm/users/ADD_SUCCESS";
|
export const ADD_USER_SUCCESS = "scm/users/ADD_SUCCESS";
|
||||||
export const ADD_USER_FAILURE = "scm/users/ADD_FAILURE";
|
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";
|
export const DELETE_USER_FAILURE = "scm/users/DELETE_FAILURE";
|
||||||
|
|
||||||
const USERS_URL = "users";
|
const USERS_URL = "users";
|
||||||
|
const USER_URL = "users/";
|
||||||
|
|
||||||
const CONTENT_TYPE_USER = "application/vnd.scmm-user+json;v=2";
|
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) {
|
function requestAddUser(user: User) {
|
||||||
return {
|
return {
|
||||||
type: ADD_USER,
|
type: ADD_USER,
|
||||||
@@ -258,7 +303,13 @@ export default function reducer(state: any = {}, action: any = {}) {
|
|||||||
error: null,
|
error: null,
|
||||||
entry: action.payload
|
entry: action.payload
|
||||||
});
|
});
|
||||||
|
case FETCH_USER:
|
||||||
|
return reduceUsersByNames(state, action.payload.name, {
|
||||||
|
loading: true,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
case FETCH_USERS_SUCCESS:
|
case FETCH_USERS_SUCCESS:
|
||||||
|
// return red(state, action.payload._embedded.users);
|
||||||
const users = action.payload._embedded.users;
|
const users = action.payload._embedded.users;
|
||||||
const userNames = users.map(user => user.name);
|
const userNames = users.map(user => user.name);
|
||||||
const usersByNames = extractUsersByNames(
|
const usersByNames = extractUsersByNames(
|
||||||
@@ -266,7 +317,6 @@ export default function reducer(state: any = {}, action: any = {}) {
|
|||||||
userNames,
|
userNames,
|
||||||
state.usersByNames
|
state.usersByNames
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
users: {
|
users: {
|
||||||
@@ -276,6 +326,21 @@ export default function reducer(state: any = {}, action: any = {}) {
|
|||||||
},
|
},
|
||||||
usersByNames
|
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 FETCH_USERS_FAILURE:
|
||||||
case DELETE_USER_FAILURE:
|
case DELETE_USER_FAILURE:
|
||||||
|
|||||||
Reference in New Issue
Block a user