1
1
import type { Interpolation , Theme } from "@emotion/react" ;
2
+ import Checkbox from "@mui/material/Checkbox" ;
2
3
import Table from "@mui/material/Table" ;
3
4
import TableBody from "@mui/material/TableBody" ;
4
5
import TableCell from "@mui/material/TableCell" ;
5
6
import TableContainer from "@mui/material/TableContainer" ;
6
7
import TableRow from "@mui/material/TableRow" ;
7
8
import TextField from "@mui/material/TextField" ;
8
- import { useFormik } from "formik" ;
9
- import type { FC } from "react" ;
9
+ import { type FormikValues , useFormik } from "formik" ;
10
+ import { type ChangeEvent , useState , type FC , useEffect } from "react" ;
10
11
import { useNavigate } from "react-router-dom" ;
11
12
import * as Yup from "yup" ;
12
13
import { isApiValidationError } from "api/errors" ;
13
14
import { RBACResourceActions } from "api/rbacresources_gen" ;
14
- import type { Role } from "api/typesGenerated" ;
15
+ import type {
16
+ Role ,
17
+ Permission ,
18
+ AssignableRoles ,
19
+ RBACResource ,
20
+ RBACAction ,
21
+ } from "api/typesGenerated" ;
15
22
import { ErrorAlert } from "components/Alert/ErrorAlert" ;
16
23
import {
17
24
FormFields ,
@@ -27,24 +34,29 @@ const validationSchema = Yup.object({
27
34
} ) ;
28
35
29
36
export type CreateEditRolePageViewProps = {
37
+ role : AssignableRoles | undefined ;
38
+ organization : string ;
30
39
onSubmit : ( data : Role ) => void ;
31
40
error ?: unknown ;
32
41
isLoading : boolean ;
33
42
} ;
34
43
35
44
export const CreateEditRolePageView : FC < CreateEditRolePageViewProps > = ( {
45
+ role,
46
+ organization,
36
47
onSubmit,
37
48
error,
38
49
isLoading,
39
50
} ) => {
40
51
const navigate = useNavigate ( ) ;
41
52
const form = useFormik < Role > ( {
42
53
initialValues : {
43
- name : "" ,
44
- display_name : "" ,
45
- site_permissions : [ ] ,
46
- organization_permissions : [ ] ,
47
- user_permissions : [ ] ,
54
+ name : role ?. name || "" ,
55
+ organization_id : role ?. organization_id || organization ,
56
+ display_name : role ?. display_name || "" ,
57
+ site_permissions : role ?. site_permissions || [ ] ,
58
+ organization_permissions : role ?. organization_permissions || [ ] ,
59
+ user_permissions : role ?. user_permissions || [ ] ,
48
60
} ,
49
61
validationSchema,
50
62
onSubmit,
@@ -55,12 +67,14 @@ export const CreateEditRolePageView: FC<CreateEditRolePageViewProps> = ({
55
67
return (
56
68
< >
57
69
< PageHeader css = { { paddingTop : 8 } } >
58
- < PageHeaderTitle > Create custom role</ PageHeaderTitle >
70
+ < PageHeaderTitle >
71
+ { role ? "Edit" : "Create" } custom role
72
+ </ PageHeaderTitle >
59
73
</ PageHeader >
60
74
< HorizontalForm onSubmit = { form . handleSubmit } >
61
75
< FormSection
62
76
title = "Role settings"
63
- description = "Set a name for this role."
77
+ description = "Set a name and permissions for this role."
64
78
>
65
79
< FormFields >
66
80
{ Boolean ( error ) && ! isApiValidationError ( error ) && (
@@ -80,7 +94,10 @@ export const CreateEditRolePageView: FC<CreateEditRolePageViewProps> = ({
80
94
fullWidth
81
95
label = "Display Name"
82
96
/>
83
- < ActionCheckboxes permissions = { [ ] } > </ ActionCheckboxes >
97
+ < ActionCheckboxes
98
+ permissions = { role ?. organization_permissions || [ ] }
99
+ form = { form }
100
+ />
84
101
</ FormFields >
85
102
</ FormSection >
86
103
< FormFooter onCancel = { onCancel } isLoading = { isLoading } />
@@ -90,26 +107,69 @@ export const CreateEditRolePageView: FC<CreateEditRolePageViewProps> = ({
90
107
} ;
91
108
92
109
interface ActionCheckboxesProps {
93
- permissions : Permissions [ ] ;
110
+ permissions : readonly Permission [ ] | undefined ;
111
+ form : ReturnType < typeof useFormik < Role > > & { values : Role } ;
94
112
}
95
113
96
- const ActionCheckboxes : FC < ActionCheckboxesProps > = ( { permissions } ) => {
114
+ const ActionCheckboxes : FC < ActionCheckboxesProps > = ( { permissions, form } ) => {
115
+ const [ checkedActions , setIsChecked ] = useState ( permissions ) ;
116
+
117
+ const handleCheckChange = async (
118
+ e : ChangeEvent < HTMLInputElement > ,
119
+ form : ReturnType < typeof useFormik < Role > > & { values : Role } ,
120
+ ) => {
121
+ const { name, checked } = e . currentTarget ;
122
+ const [ resource_type , action ] = name . split ( ":" ) ;
123
+
124
+ const newPermissions = checked
125
+ ? [
126
+ ...( checkedActions ?? [ ] ) ,
127
+ {
128
+ negate : false ,
129
+ resource_type : resource_type as RBACResource ,
130
+ action : action as RBACAction ,
131
+ } ,
132
+ ]
133
+ : checkedActions ?. filter (
134
+ ( p ) => p . resource_type !== resource_type || p . action !== action ,
135
+ ) ;
136
+
137
+ setIsChecked ( newPermissions ) ;
138
+ await form . setFieldValue ( "organization_permissions" , checkedActions ) ;
139
+ } ;
140
+
141
+ // useEffect(() => {
142
+ // setIsChecked(permissions);
143
+ // }, [permissions]);
144
+
97
145
return (
98
146
< TableContainer >
99
147
< Table >
100
148
< TableBody >
101
- { Object . entries ( RBACResourceActions ) . map ( ( [ key , value ] ) => {
149
+ { Object . entries ( RBACResourceActions ) . map ( ( [ resourceKey , value ] ) => {
102
150
return (
103
- < TableRow key = { key } >
151
+ < TableRow key = { resourceKey } >
104
152
< TableCell >
105
- < li key = { key } css = { styles . checkBoxes } >
106
- < input type = "checkbox" /> { key }
153
+ < li key = { resourceKey } css = { styles . checkBoxes } >
154
+ { resourceKey }
107
155
< ul css = { styles . checkBoxes } >
108
- { Object . entries ( value ) . map ( ( [ key , value ] ) => {
156
+ { Object . entries ( value ) . map ( ( [ actionKey , value ] ) => {
109
157
return (
110
- < li key = { key } >
158
+ < li key = { actionKey } >
111
159
< span css = { styles . actionText } >
112
- < input type = "checkbox" /> { key }
160
+ < Checkbox
161
+ name = { `${ resourceKey } :${ actionKey } ` }
162
+ checked = {
163
+ checkedActions ?. some (
164
+ ( p ) =>
165
+ p . resource_type === resourceKey &&
166
+ ( p . action . toString ( ) === "*" ||
167
+ p . action === actionKey ) ,
168
+ ) || false
169
+ }
170
+ onChange = { ( e ) => handleCheckChange ( e , form ) }
171
+ />
172
+ { actionKey }
113
173
</ span > { " " }
114
174
-{ " " }
115
175
< span css = { styles . actionDescription } > { value } </ span >
@@ -129,9 +189,6 @@ const ActionCheckboxes: FC<ActionCheckboxesProps> = ({ permissions }) => {
129
189
} ;
130
190
131
191
const styles = {
132
- rolesDropdown : {
133
- marginBottom : 20 ,
134
- } ,
135
192
checkBoxes : {
136
193
margin : 0 ,
137
194
listStyleType : "none" ,
0 commit comments