Groups UI revision (#1959)
Co-authored-by: Prakash Senthil Vel <23444145+prakashsvmx@users.noreply.github.com>
This commit is contained in:
@@ -739,7 +739,6 @@ const TableWrapper = ({
|
||||
)}
|
||||
{hasOptions && (
|
||||
<Column
|
||||
headerRenderer={() => <Fragment>Options</Fragment>}
|
||||
dataKey={idField}
|
||||
width={optionsWidth}
|
||||
headerClassName="optionsAlignment"
|
||||
|
||||
@@ -24,45 +24,51 @@ import useApi from "../Common/Hooks/useApi";
|
||||
import { ConfirmDeleteIcon } from "../../../icons";
|
||||
|
||||
interface IDeleteGroup {
|
||||
selectedGroup: string;
|
||||
selectedGroups: string[];
|
||||
deleteOpen: boolean;
|
||||
closeDeleteModalAndRefresh: any;
|
||||
setErrorSnackMessage: typeof setErrorSnackMessage;
|
||||
}
|
||||
|
||||
const DeleteGroup = ({
|
||||
selectedGroup,
|
||||
selectedGroups,
|
||||
deleteOpen,
|
||||
closeDeleteModalAndRefresh,
|
||||
setErrorSnackMessage,
|
||||
}: IDeleteGroup) => {
|
||||
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
|
||||
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
|
||||
const onDelError = (err: ErrorResponseHandler) => {
|
||||
setErrorSnackMessage(err);
|
||||
closeDeleteModalAndRefresh(true);
|
||||
}
|
||||
const onClose = () => closeDeleteModalAndRefresh(false);
|
||||
|
||||
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
|
||||
|
||||
if (!selectedGroup) {
|
||||
if (!selectedGroups) {
|
||||
return null;
|
||||
}
|
||||
const onDeleteGroup = () => {
|
||||
invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(selectedGroup)}`);
|
||||
};
|
||||
const onDeleteGroups = () => {
|
||||
for (let group of selectedGroups){
|
||||
invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(group)}`);
|
||||
}
|
||||
};
|
||||
|
||||
const renderGroups = selectedGroups.map((group) => <div key={group}><b>{group}</b></div>);
|
||||
|
||||
return (
|
||||
<ConfirmDialog
|
||||
title={`Delete Group`}
|
||||
title={`Delete Group${selectedGroups.length >1 ? "s": ""}`}
|
||||
confirmText={"Delete"}
|
||||
isOpen={deleteOpen}
|
||||
titleIcon={<ConfirmDeleteIcon />}
|
||||
isLoading={deleteLoading}
|
||||
onConfirm={onDeleteGroup}
|
||||
onConfirm={onDeleteGroups}
|
||||
onClose={onClose}
|
||||
confirmationContent={
|
||||
<DialogContentText>
|
||||
Are you sure you want to delete group
|
||||
<br />
|
||||
<b>{selectedGroup}</b>?
|
||||
Are you sure you want to delete the following {selectedGroups.length} group{selectedGroups.length >1 ? "s?": "?"}
|
||||
{renderGroups}
|
||||
</DialogContentText>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -20,8 +20,8 @@ import { Theme } from "@mui/material/styles";
|
||||
import createStyles from "@mui/styles/createStyles";
|
||||
import withStyles from "@mui/styles/withStyles";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { LinearProgress } from "@mui/material";
|
||||
import { AddIcon, GroupsIcon, UsersIcon } from "../../../icons";
|
||||
import { LinearProgress, Box } from "@mui/material";
|
||||
import { AddIcon, GroupsIcon, UsersIcon, DeleteIcon, IAMPoliciesIcon } from "../../../icons";
|
||||
import { setErrorSnackMessage } from "../../../actions";
|
||||
import { GroupsList } from "./types";
|
||||
import { stringSort } from "../../../utils/sortFunctions";
|
||||
@@ -79,12 +79,12 @@ const styles = (theme: Theme) =>
|
||||
});
|
||||
|
||||
const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
const [selectedGroup, setSelectedGroup] = useState<any>(null);
|
||||
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
|
||||
const [loading, isLoading] = useState<boolean>(false);
|
||||
const [records, setRecords] = useState<any[]>([]);
|
||||
const [filter, setFilter] = useState<string>("");
|
||||
const [policyOpen, setPolicyOpen] = useState<boolean>(false);
|
||||
const [checkedGroups, setCheckedGroups] = useState<string[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
isLoading(true);
|
||||
@@ -106,6 +106,24 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
IAM_SCOPES.ADMIN_GET_GROUP,
|
||||
]);
|
||||
|
||||
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { target: { value = "", checked = false } = {} } = e;
|
||||
|
||||
let elements: string[] = [...checkedGroups]; // We clone the checkedUsers array
|
||||
|
||||
if (checked) {
|
||||
// If the user has checked this field we need to push this to checkedUsersList
|
||||
elements.push(value);
|
||||
} else {
|
||||
// User has unchecked this field, we need to remove it from the list
|
||||
elements = elements.filter((element) => element !== value);
|
||||
}
|
||||
|
||||
setCheckedGroups(elements);
|
||||
|
||||
return elements;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (loading) {
|
||||
if (displayGroups) {
|
||||
@@ -134,7 +152,7 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
|
||||
const closeDeleteModalAndRefresh = (refresh: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
|
||||
setCheckedGroups([]);
|
||||
if (refresh) {
|
||||
isLoading(true);
|
||||
}
|
||||
@@ -148,10 +166,6 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
history.push(`${IAM_PAGES.GROUPS}/${group}`);
|
||||
};
|
||||
|
||||
const deleteAction = (group: any) => {
|
||||
setDeleteOpen(true);
|
||||
setSelectedGroup(group);
|
||||
};
|
||||
|
||||
const tableActions = [
|
||||
{
|
||||
@@ -160,25 +174,26 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
disableButtonFunction: () => !getGroup,
|
||||
},
|
||||
{
|
||||
type: "delete",
|
||||
onClick: deleteAction,
|
||||
disableButtonFunction: () => !deleteGroup,
|
||||
type: "edit",
|
||||
onClick: viewAction,
|
||||
disableButtonFunction: () => !getGroup,
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{deleteOpen && (
|
||||
<DeleteGroup
|
||||
deleteOpen={deleteOpen}
|
||||
selectedGroup={selectedGroup}
|
||||
selectedGroups={checkedGroups}
|
||||
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
|
||||
/>
|
||||
)}
|
||||
{setPolicyOpen && (
|
||||
{policyOpen && (
|
||||
<SetPolicy
|
||||
open={policyOpen}
|
||||
selectedGroup={selectedGroup}
|
||||
selectedGroup={checkedGroups[0]}
|
||||
selectedUser={null}
|
||||
closeModalAndRefresh={() => {
|
||||
setPolicyOpen(false);
|
||||
@@ -189,19 +204,67 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
|
||||
<PageLayout>
|
||||
<Grid item xs={12} className={classes.actionsTray}>
|
||||
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[IAM_SCOPES.ADMIN_LIST_GROUPS]}
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
>
|
||||
<SearchBox
|
||||
placeholder={"Search Groups"}
|
||||
onChange={setFilter}
|
||||
overrideClass={classes.searchField}
|
||||
value={filter}
|
||||
/>
|
||||
</SecureComponent>
|
||||
|
||||
</SecureComponent>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY
|
||||
]}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<RBIconButton
|
||||
tooltip={"Select Policy"}
|
||||
onClick={() => {
|
||||
setPolicyOpen(true);
|
||||
}}
|
||||
text={"Assign Policy"}
|
||||
icon={<IAMPoliciesIcon />}
|
||||
color="primary"
|
||||
disabled={checkedGroups.length !== 1}
|
||||
variant={"outlined"}
|
||||
/>
|
||||
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP
|
||||
]}
|
||||
matchAll
|
||||
errorProps={{ disabled: true }}
|
||||
>
|
||||
<RBIconButton
|
||||
tooltip={"Delete Selected"}
|
||||
onClick={() => {
|
||||
setDeleteOpen(true);
|
||||
}}
|
||||
text={"Delete Selected"}
|
||||
icon={<DeleteIcon />}
|
||||
color="secondary"
|
||||
disabled={checkedGroups.length === 0}
|
||||
variant={"outlined"}
|
||||
/>
|
||||
|
||||
</SecureComponent>
|
||||
<SecureComponent
|
||||
resource={CONSOLE_UI_RESOURCE}
|
||||
scopes={[
|
||||
@@ -222,6 +285,7 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
}}
|
||||
/>
|
||||
</SecureComponent>
|
||||
</Box>
|
||||
</Grid>
|
||||
{loading && <LinearProgress />}
|
||||
{!loading && (
|
||||
@@ -238,6 +302,8 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
|
||||
itemActions={tableActions}
|
||||
columns={[{ label: "Name", elementKey: "" }]}
|
||||
isLoading={loading}
|
||||
selectedItems={checkedGroups}
|
||||
onSelect={deleteGroup ? selectionChanged : undefined}
|
||||
records={filteredRecords}
|
||||
entityName="Groups"
|
||||
idField=""
|
||||
|
||||
@@ -378,7 +378,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
|
||||
{deleteOpen && (
|
||||
<DeleteGroup
|
||||
deleteOpen={deleteOpen}
|
||||
selectedGroup={groupName}
|
||||
selectedGroups={[groupName]}
|
||||
closeDeleteModalAndRefresh={(isDelSuccess: boolean) => {
|
||||
setDeleteOpen(false);
|
||||
if (isDelSuccess) {
|
||||
|
||||
Reference in New Issue
Block a user