Skip to content

Commit 22390a6

Browse files
Groups UI revision (#1959)
Co-authored-by: Prakash Senthil Vel <[email protected]>
1 parent 3854372 commit 22390a6

File tree

4 files changed

+102
-31
lines changed

4 files changed

+102
-31
lines changed

portal-ui/src/screens/Console/Common/TableWrapper/TableWrapper.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -739,7 +739,6 @@ const TableWrapper = ({
739739
)}
740740
{hasOptions && (
741741
<Column
742-
headerRenderer={() => <Fragment>Options</Fragment>}
743742
dataKey={idField}
744743
width={optionsWidth}
745744
headerClassName="optionsAlignment"

portal-ui/src/screens/Console/Groups/DeleteGroup.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,45 +24,51 @@ import useApi from "../Common/Hooks/useApi";
2424
import { ConfirmDeleteIcon } from "../../../icons";
2525

2626
interface IDeleteGroup {
27-
selectedGroup: string;
27+
selectedGroups: string[];
2828
deleteOpen: boolean;
2929
closeDeleteModalAndRefresh: any;
3030
setErrorSnackMessage: typeof setErrorSnackMessage;
3131
}
3232

3333
const DeleteGroup = ({
34-
selectedGroup,
34+
selectedGroups,
3535
deleteOpen,
3636
closeDeleteModalAndRefresh,
3737
setErrorSnackMessage,
3838
}: IDeleteGroup) => {
3939
const onDelSuccess = () => closeDeleteModalAndRefresh(true);
40-
const onDelError = (err: ErrorResponseHandler) => setErrorSnackMessage(err);
40+
const onDelError = (err: ErrorResponseHandler) => {
41+
setErrorSnackMessage(err);
42+
closeDeleteModalAndRefresh(true);
43+
}
4144
const onClose = () => closeDeleteModalAndRefresh(false);
4245

4346
const [deleteLoading, invokeDeleteApi] = useApi(onDelSuccess, onDelError);
4447

45-
if (!selectedGroup) {
48+
if (!selectedGroups) {
4649
return null;
4750
}
48-
const onDeleteGroup = () => {
49-
invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(selectedGroup)}`);
50-
};
51+
const onDeleteGroups = () => {
52+
for (let group of selectedGroups){
53+
invokeDeleteApi("DELETE", `/api/v1/group?name=${encodeURI(group)}`);
54+
}
55+
};
56+
57+
const renderGroups = selectedGroups.map((group) => <div key={group}><b>{group}</b></div>);
5158

5259
return (
5360
<ConfirmDialog
54-
title={`Delete Group`}
61+
title={`Delete Group${selectedGroups.length >1 ? "s": ""}`}
5562
confirmText={"Delete"}
5663
isOpen={deleteOpen}
5764
titleIcon={<ConfirmDeleteIcon />}
5865
isLoading={deleteLoading}
59-
onConfirm={onDeleteGroup}
66+
onConfirm={onDeleteGroups}
6067
onClose={onClose}
6168
confirmationContent={
6269
<DialogContentText>
63-
Are you sure you want to delete group
64-
<br />
65-
<b>{selectedGroup}</b>?
70+
Are you sure you want to delete the following {selectedGroups.length} group{selectedGroups.length >1 ? "s?": "?"}
71+
{renderGroups}
6672
</DialogContentText>
6773
}
6874
/>

portal-ui/src/screens/Console/Groups/Groups.tsx

Lines changed: 83 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import { Theme } from "@mui/material/styles";
2020
import createStyles from "@mui/styles/createStyles";
2121
import withStyles from "@mui/styles/withStyles";
2222
import Grid from "@mui/material/Grid";
23-
import { LinearProgress } from "@mui/material";
24-
import { AddIcon, GroupsIcon, UsersIcon } from "../../../icons";
23+
import { LinearProgress, Box } from "@mui/material";
24+
import { AddIcon, GroupsIcon, UsersIcon, DeleteIcon, IAMPoliciesIcon } from "../../../icons";
2525
import { setErrorSnackMessage } from "../../../actions";
2626
import { GroupsList } from "./types";
2727
import { stringSort } from "../../../utils/sortFunctions";
@@ -79,12 +79,12 @@ const styles = (theme: Theme) =>
7979
});
8080

8181
const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
82-
const [selectedGroup, setSelectedGroup] = useState<any>(null);
8382
const [deleteOpen, setDeleteOpen] = useState<boolean>(false);
8483
const [loading, isLoading] = useState<boolean>(false);
8584
const [records, setRecords] = useState<any[]>([]);
8685
const [filter, setFilter] = useState<string>("");
8786
const [policyOpen, setPolicyOpen] = useState<boolean>(false);
87+
const [checkedGroups, setCheckedGroups] = useState<string[]>([]);
8888

8989
useEffect(() => {
9090
isLoading(true);
@@ -106,6 +106,24 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
106106
IAM_SCOPES.ADMIN_GET_GROUP,
107107
]);
108108

109+
const selectionChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
110+
const { target: { value = "", checked = false } = {} } = e;
111+
112+
let elements: string[] = [...checkedGroups]; // We clone the checkedUsers array
113+
114+
if (checked) {
115+
// If the user has checked this field we need to push this to checkedUsersList
116+
elements.push(value);
117+
} else {
118+
// User has unchecked this field, we need to remove it from the list
119+
elements = elements.filter((element) => element !== value);
120+
}
121+
122+
setCheckedGroups(elements);
123+
124+
return elements;
125+
};
126+
109127
useEffect(() => {
110128
if (loading) {
111129
if (displayGroups) {
@@ -134,7 +152,7 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
134152

135153
const closeDeleteModalAndRefresh = (refresh: boolean) => {
136154
setDeleteOpen(false);
137-
155+
setCheckedGroups([]);
138156
if (refresh) {
139157
isLoading(true);
140158
}
@@ -148,10 +166,6 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
148166
history.push(`${IAM_PAGES.GROUPS}/${group}`);
149167
};
150168

151-
const deleteAction = (group: any) => {
152-
setDeleteOpen(true);
153-
setSelectedGroup(group);
154-
};
155169

156170
const tableActions = [
157171
{
@@ -160,25 +174,26 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
160174
disableButtonFunction: () => !getGroup,
161175
},
162176
{
163-
type: "delete",
164-
onClick: deleteAction,
165-
disableButtonFunction: () => !deleteGroup,
177+
type: "edit",
178+
onClick: viewAction,
179+
disableButtonFunction: () => !getGroup,
166180
},
167181
];
168182

183+
169184
return (
170185
<React.Fragment>
171186
{deleteOpen && (
172187
<DeleteGroup
173188
deleteOpen={deleteOpen}
174-
selectedGroup={selectedGroup}
189+
selectedGroups={checkedGroups}
175190
closeDeleteModalAndRefresh={closeDeleteModalAndRefresh}
176191
/>
177192
)}
178-
{setPolicyOpen && (
193+
{policyOpen && (
179194
<SetPolicy
180195
open={policyOpen}
181-
selectedGroup={selectedGroup}
196+
selectedGroup={checkedGroups[0]}
182197
selectedUser={null}
183198
closeModalAndRefresh={() => {
184199
setPolicyOpen(false);
@@ -189,19 +204,67 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
189204

190205
<PageLayout>
191206
<Grid item xs={12} className={classes.actionsTray}>
207+
192208
<SecureComponent
193209
resource={CONSOLE_UI_RESOURCE}
194210
scopes={[IAM_SCOPES.ADMIN_LIST_GROUPS]}
195211
errorProps={{ disabled: true }}
196-
>
212+
>
197213
<SearchBox
198214
placeholder={"Search Groups"}
199215
onChange={setFilter}
200216
overrideClass={classes.searchField}
201217
value={filter}
202218
/>
203-
</SecureComponent>
204-
219+
</SecureComponent>
220+
<Box
221+
sx={{
222+
display: "flex",
223+
}}
224+
>
225+
{" "}
226+
<SecureComponent
227+
resource={CONSOLE_UI_RESOURCE}
228+
scopes={[
229+
IAM_SCOPES.ADMIN_ATTACH_USER_OR_GROUP_POLICY
230+
]}
231+
matchAll
232+
errorProps={{ disabled: true }}
233+
>
234+
<RBIconButton
235+
tooltip={"Select Policy"}
236+
onClick={() => {
237+
setPolicyOpen(true);
238+
}}
239+
text={"Assign Policy"}
240+
icon={<IAMPoliciesIcon />}
241+
color="primary"
242+
disabled={checkedGroups.length !== 1}
243+
variant={"outlined"}
244+
/>
245+
246+
</SecureComponent>
247+
<SecureComponent
248+
resource={CONSOLE_UI_RESOURCE}
249+
scopes={[
250+
IAM_SCOPES.ADMIN_REMOVE_USER_FROM_GROUP
251+
]}
252+
matchAll
253+
errorProps={{ disabled: true }}
254+
>
255+
<RBIconButton
256+
tooltip={"Delete Selected"}
257+
onClick={() => {
258+
setDeleteOpen(true);
259+
}}
260+
text={"Delete Selected"}
261+
icon={<DeleteIcon />}
262+
color="secondary"
263+
disabled={checkedGroups.length === 0}
264+
variant={"outlined"}
265+
/>
266+
267+
</SecureComponent>
205268
<SecureComponent
206269
resource={CONSOLE_UI_RESOURCE}
207270
scopes={[
@@ -222,6 +285,7 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
222285
}}
223286
/>
224287
</SecureComponent>
288+
</Box>
225289
</Grid>
226290
{loading && <LinearProgress />}
227291
{!loading && (
@@ -238,6 +302,8 @@ const Groups = ({ classes, setErrorSnackMessage, history }: IGroupsProps) => {
238302
itemActions={tableActions}
239303
columns={[{ label: "Name", elementKey: "" }]}
240304
isLoading={loading}
305+
selectedItems={checkedGroups}
306+
onSelect={deleteGroup ? selectionChanged : undefined}
241307
records={filteredRecords}
242308
entityName="Groups"
243309
idField=""

portal-ui/src/screens/Console/Groups/GroupsDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ const GroupsDetails = ({ classes }: IGroupDetailsProps) => {
378378
{deleteOpen && (
379379
<DeleteGroup
380380
deleteOpen={deleteOpen}
381-
selectedGroup={groupName}
381+
selectedGroups={[groupName]}
382382
closeDeleteModalAndRefresh={(isDelSuccess: boolean) => {
383383
setDeleteOpen(false);
384384
if (isDelSuccess) {

0 commit comments

Comments
 (0)