Skip to content

Commit b4a35a2

Browse files
committed
add panel
1 parent c58ce32 commit b4a35a2

File tree

2 files changed

+94
-55
lines changed

2 files changed

+94
-55
lines changed

src/ui/pages/iam/GroupMemberManagement.tsx

Lines changed: 88 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ import {
88
Modal,
99
List,
1010
ListItem,
11-
Alert,
12-
ActionIcon,
1311
ScrollArea,
1412
Badge,
13+
ActionIcon,
1514
} from '@mantine/core';
16-
import { IconTrash, IconCheck, IconX } from '@tabler/icons-react';
15+
import { IconTrash, IconUserPlus } from '@tabler/icons-react';
1716
import { notifications } from '@mantine/notifications';
1817
import { GroupMemberGetResponse, EntraActionResponse } from '@common/types/iam';
1918

@@ -29,17 +28,9 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
2928
const [members, setMembers] = useState<GroupMemberGetResponse>([]);
3029
const [toAdd, setToAdd] = useState<string[]>([]);
3130
const [toRemove, setToRemove] = useState<string[]>([]);
32-
const [results, setResults] = useState<
33-
{ email: string; status: 'success' | 'failure'; message?: string }[]
34-
>([]);
35-
const [email, setEmail] = useState<string>('');
36-
const [isLoading, setIsLoading] = useState<boolean>(false);
37-
const [confirmationModal, setConfirmationModal] = useState<boolean>(false);
38-
const [errorModal, setErrorModal] = useState<{ open: boolean; email: string; message: string }>({
39-
open: false,
40-
email: '',
41-
message: '',
42-
});
31+
const [email, setEmail] = useState('');
32+
const [isLoading, setIsLoading] = useState(false);
33+
const [confirmationModal, setConfirmationModal] = useState(false);
4334

4435
useEffect(() => {
4536
const loadMembers = async () => {
@@ -61,9 +52,14 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
6152
if (email && !members.some((member) => member.email === email) && !toAdd.includes(email)) {
6253
setToAdd((prev) => [...prev, email]);
6354
setEmail('');
55+
} else {
56+
notifications.show({
57+
title: 'Invalid Input',
58+
message: 'Email is missing or the user already exists.',
59+
color: 'orange',
60+
});
6461
}
6562
};
66-
6763
const handleRemoveMember = (email: string) => {
6864
if (!toRemove.includes(email)) {
6965
setToRemove((prev) => [...prev, email]);
@@ -72,51 +68,60 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
7268

7369
const handleSaveChanges = async () => {
7470
setIsLoading(true);
75-
const newResults: { email: string; status: 'success' | 'failure'; message?: string }[] = [];
76-
7771
try {
7872
const response = await updateMembers(toAdd, toRemove);
79-
response.success?.forEach(({ email }) => {
80-
newResults.push({ email, status: 'success' });
81-
});
82-
response.failure?.forEach(({ email, message }) => {
83-
newResults.push({ email, status: 'failure', message });
73+
if (response.success) {
74+
setMembers((prev) =>
75+
prev
76+
.filter((member) => !toRemove.includes(member.email))
77+
.concat(toAdd.map((email) => ({ name: '', email })))
78+
);
79+
setToAdd([]);
80+
setToRemove([]);
81+
}
82+
83+
notifications.show({
84+
title: 'Success',
85+
message: 'Changes saved successfully!',
86+
color: 'green',
8487
});
85-
setResults(newResults);
86-
setToAdd([]);
87-
setToRemove([]);
8888
} catch (error) {
8989
notifications.show({
9090
title: 'Error',
91-
message: 'An error occurred while saving changes.',
91+
message: 'Failed to save changes.',
9292
color: 'red',
9393
});
9494
} finally {
9595
setIsLoading(false);
9696
}
9797
};
9898

99-
const handleViewErrorDetails = (email: string, message: string) => {
100-
setErrorModal({ open: true, email, message });
101-
};
102-
10399
return (
104100
<Box p="md">
105101
<Text fw={500} mb={4}>
106-
Group Member Management
102+
Exec Group Management
107103
</Text>
108104

109105
{/* Member List */}
110106
<Box mb="md">
111107
<Text size="sm" fw={500} mb="xs">
112108
Current Members
113109
</Text>
114-
<ScrollArea style={{ height: 200 }}>
115-
<List>
110+
<ScrollArea style={{ height: 250 }}>
111+
<List spacing="sm">
116112
{members.map((member) => (
117113
<ListItem key={member.email}>
118114
<Group justify="space-between">
119-
<Text size="sm">{member.email}</Text>
115+
<Box>
116+
<Text size="sm">
117+
{member.name} ({member.email})
118+
</Text>
119+
{toRemove.includes(member.email) && (
120+
<Badge color="green" size="sm">
121+
Queued for removal
122+
</Badge>
123+
)}
124+
</Box>
120125
<ActionIcon
121126
color="red"
122127
variant="light"
@@ -127,14 +132,45 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
127132
</Group>
128133
</ListItem>
129134
))}
135+
{toAdd.map((member) => (
136+
<ListItem key={member}>
137+
<Group justify="space-between">
138+
<Box>
139+
<Text size="sm">{member}</Text>
140+
<Badge color="red" size="sm">
141+
Queued for addition
142+
</Badge>
143+
</Box>
144+
</Group>
145+
</ListItem>
146+
))}
130147
</List>
131148
</ScrollArea>
132149
</Box>
133150

151+
{/* Add Member */}
152+
<Box mb="md">
153+
<TextInput
154+
value={email}
155+
onChange={(e) => setEmail(e.currentTarget.value)}
156+
placeholder="Enter email"
157+
label="Add Member"
158+
/>
159+
<Button
160+
mt="sm"
161+
leftSection={<IconUserPlus size={16} />}
162+
onClick={handleAddMember}
163+
disabled={isLoading}
164+
>
165+
Add Member
166+
</Button>
167+
</Box>
168+
134169
{/* Save Changes Button */}
135170
<Button
136171
fullWidth
137172
color="blue"
173+
mt="md"
138174
onClick={() => setConfirmationModal(true)}
139175
disabled={!toAdd.length && !toRemove.length}
140176
loading={isLoading}
@@ -147,43 +183,41 @@ export const GroupMemberManagement: React.FC<GroupMemberManagementProps> = ({
147183
opened={confirmationModal}
148184
onClose={() => setConfirmationModal(false)}
149185
title="Confirm Changes"
150-
size="md"
151186
>
152187
<Box>
153188
{toAdd.length > 0 && (
154189
<Box mb="md">
155190
<Text fw={500} size="sm">
156191
Members to Add:
157192
</Text>
158-
<ScrollArea style={{ height: 100 }}>
159-
<List>
160-
{toAdd.map((email) => (
161-
<ListItem key={email}>
162-
<Text size="sm">{email}</Text>
163-
</ListItem>
164-
))}
165-
</List>
166-
</ScrollArea>
193+
<List spacing="sm">
194+
{toAdd.map((email) => (
195+
<ListItem key={email}>{email}</ListItem>
196+
))}
197+
</List>
167198
</Box>
168199
)}
169200
{toRemove.length > 0 && (
170201
<Box mb="md">
171202
<Text fw={500} size="sm">
172203
Members to Remove:
173204
</Text>
174-
<ScrollArea style={{ height: 100 }}>
175-
<List>
176-
{toRemove.map((email) => (
177-
<ListItem key={email}>
178-
<Text size="sm">{email}</Text>
179-
</ListItem>
180-
))}
181-
</List>
182-
</ScrollArea>
205+
<List spacing="sm">
206+
{toRemove.map((email) => (
207+
<ListItem key={email}>{email}</ListItem>
208+
))}
209+
</List>
183210
</Box>
184211
)}
185212
<Group justify="center" mt="lg">
186-
<Button onClick={handleSaveChanges} loading={isLoading} color="blue">
213+
<Button
214+
onClick={() => {
215+
handleSaveChanges();
216+
setConfirmationModal(false);
217+
}}
218+
loading={isLoading}
219+
color="blue"
220+
>
187221
Confirm and Save
188222
</Button>
189223
<Button

src/ui/pages/iam/ManageIam.page.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@ export const ManageIamPage = () => {
7070
<Title order={2}>Manage Authentication</Title>
7171
<SimpleGrid cols={2}>
7272
<UserInvitePanel onSubmit={handleInviteSubmit} />
73-
<GroupMemberManagement fetchMembers={getExecMembers} updateMembers={updateExecMembers} />
73+
<AuthGuard
74+
resourceDef={{ service: 'core', validRoles: [AppRoles.IAM_ADMIN] }}
75+
isAppShell={false}
76+
>
77+
<GroupMemberManagement fetchMembers={getExecMembers} updateMembers={updateExecMembers} />
78+
</AuthGuard>
7479
{/* For future panels, make sure to add an auth guard if not every IAM role can see it. */}
7580
</SimpleGrid>
7681
</AuthGuard>

0 commit comments

Comments
 (0)