[WIP] added multi select to grant access to users

This commit is contained in:
Sina Blattmann 2023-03-23 15:46:15 +01:00
parent bf63da1ffd
commit 7a0012c626
10 changed files with 208 additions and 62 deletions

View File

@ -20,7 +20,7 @@ export const InstallationContext =
fetchData: () => Promise.resolve(), fetchData: () => Promise.resolve(),
loading: false, loading: false,
setLoading: () => {}, setLoading: () => {},
setError: (value) => {}, setError: () => {},
}); });
const InstallationContextProvider = ({ children }: { children: ReactNode }) => { const InstallationContextProvider = ({ children }: { children: ReactNode }) => {
@ -36,7 +36,10 @@ const InstallationContextProvider = ({ children }: { children: ReactNode }) => {
setData(res.data); setData(res.data);
setLoading(false); setLoading(false);
}) })
.catch((err: AxiosError) => setError(err)); .catch((err: AxiosError) => {
setLoading(false);
setError(err);
});
}, []); }, []);
return ( return (

View File

@ -5,6 +5,7 @@ import { useParams } from "react-router-dom";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { I_Installation } from "../../util/types"; import { I_Installation } from "../../util/types";
import FolderForm from "./FolderForm"; import FolderForm from "./FolderForm";
import LocationForm from "./LocationForm";
const Folder = () => { const Folder = () => {
const { id } = useParams(); const { id } = useParams();
@ -31,6 +32,7 @@ const Folder = () => {
<> <>
<Box sx={{ py: 3 }}> <Box sx={{ py: 3 }}>
<FolderForm values={values} id={id} /> <FolderForm values={values} id={id} />
<LocationForm parentId={values.parentId} />
</Box> </Box>
</> </>
); );

View File

@ -1,4 +1,4 @@
import { Button, CircularProgress, Grid, InputLabel } from "@mui/material"; import { Button, CircularProgress, Grid } from "@mui/material";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -7,7 +7,6 @@ import { I_Folder } from "../../util/types";
import { GroupContext } from "../Context/GroupContextProvider"; 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";
interface I_CustomerFormProps { interface I_CustomerFormProps {
values: I_Folder; values: I_Folder;
@ -26,9 +25,6 @@ const FolderForm = (props: I_CustomerFormProps) => {
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>(
values.parentId
);
const formik = useFormik({ const formik = useFormik({
initialValues: { initialValues: {
@ -41,7 +37,6 @@ const FolderForm = (props: I_CustomerFormProps) => {
updateFolder({ updateFolder({
...values, ...values,
...formikValues, ...formikValues,
parentId: selectedParentId ?? values.parentId,
id: idAsNumber, id: idAsNumber,
}) })
.then((res) => { .then((res) => {
@ -59,52 +54,44 @@ const FolderForm = (props: I_CustomerFormProps) => {
}); });
return ( return (
<form onSubmit={formik.handleSubmit}> <>
<InnovenergyTextfield <form onSubmit={formik.handleSubmit}>
id="name-textfield" <InnovenergyTextfield
label={intl.formatMessage({ id="name-textfield"
id: "name", label={intl.formatMessage({
defaultMessage: "Name", id: "name",
})} defaultMessage: "Name",
name="name" })}
value={formik.values.name} name="name"
handleChange={formik.handleChange} value={formik.values.name}
/> handleChange={formik.handleChange}
<InnovenergyTextfield />
id="information-textfield" <InnovenergyTextfield
label={intl.formatMessage({ id="information-textfield"
id: "information", label={intl.formatMessage({
defaultMessage: "Information", id: "information",
})} defaultMessage: "Information",
name="information" })}
value={formik.values.information} name="information"
handleChange={formik.handleChange} value={formik.values.information}
/> handleChange={formik.handleChange}
<Grid container direction="row" alignItems="center" spacing={2}> />
<Grid item xs={3} alignItems="start"> <Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
<InputLabel style={{ marginBottom: "180px" }}> {loading && <CircularProgress />}
<FormattedMessage id="location" defaultMessage="Location" /> <Button variant="outlined" type="submit" sx={{ height: 40, ml: 2 }}>
</InputLabel> <FormattedMessage
id="applyChanges"
defaultMessage="Apply changes"
/>
</Button>
</Grid> </Grid>
<Grid item xs={9} display="inline"> <InnovenergySnackbar
<MoveTree error={error}
setSelectedParentId={setSelectedParentId} setOpen={setSnackbarOpen}
parentId={selectedParentId} open={snackbarOpen}
/> />
</Grid> </form>
</Grid> </>
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
{loading && <CircularProgress />}
<Button variant="outlined" type="submit" sx={{ height: 40, ml: 2 }}>
<FormattedMessage id="applyChanges" defaultMessage="Apply changes" />
</Button>
</Grid>
<InnovenergySnackbar
error={error}
setOpen={setSnackbarOpen}
open={snackbarOpen}
/>
</form>
); );
}; };

View File

@ -0,0 +1,59 @@
import { Button, Grid, InputLabel } from "@mui/material";
import { useContext, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useParams } from "react-router-dom";
import axiosConfig from "../../config/axiosConfig";
import { GroupContext } from "../Context/GroupContextProvider";
import MoveTree from "./Tree/MoveTree";
interface LocationFormProps {
parentId: number;
}
const LocationForm = (props: LocationFormProps) => {
const [selectedParentId, setSelectedParentId] = useState<number>(
props.parentId
);
const { fetchData, currentType } = useContext(GroupContext);
const { id } = useParams();
const handleMove = () => {
const route =
currentType === "Folder" ? "/MoveFolder" : "/MoveInstallation";
const paramsProp = currentType === "Folder" ? "folderId" : "installationId";
axiosConfig
.put(route, null, {
params: { [paramsProp]: id, parentId: selectedParentId },
})
.then((res) => {
fetchData();
});
};
return (
<Grid container direction="row" alignItems="center" spacing={2}>
<Grid item xs={3} alignItems="start">
<InputLabel style={{ marginBottom: "180px" }}>
<FormattedMessage id="location" defaultMessage="Location" />
</InputLabel>
</Grid>
<Grid item xs={9} display="inline">
<MoveTree
setSelectedParentId={setSelectedParentId}
parentId={selectedParentId}
/>
</Grid>
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
<Button
variant="outlined"
sx={{ height: 40, ml: 2 }}
onClick={handleMove}
>
<FormattedMessage id="move" defaultMessage="Move" />
</Button>
</Grid>
</Grid>
);
};
export default LocationForm;

View File

@ -0,0 +1,82 @@
import {
Autocomplete,
Button,
CircularProgress,
Grid,
TextField,
} from "@mui/material";
import { useContext, useEffect, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useParams } from "react-router-dom";
import axiosConfig from "../../../config/axiosConfig";
import { User } from "../../../util/user.util";
import { GroupContext } from "../../Context/GroupContextProvider";
interface AutoCompleteOption {
label: string;
id: number;
}
const AvailableUserList = () => {
const [users, setUsers] = useState<User[]>([]);
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
const { currentType } = useContext(GroupContext);
const { id } = useParams();
useEffect(() => {
axiosConfig.get("/GetAllChildUsers").then((res) => {
setUsers(res.data);
});
}, []);
const handleGrant = () => {
selectedUsers.forEach((user) => {
const bodyProp = currentType === "Folder" ? "folderId" : "installationId";
const elementId = id ? parseInt(id) : "";
axiosConfig
.post(
currentType === "Folder"
? "/GrantUserAccessToFolder"
: "/GrantUserAccessToInstallation",
{ userId: user.id, [bodyProp]: elementId }
)
.then((res) => {
console.log(res);
});
});
};
if (users) {
return (
<>
<Grid container sx={{ pt: 1 }}>
<Autocomplete
sx={{ width: "500px" }}
multiple
id="tags-standard"
options={users}
getOptionLabel={(option) => option.name}
renderInput={(params) => (
<TextField
{...params}
variant="outlined"
label="Grant access to user"
placeholder="User"
/>
)}
onChange={(event, values) => setSelectedUsers(values)}
/>
<Button
variant="outlined"
type="submit"
sx={{ height: 40, ml: 2 }}
onClick={handleGrant}
>
<FormattedMessage id="grantAccess" defaultMessage="Grant access" />
</Button>
</Grid>
</>
);
}
return null;
};
export default AvailableUserList;

View File

@ -1,13 +1,17 @@
import { Grid } from "@mui/material"; import { Grid } from "@mui/material";
import AvailableUserList from "./AvailableUserList";
import UsersWithDirectAccess from "./UsersWithDirectAccess"; import UsersWithDirectAccess from "./UsersWithDirectAccess";
import UsersWithInheritedAccess from "./UsersWithInheritedAccess"; import UsersWithInheritedAccess from "./UsersWithInheritedAccess";
const Users = () => { const Users = () => {
return ( return (
<Grid container sx={{ mt: 1 }}> <>
<UsersWithInheritedAccess /> <AvailableUserList />
<UsersWithDirectAccess /> <Grid container sx={{ mt: 1 }}>
</Grid> <UsersWithInheritedAccess />
<UsersWithDirectAccess />
</Grid>
</>
); );
}; };

View File

@ -65,7 +65,7 @@ const UsersWithInheritedAccess = () => {
</Typography> </Typography>
<InnovenergyList> <InnovenergyList>
{filterDuplicateUsers(users).map( {filterDuplicateUsers(users).map(
({ user }: UserWithInheritedAccess) => { ({ user, folderName }: UserWithInheritedAccess) => {
return ( return (
<Fragment key={user.id}> <Fragment key={user.id}>
<ListItem> <ListItem>
@ -82,7 +82,7 @@ const UsersWithInheritedAccess = () => {
<Link <Link
to={routes.groups + routes.users + user.parentId} to={routes.groups + routes.users + user.parentId}
> >
this folder {folderName}
</Link> </Link>
</> </>
} }

View File

@ -5,6 +5,7 @@ import { useParams } from "react-router-dom";
import CustomerForm from "./CustomerForm"; import CustomerForm from "./CustomerForm";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { I_Installation } from "../../util/types"; import { I_Installation } from "../../util/types";
import LocationForm from "../Groups/LocationForm";
const Installation = () => { const Installation = () => {
const { id } = useParams(); const { id } = useParams();
@ -30,6 +31,7 @@ const Installation = () => {
return ( return (
<Box sx={{ py: 3 }}> <Box sx={{ py: 3 }}>
<CustomerForm values={values} id={id} /> <CustomerForm values={values} id={id} />
<LocationForm parentId={values.parentId} />
</Box> </Box>
); );
} else if (loading) { } else if (loading) {

View File

@ -1,7 +1,7 @@
import List from "@mui/material/List"; import List from "@mui/material/List";
import ListItemButton from "@mui/material/ListItemButton"; import ListItemButton from "@mui/material/ListItemButton";
import ListItemText from "@mui/material/ListItemText"; import ListItemText from "@mui/material/ListItemText";
import { CircularProgress, Divider, Grid } from "@mui/material"; import { Alert, CircularProgress, Divider, Grid } from "@mui/material";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import routes from "../../routes.json"; import routes from "../../routes.json";
@ -57,8 +57,7 @@ const InstallationList = (props: InstallationListProps) => {
<CircularProgress sx={{ m: 6 }} /> <CircularProgress sx={{ m: 6 }} />
</Grid> </Grid>
); );
} } else if (data && data.length) {
if (data) {
return ( return (
<List <List
sx={{ sx={{
@ -96,6 +95,13 @@ const InstallationList = (props: InstallationListProps) => {
})} })}
</List> </List>
); );
} else if (error) {
console.log(error);
return (
<Alert severity="error" sx={{ mt: 1 }}>
{error.message}
</Alert>
);
} }
return null; return null;
}; };

View File

@ -13,5 +13,6 @@ export interface User {
export interface UserWithInheritedAccess { export interface UserWithInheritedAccess {
folderId: number; folderId: number;
folderName: string;
user: User; user: User;
} }