[WIP] added multi select to grant access to users
This commit is contained in:
parent
bf63da1ffd
commit
7a0012c626
|
@ -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 (
|
||||||
|
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,5 +13,6 @@ export interface User {
|
||||||
|
|
||||||
export interface UserWithInheritedAccess {
|
export interface UserWithInheritedAccess {
|
||||||
folderId: number;
|
folderId: number;
|
||||||
|
folderName: string;
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue