diff --git a/frontend/js/actions/polochon.js b/frontend/js/actions/polochon.js
new file mode 100644
index 0000000..acac051
--- /dev/null
+++ b/frontend/js/actions/polochon.js
@@ -0,0 +1,35 @@
+import { configureAxios, request } from "../requests"
+
+export const getPolochons = () => request(
+ "PUBLIC_POLOCHON_LIST_FETCH",
+ configureAxios().get("/polochons"),
+)
+
+export const getManagedPolochons = () => request(
+ "MANAGED_POLOCHON_LIST_FETCH",
+ configureAxios().get("/users/polochons"),
+)
+
+export const addPolochon = (params) => request(
+ "ADD_POLOCHON",
+ configureAxios().post("/polochons", params),
+ [
+ () => getManagedPolochons(),
+ ],
+)
+
+export const updatePolochon = ({ id, ...params }) => request(
+ "UPDATE_POLOCHON",
+ configureAxios().post(`/polochons/${id}`, params),
+ [
+ () => getManagedPolochons(),
+ ],
+)
+
+export const deletePolochon = (id) => request(
+ "UPDATE_POLOCHON",
+ configureAxios().delete(`/polochons/${id}`),
+ [
+ () => getManagedPolochons(),
+ ],
+)
diff --git a/frontend/js/components/forms/input.js b/frontend/js/components/forms/input.js
new file mode 100644
index 0000000..8da4c85
--- /dev/null
+++ b/frontend/js/components/forms/input.js
@@ -0,0 +1,22 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export const FormInput = ({ label, value, updateValue }) => {
+ return (
+
+
+ updateValue(e.target.value)}
+ />
+
+ )
+}
+FormInput.propTypes = {
+ label: PropTypes.string,
+ value: PropTypes.string,
+ updateValue: PropTypes.func,
+};
diff --git a/frontend/js/components/forms/modal.js b/frontend/js/components/forms/modal.js
new file mode 100644
index 0000000..26b3475
--- /dev/null
+++ b/frontend/js/components/forms/modal.js
@@ -0,0 +1,49 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+import { Modal } from "react-bootstrap"
+
+export const FormModal = ({
+ show,
+ setShow,
+ title,
+ icon,
+ handleSubmit,
+ children,
+}) => {
+ const submit = function(e) {
+ if (e) { e.preventDefault(); }
+ handleSubmit();
+ };
+
+ return (
+ setShow(false)}>
+
+
+
+ {title}
+
+
+
+
+
+
+ Apply
+ setShow(false)}>Close
+
+
+ )
+}
+FormModal.propTypes = {
+ show: PropTypes.bool,
+ setShow: PropTypes.func,
+ icon: PropTypes.string,
+ title: PropTypes.string,
+ handleSubmit: PropTypes.func,
+ children: PropTypes.oneOf(
+ PropTypes.object,
+ PropTypes.array,
+ ),
+};
diff --git a/frontend/js/components/polochons/add.js b/frontend/js/components/polochons/add.js
new file mode 100644
index 0000000..e8d41d8
--- /dev/null
+++ b/frontend/js/components/polochons/add.js
@@ -0,0 +1,31 @@
+import React, { useState } from "react"
+import PropTypes from "prop-types"
+import { connect } from "react-redux"
+
+import { addPolochon } from "../../actions/polochon"
+
+import { PolochonEdit } from "./edit"
+
+export const PolochonAddConnected = ({ addPolochon }) => {
+ const [modal, setModal] = useState(false);
+
+ return (
+
+ setModal(true)}>
+
+ Add new polochon
+
+
+
+
+ )
+}
+PolochonAddConnected.propTypes = {
+ addPolochon: PropTypes.func,
+};
+
+export const PolochonAdd = connect(null, {addPolochon})(PolochonAddConnected);
diff --git a/frontend/js/components/polochons/edit.js b/frontend/js/components/polochons/edit.js
new file mode 100644
index 0000000..d740c7b
--- /dev/null
+++ b/frontend/js/components/polochons/edit.js
@@ -0,0 +1,59 @@
+import React, { useState, useEffect } from "react"
+import PropTypes from "prop-types"
+
+import { FormModal } from "../forms/modal"
+import { FormInput } from "../forms/input"
+
+export const PolochonEdit = ({
+ show,
+ setShow,
+ id,
+ initialName,
+ initialUrl,
+ initialToken,
+ update,
+}) => {
+ const [name, setName] = useState(initialName);
+ const [url, setUrl] = useState(initialUrl);
+ const [token, setToken] = useState(initialToken);
+
+ useEffect(() => {
+ setName(initialName);
+ setUrl(initialUrl);
+ setToken(initialToken);
+ }, [id, initialName, initialUrl, initialToken])
+
+ const handleSubmit = () => {
+ update({ id, name, url, token });
+ setShow(false);
+ };
+
+ return (
+
+
+
+
+
+ )
+}
+PolochonEdit.propTypes = {
+ show: PropTypes.bool,
+ setShow: PropTypes.func,
+ update: PropTypes.func,
+ id: PropTypes.string,
+ initialName: PropTypes.string,
+ initialUrl: PropTypes.string,
+ initialToken: PropTypes.string,
+};
+PolochonEdit.defaultProps = {
+ id: "",
+ initialName: "",
+ initialUrl: "",
+ initialToken: "",
+};
diff --git a/frontend/js/components/polochons/list.js b/frontend/js/components/polochons/list.js
new file mode 100644
index 0000000..22474fe
--- /dev/null
+++ b/frontend/js/components/polochons/list.js
@@ -0,0 +1,56 @@
+import React, { useEffect } from "react"
+import PropTypes from "prop-types"
+import { connect } from "react-redux"
+import { List } from "immutable"
+
+import { getManagedPolochons } from "../../actions/polochon"
+
+import { Polochon } from "./polochon"
+import { PolochonAdd } from "./add"
+
+const mapStateToProps = (state) => ({
+ managedList: state.polochon.get("managed"),
+});
+
+const mapDispatchToProps = {
+ getManagedPolochons,
+}
+
+const PolochonListConnected = ({
+ getManagedPolochons,
+ managedList,
+}) => {
+
+ useEffect(() => {
+ getManagedPolochons();
+ }, [getManagedPolochons])
+
+ return (
+
+
+
My polochons
+
+
+ {managedList.map((el, index) => (
+
+ ))}
+
+
+
+
+ )
+}
+PolochonListConnected.propTypes = {
+ getManagedPolochons: PropTypes.func,
+ managedList: PropTypes.instanceOf(List),
+};
+
+export const PolochonList = connect(mapStateToProps, mapDispatchToProps)(PolochonListConnected);
diff --git a/frontend/js/components/polochons/polochon.js b/frontend/js/components/polochons/polochon.js
new file mode 100644
index 0000000..6e86c00
--- /dev/null
+++ b/frontend/js/components/polochons/polochon.js
@@ -0,0 +1,83 @@
+import React, { useState } from "react"
+import PropTypes from "prop-types"
+import { List } from "immutable"
+import { connect } from "react-redux"
+
+import { PolochonUser } from "./user"
+import { PolochonEdit } from "./edit"
+
+import { updatePolochon, deletePolochon } from "../../actions/polochon"
+
+export const PolochonConnected = ({
+ id,
+ name,
+ token,
+ url,
+ authToken,
+ users,
+ updatePolochon,
+ deletePolochon,
+}) => {
+ const [edit, setEdit] = useState(false);
+
+ return (
+
+
+
+ {name !== "" ? name : "-"}
+
+ ({url !== "" ? url : "-"})
+
+
+ setEdit(true)}
+ />
+ deletePolochon(id)}
+ />
+
+
+
+
ID: {id}
+
Egress token: {token}
+
Ingress token: {authToken}
+
+ Users:
+ {users.map((user, index) => (
+
+ ))}
+
+
+
+
+
+
+ )
+}
+PolochonConnected.propTypes = {
+ id: PropTypes.string,
+ name: PropTypes.string,
+ token: PropTypes.string,
+ url: PropTypes.string,
+ authToken: PropTypes.string,
+ users: PropTypes.instanceOf(List),
+ updatePolochon: PropTypes.func,
+ deletePolochon: PropTypes.func,
+};
+
+export const Polochon = connect(null, { updatePolochon, deletePolochon })(PolochonConnected);
diff --git a/frontend/js/components/polochons/user.js b/frontend/js/components/polochons/user.js
new file mode 100644
index 0000000..4ed207b
--- /dev/null
+++ b/frontend/js/components/polochons/user.js
@@ -0,0 +1,14 @@
+import React from "react"
+import PropTypes from "prop-types"
+
+export const PolochonUser = ({ id, name }) => {
+ return (
+
+ {name} ({id})
+
+ )
+}
+PolochonUser.propTypes = {
+ id: PropTypes.string,
+ name: PropTypes.string,
+};
diff --git a/frontend/js/components/users/profile.js b/frontend/js/components/users/profile.js
index 8905590..207780c 100644
--- a/frontend/js/components/users/profile.js
+++ b/frontend/js/components/users/profile.js
@@ -4,6 +4,8 @@ import { connect } from "react-redux"
import Loader from "../loader/loader"
import { Map } from "immutable"
+import { PolochonList } from "../polochons/list"
+
import {
updateUser, getUserInfos,
getUserTokens, getUserModules
@@ -37,6 +39,7 @@ const UserProfile = (props) => {
url={props.url}
updateUser={props.updateUser}
/>
+
state.set("loadingPublic", true),
+ "PUBLIC_POLOCHON_LIST_FETCH_FULFILLED": (state, action) => {
+ return state.merge({
+ loadingPublic: false,
+ public: List(fromJS(action.payload.response.data)),
+ });
+ },
+ "MANAGED_POLOCHON_LIST_FETCH_PENDING": state => state.set("loadingManaged", true),
+ "MANAGED_POLOCHON_LIST_FETCH_FULFILLED": (state, action) => {
+ return state.merge({
+ loadingManaged: false,
+ managed: List(fromJS(action.payload.response.data)),
+ });
+ },
+}
+
+export default (state = defaultState, action) =>
+ handlers[action.type] ? handlers[action.type](state, action) : state;
diff --git a/frontend/js/reducers/users.js b/frontend/js/reducers/users.js
index 0b7cad6..557f27c 100644
--- a/frontend/js/reducers/users.js
+++ b/frontend/js/reducers/users.js
@@ -13,6 +13,8 @@ const defaultState = Map({
isLogged: false,
polochonToken: "",
polochonUrl: "",
+ polochonName: "",
+ polochonActivated: false,
tokens: List(),
modules: Map(),
modulesLoading: false,
@@ -45,6 +47,8 @@ const handlers = {
"GET_USER_FULFILLED": (state, action) => state.merge(Map({
polochonToken: action.payload.response.data.token,
polochonUrl: action.payload.response.data.url,
+ polochonName: action.payload.response.data.name,
+ polochonActivated: action.payload.response.data.activated,
loading: false,
})),
"GET_USER_TOKENS_PENDING": state => state.set("loading", true),