diff --git a/portal-ui/src/screens/Console/Common/TableWrapper/TableWrapper.tsx b/portal-ui/src/screens/Console/Common/TableWrapper/TableWrapper.tsx index d2b6ae77a..ddd95d020 100644 --- a/portal-ui/src/screens/Console/Common/TableWrapper/TableWrapper.tsx +++ b/portal-ui/src/screens/Console/Common/TableWrapper/TableWrapper.tsx @@ -739,7 +739,6 @@ const TableWrapper = ({ )} {hasOptions && ( Options} dataKey={idField} width={optionsWidth} headerClassName="optionsAlignment" diff --git a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx index f4da745c8..202402b0e 100644 --- a/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx +++ b/portal-ui/src/screens/Console/Groups/DeleteGroup.tsx @@ -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) =>
{group}
); return ( 1 ? "s": ""}`} confirmText={"Delete"} isOpen={deleteOpen} titleIcon={} isLoading={deleteLoading} - onConfirm={onDeleteGroup} + onConfirm={onDeleteGroups} onClose={onClose} confirmationContent={ - Are you sure you want to delete group -
- {selectedGroup}? + Are you sure you want to delete the following {selectedGroups.length} group{selectedGroups.length >1 ? "s?": "?"} + {renderGroups}
} /> diff --git a/portal-ui/src/screens/Console/Groups/Groups.tsx b/portal-ui/src/screens/Console/Groups/Groups.tsx index 8ad1ca9e9..be9e659a1 100644 --- a/portal-ui/src/screens/Console/Groups/Groups.tsx +++ b/portal-ui/src/screens/Console/Groups/Groups.tsx @@ -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(null); const [deleteOpen, setDeleteOpen] = useState(false); const [loading, isLoading] = useState(false); const [records, setRecords] = useState([]); const [filter, setFilter] = useState(""); const [policyOpen, setPolicyOpen] = useState(false); + const [checkedGroups, setCheckedGroups] = useState([]); useEffect(() => { isLoading(true); @@ -106,6 +106,24 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => { IAM_SCOPES.ADMIN_GET_GROUP, ]); + const selectionChanged = (e: React.ChangeEvent) => { + 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 ( {deleteOpen && ( )} - {setPolicyOpen && ( + {policyOpen && ( { setPolicyOpen(false); @@ -189,19 +204,67 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => { + + > - - + + + {" "} + + { + setPolicyOpen(true); + }} + text={"Assign Policy"} + icon={} + color="primary" + disabled={checkedGroups.length !== 1} + variant={"outlined"} + /> + + + + { + setDeleteOpen(true); + }} + text={"Delete Selected"} + icon={} + color="secondary" + disabled={checkedGroups.length === 0} + variant={"outlined"} + /> + + { }} /> + {loading && } {!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="" diff --git a/portal-ui/src/screens/Console/Groups/GroupsDetails.tsx b/portal-ui/src/screens/Console/Groups/GroupsDetails.tsx index 299bb1fda..2792c1c26 100644 --- a/portal-ui/src/screens/Console/Groups/GroupsDetails.tsx +++ b/portal-ui/src/screens/Console/Groups/GroupsDetails.tsx @@ -378,7 +378,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => { {deleteOpen && ( { setDeleteOpen(false); if (isDelSuccess) {