Allow polochon admin to edit the user's config

This commit is contained in:
Grégoire Delattre 2019-07-10 14:42:33 +02:00
parent d1af1d3437
commit 360363c0ae
11 changed files with 176 additions and 47 deletions

View File

@ -1,5 +1,7 @@
import { configureAxios, request } from "../requests" import { configureAxios, request } from "../requests"
import { getUserInfos } from "./users"
export const getPolochons = () => request( export const getPolochons = () => request(
"PUBLIC_POLOCHON_LIST_FETCH", "PUBLIC_POLOCHON_LIST_FETCH",
configureAxios().get("/polochons"), configureAxios().get("/polochons"),
@ -36,3 +38,13 @@ export const deletePolochon = (id) => request(
() => getManagedPolochons(), () => getManagedPolochons(),
], ],
) )
export const editPolochonUser = ({ polochonId, id, ...params }) => request(
"EDIT_POLOCHON_USER",
configureAxios().post(`/polochons/${polochonId}/users/${id}`, params),
[
() => getPolochons(),
() => getManagedPolochons(),
() => getUserInfos(),
],
)

View File

@ -2,6 +2,8 @@ import { configureAxios, request } from "../requests"
import { addAlertOk } from "./alerts" import { addAlertOk } from "./alerts"
import { getManagedPolochons } from "./polochon"
export function userLogout() { export function userLogout() {
return { return {
type: "USER_LOGOUT", type: "USER_LOGOUT",
@ -27,6 +29,7 @@ export function updateUser(config) {
configureAxios().post("/users/edit", config), configureAxios().post("/users/edit", config),
[ [
addAlertOk("User updated"), addAlertOk("User updated"),
() => getManagedPolochons(),
], ],
) )
} }

View File

@ -31,7 +31,7 @@ export const FormModal = ({
</Modal.Body> </Modal.Body>
<Modal.Footer> <Modal.Footer>
<div className="btn btn-success" onClick={submit}>Apply</div> <div className="btn btn-success" onClick={submit}>Apply</div>
<div className="btn btn-error" onClick={() => setShow(false)}>Close</div> <div className="btn btn-danger" onClick={() => setShow(false)}>Close</div>
</Modal.Footer> </Modal.Footer>
</Modal> </Modal>
) )

View File

@ -11,12 +11,14 @@ export const PolochonAddConnected = ({ addPolochon }) => {
return ( return (
<React.Fragment> <React.Fragment>
<div className="btn btn-primary btn-lg" onClick={() => setModal(true)}> <div className="btn btn-primary" onClick={() => setModal(true)}>
<i className="fa fa-plus mr-2" /> <i className="fa fa-plus mr-2" />
Add new polochon Add new polochon
</div> </div>
<PolochonEdit <PolochonEdit
title="Add a new polochon"
icon="plus"
show={modal} show={modal}
setShow={setModal} setShow={setModal}
update={addPolochon} update={addPolochon}

View File

@ -8,6 +8,8 @@ export const PolochonEdit = ({
show, show,
setShow, setShow,
id, id,
title,
icon,
initialName, initialName,
initialUrl, initialUrl,
initialToken, initialToken,
@ -32,8 +34,8 @@ export const PolochonEdit = ({
<FormModal <FormModal
show={show} show={show}
setShow={setShow} setShow={setShow}
title="Add a new polochon" title={title}
icon="plus" icon={icon}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
> >
<FormInput label="Name" value={name} updateValue={setName} /> <FormInput label="Name" value={name} updateValue={setName} />
@ -44,6 +46,8 @@ export const PolochonEdit = ({
} }
PolochonEdit.propTypes = { PolochonEdit.propTypes = {
show: PropTypes.bool, show: PropTypes.bool,
title: PropTypes.string,
icon: PropTypes.string,
setShow: PropTypes.func, setShow: PropTypes.func,
update: PropTypes.func, update: PropTypes.func,
id: PropTypes.string, id: PropTypes.string,
@ -53,6 +57,8 @@ PolochonEdit.propTypes = {
}; };
PolochonEdit.defaultProps = { PolochonEdit.defaultProps = {
id: "", id: "",
title: "Edit",
icon: "edit",
initialName: "", initialName: "",
initialUrl: "", initialUrl: "",
initialToken: "", initialToken: "",

View File

@ -27,7 +27,7 @@ const PolochonListConnected = ({
return ( return (
<div className="row mb-3"> <div className="row mb-3">
<div className="col-12 col-md-6 offset-md-3"> <div className="col-12 col-md-8 offset-md-2">
<h2>My polochons</h2> <h2>My polochons</h2>
<hr /> <hr />
<span> <span>

View File

@ -3,7 +3,7 @@ import PropTypes from "prop-types"
import { List } from "immutable" import { List } from "immutable"
import { connect } from "react-redux" import { connect } from "react-redux"
import { PolochonUser } from "./user" import { PolochonUsers } from "./users"
import { PolochonEdit } from "./edit" import { PolochonEdit } from "./edit"
import { updatePolochon, deletePolochon } from "../../actions/polochon" import { updatePolochon, deletePolochon } from "../../actions/polochon"
@ -43,20 +43,12 @@ export const PolochonConnected = ({
<p className="card-text">ID: {id}</p> <p className="card-text">ID: {id}</p>
<p className="card-text">Egress token: {token}</p> <p className="card-text">Egress token: {token}</p>
<p className="card-text">Ingress token: {authToken}</p> <p className="card-text">Ingress token: {authToken}</p>
<p className="card-text"> <PolochonUsers id={id} users={users} />
Users:
{users.map((user, index) => (
<PolochonUser
key={index}
id={user.get("id")}
name={user.get("name")}
/>
))}
</p>
</div> </div>
</div> </div>
<PolochonEdit <PolochonEdit
title="Polochon config"
show={edit} show={edit}
setShow={setEdit} setShow={setEdit}
update={updatePolochon} update={updatePolochon}
@ -64,7 +56,6 @@ export const PolochonConnected = ({
initialName={name} initialName={name}
initialUrl={url} initialUrl={url}
initialToken={token} initialToken={token}
initialAuthToken={authToken}
/> />
</React.Fragment> </React.Fragment>
) )

View File

@ -0,0 +1,30 @@
import React from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
export const PolochonSelect = ({
value,
changeValue,
polochonList,
}) => {
return (
<select
className="form-control"
value={value}
onChange={(e) => changeValue(e.target.options[e.target.selectedIndex].value)}
>
{polochonList.map((el, index) => (
<option
value={el.get("id")}
key={index}>
{el.get("name")} ({el.get("url")})
</option>
))}
</select>
);
}
PolochonSelect.propTypes = {
value: PropTypes.string,
changeValue: PropTypes.func,
polochonList: PropTypes.instanceOf(List),
};

View File

@ -1,14 +1,82 @@
import React from "react" import React, { useState, useEffect } from "react"
import PropTypes from "prop-types" import PropTypes from "prop-types"
import { connect } from "react-redux"
import { editPolochonUser } from "../../actions/polochon"
import Toggle from "react-bootstrap-toggle";
import { FormModal } from "../forms/modal"
import { FormInput } from "../forms/input"
export const PolochonUserConnected = ({
polochonId,
id,
name,
initialToken,
initialActivated,
editPolochonUser,
}) => {
const [edit, setEdit] = useState(false);
const [token, setToken] = useState(initialToken);
const [activated, setActivated] = useState(initialActivated);
useEffect(() => {
setActivated(initialActivated);
setToken(initialToken);
}, [initialActivated, initialToken])
const handleSubmit = () => {
editPolochonUser({
polochonId,
id,
token,
activated,
});
setEdit(false);
}
export const PolochonUser = ({ id, name }) => {
return ( return (
<span> <tr>
{name} ({id}) <td>
</span> {name}
</td>
<td>
{activated ? "Activated" : "Not activated"}
</td>
<td>
<i className="fa fa-edit ml-2" onClick={() => setEdit(true)} />
<FormModal
show={edit}
setShow={setEdit}
title="Edit polochon's user"
icon="edit"
handleSubmit={handleSubmit}
>
<FormInput label="Token" value={token} updateValue={setToken} />
<div className="form-group">
<label>Activated</label>
<Toggle
className="pull-right"
on="yes"
off="no"
active={activated}
offstyle="info"
handlestyle="secondary"
onClick={() => setActivated(!activated)} />
</div>
</FormModal>
</td>
</tr>
) )
} }
PolochonUser.propTypes = { PolochonUserConnected.propTypes = {
polochonId: PropTypes.string,
id: PropTypes.string, id: PropTypes.string,
name: PropTypes.string, name: PropTypes.string,
initialToken: PropTypes.string,
initialActivated: PropTypes.bool,
editPolochonUser: PropTypes.func,
}; };
export const PolochonUser = connect(null, {editPolochonUser})(PolochonUserConnected);

View File

@ -0,0 +1,37 @@
import React from "react"
import PropTypes from "prop-types"
import { List } from "immutable"
import { PolochonUser } from "./user"
export const PolochonUsers = ({ id, users }) => {
if (users === null || users.size === 0) { return null }
return (
<table className="table border border-light table-dark">
<thead className="thead-dark">
<tr>
<th scope="col">User</th>
<th scope="col">Status</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
{users.map((user, index) => (
<PolochonUser
key={index}
polochonId={id}
id={user.get("id")}
name={user.get("name")}
initialToken={user.get("token")}
initialActivated={user.get("polochon_activated")}
/>
))}
</tbody>
</table>
)
}
PolochonUsers.propTypes = {
id: PropTypes.string,
users: PropTypes.instanceOf(List),
};

View File

@ -7,13 +7,12 @@ import { List } from "immutable"
import { getUserInfos, updateUser } from "../../actions/users" import { getUserInfos, updateUser } from "../../actions/users"
import { getPolochons } from "../../actions/polochon" import { getPolochons } from "../../actions/polochon"
import { FormInput } from "../forms/input" import { PolochonSelect } from "../polochons/select"
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
loading: state.userStore.get("loading"), loading: state.userStore.get("loading"),
publicPolochons: state.polochon.get("public"), publicPolochons: state.polochon.get("public"),
polochonId: state.userStore.get("polochonId"), polochonId: state.userStore.get("polochonId"),
polochonToken: state.userStore.get("polochonToken"),
polochonActivated: state.userStore.get("polochonActivated"), polochonActivated: state.userStore.get("polochonActivated"),
}); });
@ -24,7 +23,6 @@ const mapDispatchToProps = {
const UserEditConnect = ({ const UserEditConnect = ({
loading, loading,
polochonId, polochonId,
polochonToken,
polochonActivated, polochonActivated,
updateUser, updateUser,
getPolochons, getPolochons,
@ -32,7 +30,6 @@ const UserEditConnect = ({
publicPolochons, publicPolochons,
}) => { }) => {
const [id, setId] = useState(polochonId); const [id, setId] = useState(polochonId);
const [token, setToken] = useState(polochonToken);
const [password, setPassword] = useState(""); const [password, setPassword] = useState("");
const [passwordConfirm, setPasswordConfirm] = useState(""); const [passwordConfirm, setPasswordConfirm] = useState("");
@ -43,8 +40,7 @@ const UserEditConnect = ({
useEffect(() => { useEffect(() => {
setId(polochonId); setId(polochonId);
setToken(polochonToken); }, [polochonId])
}, [polochonToken, polochonId])
const handleSubmit = (ev) => { const handleSubmit = (ev) => {
ev.preventDefault(); ev.preventDefault();
@ -52,7 +48,6 @@ const UserEditConnect = ({
"password": password, "password": password,
"password_confirm": passwordConfirm, "password_confirm": passwordConfirm,
"polochon_id": id, "polochon_id": id,
"polochon_token": token,
}); });
} }
@ -60,7 +55,7 @@ const UserEditConnect = ({
return ( return (
<div className="row mb-3"> <div className="row mb-3">
<div className="col-12 col-md-6 offset-md-3"> <div className="col-12 col-md-8 offset-md-2">
<h2>Edit user</h2> <h2>Edit user</h2>
<hr /> <hr />
<form className="form-horizontal" onSubmit={(ev) => handleSubmit(ev)}> <form className="form-horizontal" onSubmit={(ev) => handleSubmit(ev)}>
@ -71,23 +66,9 @@ const UserEditConnect = ({
<span className="ml-1 text text-primary">(Needs activation from admin)</span> <span className="ml-1 text text-primary">(Needs activation from admin)</span>
} }
</label> </label>
<select <PolochonSelect value={id} changeValue={setId} polochonList={publicPolochons} />
className="form-control"
value={id}
onChange={(e) => setId(e.target.options[e.target.selectedIndex].value)}
>
{publicPolochons.map((el, index) => (
<option
value={el.get("id")}
key={index}>
{el.get("name")} ({el.get("url")})
</option>
))}
</select>
</div> </div>
<FormInput label="token" value={token} updateValue={setToken} />
<hr /> <hr />
<div className="form-group"> <div className="form-group">
@ -123,7 +104,6 @@ const UserEditConnect = ({
UserEditConnect.propTypes = { UserEditConnect.propTypes = {
loading: PropTypes.bool.isRequired, loading: PropTypes.bool.isRequired,
polochonId: PropTypes.string, polochonId: PropTypes.string,
polochonToken: PropTypes.string,
polochonActivated: PropTypes.bool, polochonActivated: PropTypes.bool,
updateUser: PropTypes.func, updateUser: PropTypes.func,
getPolochons: PropTypes.func, getPolochons: PropTypes.func,