1
- import type { Interpolation , Theme } from "@emotion/react" ;
1
+ import { type Interpolation , type Theme , useTheme } from "@emotion/react" ;
2
2
import AddOutlined from "@mui/icons-material/AddOutlined" ;
3
3
import Button from "@mui/material/Button" ;
4
4
import Skeleton from "@mui/material/Skeleton" ;
5
+ import Stack from "@mui/material/Stack" ;
5
6
import Table from "@mui/material/Table" ;
6
7
import TableBody from "@mui/material/TableBody" ;
7
8
import TableCell from "@mui/material/TableCell" ;
8
9
import TableContainer from "@mui/material/TableContainer" ;
9
10
import TableHead from "@mui/material/TableHead" ;
10
11
import TableRow from "@mui/material/TableRow" ;
11
- import type { Role } from "api/typesGenerated" ;
12
+ import type { Permission , Role } from "api/typesGenerated" ;
12
13
import { ChooseOne , Cond } from "components/Conditionals/ChooseOne" ;
13
14
import { EmptyState } from "components/EmptyState/EmptyState" ;
14
15
import {
@@ -19,6 +20,12 @@ import {
19
20
ThreeDotsButton ,
20
21
} from "components/MoreMenu/MoreMenu" ;
21
22
import { Paywall } from "components/Paywall/Paywall" ;
23
+ import { Pill } from "components/Pill/Pill" ;
24
+ import {
25
+ Popover ,
26
+ PopoverContent ,
27
+ PopoverTrigger ,
28
+ } from "components/Popover/Popover" ;
22
29
import {
23
30
TableLoaderSkeleton ,
24
31
TableRowSkeleton ,
@@ -42,7 +49,6 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
42
49
} ) => {
43
50
const isLoading = roles === undefined ;
44
51
const isEmpty = Boolean ( roles && roles . length === 0 ) ;
45
-
46
52
return (
47
53
< >
48
54
< ChooseOne >
@@ -58,8 +64,8 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
58
64
< Table >
59
65
< TableHead >
60
66
< TableRow >
61
- < TableCell width = "50 %" > Name</ TableCell >
62
- < TableCell width = "49 %" > Permissions</ TableCell >
67
+ < TableCell width = "40 %" > Name</ TableCell >
68
+ < TableCell width = "59 %" > Permissions</ TableCell >
63
69
< TableCell width = "1%" />
64
70
</ TableRow >
65
71
</ TableHead >
@@ -116,6 +122,10 @@ export const CustomRolesPageView: FC<CustomRolesPageViewProps> = ({
116
122
) ;
117
123
} ;
118
124
125
+ function getUniqueResourceTypes ( jsonObject : readonly Permission [ ] ) {
126
+ const resourceTypes = jsonObject . map ( ( item ) => item . resource_type ) ;
127
+ return [ ...new Set ( resourceTypes ) ] ;
128
+ }
119
129
interface RoleRowProps {
120
130
role : Role ;
121
131
onDelete : ( ) => void ;
@@ -125,12 +135,28 @@ interface RoleRowProps {
125
135
const RoleRow : FC < RoleRowProps > = ( { role, onDelete, canAssignOrgRole } ) => {
126
136
const navigate = useNavigate ( ) ;
127
137
138
+ const resourceTypes : string [ ] = getUniqueResourceTypes (
139
+ role . organization_permissions ,
140
+ ) ;
141
+
128
142
return (
129
143
< TableRow data-testid = { `role-${ role . name } ` } >
130
144
< TableCell > { role . display_name || role . name } </ TableCell >
131
145
132
- < TableCell css = { styles . secondary } >
133
- { role . organization_permissions . length }
146
+ < TableCell >
147
+ < Stack direction = "row" spacing = { 1 } >
148
+ < PermissionsPill
149
+ resource = { resourceTypes [ 0 ] }
150
+ permissions = { role . organization_permissions }
151
+ />
152
+
153
+ { resourceTypes . length > 1 && (
154
+ < OverflowPermissionPill
155
+ resources = { resourceTypes . slice ( 1 ) }
156
+ permissions = { role . organization_permissions . slice ( 1 ) }
157
+ />
158
+ ) }
159
+ </ Stack >
134
160
</ TableCell >
135
161
136
162
< TableCell >
@@ -176,10 +202,98 @@ const TableLoader = () => {
176
202
) ;
177
203
} ;
178
204
205
+ interface PermissionPillProps {
206
+ resource : string ;
207
+ permissions : readonly Permission [ ] ;
208
+ }
209
+
210
+ const PermissionsPill : FC < PermissionPillProps > = ( {
211
+ resource,
212
+ permissions,
213
+ } ) => {
214
+ const actions = permissions . filter ( ( p ) => {
215
+ if ( resource === p . resource_type ) {
216
+ return p . action ;
217
+ }
218
+ } ) ;
219
+
220
+ return (
221
+ < Pill css = { styles . permissionPill } >
222
+ < b > { resource } </ b > : { actions . map ( ( p ) => p . action ) . join ( ", " ) }
223
+ </ Pill >
224
+ ) ;
225
+ } ;
226
+
227
+ type OverflowPermissionPillProps = {
228
+ resources : string [ ] ;
229
+ permissions : readonly Permission [ ] ;
230
+ } ;
231
+
232
+ const OverflowPermissionPill : FC < OverflowPermissionPillProps > = ( {
233
+ resources,
234
+ permissions,
235
+ } ) => {
236
+ const theme = useTheme ( ) ;
237
+
238
+ return (
239
+ < Popover mode = "hover" >
240
+ < PopoverTrigger >
241
+ < Pill
242
+ css = { {
243
+ backgroundColor : theme . palette . background . paper ,
244
+ borderColor : theme . palette . divider ,
245
+ } }
246
+ >
247
+ +{ resources . length } more
248
+ </ Pill >
249
+ </ PopoverTrigger >
250
+
251
+ < PopoverContent
252
+ disableRestoreFocus
253
+ disableScrollLock
254
+ css = { {
255
+ ".MuiPaper-root" : {
256
+ display : "flex" ,
257
+ flexFlow : "column wrap" ,
258
+ columnGap : 8 ,
259
+ rowGap : 12 ,
260
+ padding : "12px 16px" ,
261
+ alignContent : "space-around" ,
262
+ minWidth : "auto" ,
263
+ backgroundColor : theme . palette . background . default ,
264
+ } ,
265
+ } }
266
+ anchorOrigin = { {
267
+ vertical : - 4 ,
268
+ horizontal : "center" ,
269
+ } }
270
+ transformOrigin = { {
271
+ vertical : "bottom" ,
272
+ horizontal : "center" ,
273
+ } }
274
+ >
275
+ { resources . map ( ( resource ) => (
276
+ < PermissionsPill
277
+ key = { resource }
278
+ resource = { resource }
279
+ permissions = { permissions }
280
+ />
281
+ ) ) }
282
+ </ PopoverContent >
283
+ </ Popover >
284
+ ) ;
285
+ } ;
286
+
179
287
const styles = {
180
288
secondary : ( theme ) => ( {
181
289
color : theme . palette . text . secondary ,
182
290
} ) ,
291
+ permissionPill : ( theme ) => ( {
292
+ backgroundColor : theme . permission . background ,
293
+ borderColor : theme . permission . outline ,
294
+ color : theme . permission . text ,
295
+ width : "fit-content" ,
296
+ } ) ,
183
297
} satisfies Record < string , Interpolation < Theme > > ;
184
298
185
299
export default CustomRolesPageView ;
0 commit comments