[WIP] add Users tab to Groups
This commit is contained in:
parent
9cb29ef099
commit
5d801ab36b
|
@ -50,7 +50,6 @@ const GroupContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
value={{
|
value={{
|
||||||
currentType,
|
currentType,
|
||||||
setCurrentType,
|
setCurrentType,
|
||||||
|
|
||||||
data,
|
data,
|
||||||
setData,
|
setData,
|
||||||
fetchData,
|
fetchData,
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Button, CircularProgress, Grid, InputLabel } from "@mui/material";
|
import { Button, CircularProgress, Grid, InputLabel } from "@mui/material";
|
||||||
import { useFormik } from "formik";
|
import { useFormik } from "formik";
|
||||||
import { useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import axiosConfig from "../../config/axiosConfig";
|
import axiosConfig from "../../config/axiosConfig";
|
||||||
import { I_Folder } from "../../util/types";
|
import { I_Folder } from "../../util/types";
|
||||||
|
import { GroupContext } from "../Context/GroupContextProvider";
|
||||||
import InnovenergySnackbar from "../InnovenergySnackbar";
|
import InnovenergySnackbar from "../InnovenergySnackbar";
|
||||||
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
|
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
|
||||||
import MoveTree from "./Tree/MoveTree";
|
import MoveTree from "./Tree/MoveTree";
|
||||||
|
@ -20,11 +21,14 @@ const updateFolder = (data: I_Folder) => {
|
||||||
const FolderForm = (props: I_CustomerFormProps) => {
|
const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
const { values, id } = props;
|
const { values, id } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { fetchData } = useContext(GroupContext);
|
||||||
|
|
||||||
const [snackbarOpen, setSnackbarOpen] = useState(false);
|
const [snackbarOpen, setSnackbarOpen] = useState(false);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [selectedParentId, setSelectedParentId] = useState<number>();
|
const [selectedParentId, setSelectedParentId] = useState<number>(
|
||||||
|
values.parentId
|
||||||
|
);
|
||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
|
@ -41,6 +45,8 @@ const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
id: idAsNumber,
|
id: idAsNumber,
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
// TODO figure out why this isnt refreshing tree
|
||||||
|
fetchData();
|
||||||
setSnackbarOpen(true);
|
setSnackbarOpen(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
|
@ -81,7 +87,10 @@ const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
</InputLabel>
|
</InputLabel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={9} display="inline">
|
<Grid item xs={9} display="inline">
|
||||||
<MoveTree setSelectedParentId={setSelectedParentId} />
|
<MoveTree
|
||||||
|
setSelectedParentId={setSelectedParentId}
|
||||||
|
parentId={selectedParentId}
|
||||||
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import GroupTabs from "./GroupTabs";
|
||||||
import GroupContextProvider from "../Context/GroupContextProvider";
|
import GroupContextProvider from "../Context/GroupContextProvider";
|
||||||
import GroupTree from "./Tree/GroupTree";
|
import GroupTree from "./Tree/GroupTree";
|
||||||
import NavigationButtons from "../Layout/NavigationButtons";
|
import NavigationButtons from "../Layout/NavigationButtons";
|
||||||
|
import Users from "./Users/Users";
|
||||||
|
|
||||||
const Groups = () => {
|
const Groups = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -22,7 +23,7 @@ const Groups = () => {
|
||||||
<GroupTabs />
|
<GroupTabs />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={routes.folder + ":id"} element={<Folder />} index />
|
<Route path={routes.folder + ":id"} element={<Folder />} index />
|
||||||
<Route path={routes.users + ":id"} element={<div>Users</div>} />
|
<Route path={routes.users + ":id"} element={<Users />} />
|
||||||
<Route
|
<Route
|
||||||
path={routes.installation + ":id"}
|
path={routes.installation + ":id"}
|
||||||
element={<Installation />}
|
element={<Installation />}
|
||||||
|
|
|
@ -1,21 +1,32 @@
|
||||||
import TreeView from "@mui/lab/TreeView";
|
import TreeView from "@mui/lab/TreeView";
|
||||||
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||||
import { ReactNode, useContext, useEffect } from "react";
|
import { ReactNode, useContext, useEffect, useState } from "react";
|
||||||
import { TreeItem } from "@mui/lab";
|
import { TreeItem } from "@mui/lab";
|
||||||
import { I_Folder, I_Installation } from "../../../util/types";
|
import { I_Folder, I_Installation } from "../../../util/types";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import routes from "../../../routes.json";
|
import routes from "../../../routes.json";
|
||||||
import { GroupContext } from "../../Context/GroupContextProvider";
|
import { GroupContext } from "../../Context/GroupContextProvider";
|
||||||
import { instanceOfFolder } from "../../../util/group.util";
|
import { instanceOfFolder } from "../../../util/group.util";
|
||||||
|
import { Grid, CircularProgress } from "@mui/material";
|
||||||
|
|
||||||
const GroupTree = () => {
|
const GroupTree = () => {
|
||||||
const { setCurrentType, fetchData, data } = useContext(GroupContext);
|
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext);
|
||||||
|
const [openNodes, setOpenNodes] = useState<string[]>([]);
|
||||||
|
const [selected, setSelected] = useState<string>("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchData();
|
fetchData();
|
||||||
}, [fetchData]);
|
}, [fetchData]);
|
||||||
|
|
||||||
|
/* useEffect(() => {
|
||||||
|
if (id) {
|
||||||
|
setSelected(
|
||||||
|
currentType === "Folder" ? "Folder" + id : "Installation" + id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [id, currentType]); */
|
||||||
|
|
||||||
const getNodes = (element: I_Folder | I_Installation): null | ReactNode => {
|
const getNodes = (element: I_Folder | I_Installation): null | ReactNode => {
|
||||||
if (instanceOfFolder(element)) {
|
if (instanceOfFolder(element)) {
|
||||||
return element.children ? renderTree(element.children) : null;
|
return element.children ? renderTree(element.children) : null;
|
||||||
|
@ -40,8 +51,8 @@ const GroupTree = () => {
|
||||||
draggable={false}
|
draggable={false}
|
||||||
>
|
>
|
||||||
<TreeItem
|
<TreeItem
|
||||||
key={element.id}
|
key={element.type + element.id}
|
||||||
nodeId={element.id.toString()}
|
nodeId={element.type + element.id}
|
||||||
label={element.name}
|
label={element.name}
|
||||||
onClick={() => setCurrentType(element.type)}
|
onClick={() => setCurrentType(element.type)}
|
||||||
>
|
>
|
||||||
|
@ -51,6 +62,13 @@ const GroupTree = () => {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Grid container justifyContent="center" width="100%">
|
||||||
|
<CircularProgress />
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
return (
|
return (
|
||||||
<TreeView
|
<TreeView
|
||||||
|
@ -58,6 +76,12 @@ const GroupTree = () => {
|
||||||
defaultCollapseIcon={<ExpandMoreIcon />}
|
defaultCollapseIcon={<ExpandMoreIcon />}
|
||||||
defaultExpandIcon={<ChevronRightIcon />}
|
defaultExpandIcon={<ChevronRightIcon />}
|
||||||
sx={{ height: 300, flexGrow: 1, maxWidth: 400 }}
|
sx={{ height: 300, flexGrow: 1, maxWidth: 400 }}
|
||||||
|
expanded={openNodes}
|
||||||
|
onNodeToggle={(e, ids) => {
|
||||||
|
setOpenNodes(ids);
|
||||||
|
}}
|
||||||
|
onNodeSelect={(e: any, nodeId: string) => setSelected(nodeId)}
|
||||||
|
selected={selected}
|
||||||
>
|
>
|
||||||
{renderTree(data)}
|
{renderTree(data)}
|
||||||
</TreeView>
|
</TreeView>
|
||||||
|
|
|
@ -7,11 +7,12 @@ import { I_Folder, I_Installation } from "../../../util/types";
|
||||||
import { GroupContext } from "../../Context/GroupContextProvider";
|
import { GroupContext } from "../../Context/GroupContextProvider";
|
||||||
import { instanceOfFolder } from "../../../util/group.util";
|
import { instanceOfFolder } from "../../../util/group.util";
|
||||||
|
|
||||||
interface GroupTreeProps {
|
interface MoveTreeProps {
|
||||||
setSelectedParentId: (value: number) => void;
|
setSelectedParentId: (value: number) => void;
|
||||||
|
parentId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GroupTree = (props: GroupTreeProps) => {
|
const MoveTree = (props: MoveTreeProps) => {
|
||||||
const { data } = useContext(GroupContext);
|
const { data } = useContext(GroupContext);
|
||||||
|
|
||||||
const getNodes = (element: I_Folder | I_Installation): null | ReactNode => {
|
const getNodes = (element: I_Folder | I_Installation): null | ReactNode => {
|
||||||
|
@ -50,9 +51,10 @@ const GroupTree = (props: GroupTreeProps) => {
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
overflowX: "hidden",
|
overflowX: "hidden",
|
||||||
}}
|
}}
|
||||||
onNodeSelect={(e: any, id: string) =>
|
onNodeSelect={(e: any, id: string) => {
|
||||||
props.setSelectedParentId(parseInt(id))
|
props.setSelectedParentId(parseInt(id));
|
||||||
}
|
}}
|
||||||
|
selected={props.parentId.toString()}
|
||||||
>
|
>
|
||||||
{renderTree(data)}
|
{renderTree(data)}
|
||||||
</TreeView>
|
</TreeView>
|
||||||
|
@ -61,4 +63,4 @@ const GroupTree = (props: GroupTreeProps) => {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GroupTree;
|
export default MoveTree;
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
import List from "@mui/material/List";
|
||||||
|
import ListItemText from "@mui/material/ListItemText";
|
||||||
|
import { CircularProgress, Divider, Grid, ListItemIcon } from "@mui/material";
|
||||||
|
import { Fragment, useContext, useEffect, useState } from "react";
|
||||||
|
import axiosConfig from "../../../config/axiosConfig";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import ListItem from "@mui/material/ListItem";
|
||||||
|
import GroupRemoveIcon from "@mui/icons-material/GroupRemove";
|
||||||
|
import { User } from "../../../util/user.util";
|
||||||
|
import { GroupContext } from "../../Context/GroupContextProvider";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import routes from "../../../routes.json";
|
||||||
|
|
||||||
|
const InstallationList = () => {
|
||||||
|
const [data, setData] = useState<any>();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const { id } = useParams();
|
||||||
|
const { currentType } = useContext(GroupContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
axiosConfig
|
||||||
|
.get(
|
||||||
|
currentType === "Folder"
|
||||||
|
? "/GetUsersWithAccessToFolder"
|
||||||
|
: "/GetUsersWithAccessToInstallation",
|
||||||
|
{ params: { id } }
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
// TODO temp solution
|
||||||
|
const mappedData = res.data
|
||||||
|
.filter((element: any) => element.user)
|
||||||
|
.map((element: any) => element.user);
|
||||||
|
console.log(mappedData);
|
||||||
|
setData(mappedData);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [currentType, id]);
|
||||||
|
|
||||||
|
const filterDuplicateUsers = (data: any[]) => {
|
||||||
|
return data.reduce((prev: User[], curr: User) => {
|
||||||
|
const foundUser = prev.find((el) => el.id === curr.id);
|
||||||
|
if (foundUser) {
|
||||||
|
const prevIds = foundUser.folderIds ? foundUser.folderIds : [];
|
||||||
|
foundUser.folderIds = [...prevIds, curr.parentId];
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
curr.folderIds = [curr.parentId];
|
||||||
|
prev.push(curr);
|
||||||
|
return prev;
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<Grid container justifyContent="center" width="100%">
|
||||||
|
<CircularProgress sx={{ m: 6 }} />
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
return (
|
||||||
|
<List
|
||||||
|
sx={{
|
||||||
|
bgcolor: "background.paper",
|
||||||
|
position: "relative",
|
||||||
|
width: 500,
|
||||||
|
}}
|
||||||
|
component="nav"
|
||||||
|
aria-labelledby="nested-list-subheader"
|
||||||
|
>
|
||||||
|
{filterDuplicateUsers(data).map((user: User) => {
|
||||||
|
return (
|
||||||
|
<Fragment key={user.id}>
|
||||||
|
<ListItem>
|
||||||
|
<ListItemText
|
||||||
|
primary={user.name}
|
||||||
|
secondary={
|
||||||
|
<>
|
||||||
|
Inherited access from{" "}
|
||||||
|
<Link to={routes.groups + routes.users + user.parentId}>
|
||||||
|
this folder
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
<Divider />
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InstallationList;
|
|
@ -0,0 +1,12 @@
|
||||||
|
export interface User {
|
||||||
|
email: string;
|
||||||
|
hasWriteAccess: boolean;
|
||||||
|
id: number;
|
||||||
|
information: string;
|
||||||
|
language: string;
|
||||||
|
name: string;
|
||||||
|
parentId: number;
|
||||||
|
password: number;
|
||||||
|
type: string;
|
||||||
|
folderIds?: number[];
|
||||||
|
}
|
Loading…
Reference in New Issue