1
1
import type { Interpolation , Theme } from "@emotion/react" ;
2
+ import Button from "@mui/material/Button" ;
2
3
import Checkbox from "@mui/material/Checkbox" ;
3
4
import FormControlLabel from "@mui/material/FormControlLabel" ;
4
5
import Table from "@mui/material/Table" ;
@@ -8,9 +9,10 @@ import TableContainer from "@mui/material/TableContainer";
8
9
import TableHead from "@mui/material/TableHead" ;
9
10
import TableRow from "@mui/material/TableRow" ;
10
11
import TextField from "@mui/material/TextField" ;
11
- import type { useFormik } from "formik" ;
12
+ import { useFormik } from "formik" ;
12
13
import { type ChangeEvent , useState , type FC } from "react" ;
13
14
import { useNavigate } from "react-router-dom" ;
15
+ import * as Yup from "yup" ;
14
16
import { isApiValidationError } from "api/errors" ;
15
17
import { RBACResourceActions } from "api/rbacresources_gen" ;
16
18
import type {
@@ -28,71 +30,129 @@ import {
28
30
FormSection ,
29
31
HorizontalForm ,
30
32
} from "components/Form/Form" ;
31
- import { getFormHelpers } from "utils/formUtils" ;
33
+ import { PageHeader , PageHeaderTitle } from "components/PageHeader/PageHeader" ;
34
+ import { getFormHelpers , nameValidator } from "utils/formUtils" ;
35
+
36
+ const validationSchema = Yup . object ( {
37
+ name : nameValidator ( "Name" ) ,
38
+ } ) ;
32
39
33
40
export type CreateEditRolePageViewProps = {
34
41
role : AssignableRoles | undefined ;
35
- form : ReturnType < typeof useFormik < PatchRoleRequest > > ;
42
+ onSubmit : ( data : PatchRoleRequest ) => void ;
36
43
error ?: unknown ;
37
44
isLoading : boolean ;
45
+ organizationName : string ;
46
+ canAssignOrgRole : boolean ;
47
+ allResources ?: boolean ;
38
48
} ;
39
49
40
50
export const CreateEditRolePageView : FC < CreateEditRolePageViewProps > = ( {
41
51
role,
42
- form ,
52
+ onSubmit ,
43
53
error,
44
54
isLoading,
55
+ organizationName,
56
+ canAssignOrgRole,
57
+ allResources = false ,
45
58
} ) => {
46
59
const navigate = useNavigate ( ) ;
47
- const getFieldHelpers = getFormHelpers < Role > ( form , error ) ;
48
60
const onCancel = ( ) => navigate ( - 1 ) ;
49
61
62
+ const form = useFormik < PatchRoleRequest > ( {
63
+ initialValues : {
64
+ name : role ?. name || "" ,
65
+ display_name : role ?. display_name || "" ,
66
+ site_permissions : role ?. site_permissions || [ ] ,
67
+ organization_permissions : role ?. organization_permissions || [ ] ,
68
+ user_permissions : role ?. user_permissions || [ ] ,
69
+ } ,
70
+ validationSchema,
71
+ onSubmit,
72
+ } ) ;
73
+
74
+ const getFieldHelpers = getFormHelpers < Role > ( form , error ) ;
75
+
50
76
return (
51
- < HorizontalForm onSubmit = { form . handleSubmit } >
52
- < FormSection
53
- title = "Role settings"
54
- description = "Set a name and permissions for this role."
77
+ < >
78
+ < PageHeader
79
+ actions = {
80
+ canAssignOrgRole && (
81
+ < >
82
+ < Button
83
+ onClick = { ( ) => {
84
+ navigate ( `/organizations/${ organizationName } /roles` ) ;
85
+ } }
86
+ >
87
+ Cancel
88
+ </ Button >
89
+ < Button
90
+ variant = "contained"
91
+ color = "primary"
92
+ onClick = { ( ) => {
93
+ form . handleSubmit ( ) ;
94
+ } }
95
+ >
96
+ { role !== undefined ? "Save" : "Create Role" }
97
+ </ Button >
98
+ </ >
99
+ )
100
+ }
55
101
>
56
- < FormFields >
57
- { Boolean ( error ) && ! isApiValidationError ( error ) && (
58
- < ErrorAlert error = { error } />
59
- ) }
60
-
61
- < TextField
62
- { ...getFieldHelpers ( "name" , {
63
- helperText :
64
- "The role name cannot be modified after the role is created." ,
65
- } ) }
66
- autoFocus
67
- fullWidth
68
- disabled = { role !== undefined }
69
- label = "Name"
70
- />
71
- < TextField
72
- { ...getFieldHelpers ( "display_name" , {
73
- helperText : "Optional: keep empty to default to the name." ,
74
- } ) }
75
- fullWidth
76
- label = "Display Name"
77
- />
78
- < ActionCheckboxes
79
- permissions = { role ?. organization_permissions || [ ] }
80
- form = { form }
102
+ < PageHeaderTitle >
103
+ { role ? "Edit" : "Create" } custom role
104
+ </ PageHeaderTitle >
105
+ </ PageHeader >
106
+ < HorizontalForm onSubmit = { form . handleSubmit } >
107
+ < FormSection
108
+ title = "Role settings"
109
+ description = "Set a name and permissions for this role."
110
+ >
111
+ < FormFields >
112
+ { Boolean ( error ) && ! isApiValidationError ( error ) && (
113
+ < ErrorAlert error = { error } />
114
+ ) }
115
+
116
+ < TextField
117
+ { ...getFieldHelpers ( "name" , {
118
+ helperText :
119
+ "The role name cannot be modified after the role is created." ,
120
+ } ) }
121
+ autoFocus
122
+ fullWidth
123
+ disabled = { role !== undefined }
124
+ label = "Name"
125
+ />
126
+ < TextField
127
+ { ...getFieldHelpers ( "display_name" , {
128
+ helperText : "Optional: keep empty to default to the name." ,
129
+ } ) }
130
+ fullWidth
131
+ label = "Display Name"
132
+ />
133
+ < ActionCheckboxes
134
+ permissions = { role ?. organization_permissions || [ ] }
135
+ form = { form }
136
+ allResources = { allResources }
137
+ />
138
+ </ FormFields >
139
+ </ FormSection >
140
+ { canAssignOrgRole && (
141
+ < FormFooter
142
+ onCancel = { onCancel }
143
+ isLoading = { isLoading }
144
+ submitLabel = { role !== undefined ? "Save" : "Create Role" }
81
145
/>
82
- </ FormFields >
83
- </ FormSection >
84
- < FormFooter
85
- onCancel = { onCancel }
86
- isLoading = { isLoading }
87
- submitLabel = { role !== undefined ? "Save" : "Create Role" }
88
- />
89
- </ HorizontalForm >
146
+ ) }
147
+ </ HorizontalForm >
148
+ </ >
90
149
) ;
91
150
} ;
92
151
93
152
interface ActionCheckboxesProps {
94
153
permissions : readonly Permission [ ] | undefined ;
95
154
form : ReturnType < typeof useFormik < Role > > & { values : Role } ;
155
+ allResources : boolean ;
96
156
}
97
157
98
158
const ResourceActionComparator = (
@@ -120,9 +180,13 @@ const filteredRBACResourceActions = Object.fromEntries(
120
180
) ,
121
181
) ;
122
182
123
- const ActionCheckboxes : FC < ActionCheckboxesProps > = ( { permissions, form } ) => {
183
+ const ActionCheckboxes : FC < ActionCheckboxesProps > = ( {
184
+ permissions,
185
+ form,
186
+ allResources,
187
+ } ) => {
124
188
const [ checkedActions , setCheckActions ] = useState ( permissions ) ;
125
- const [ showAllResources , setShowAllResources ] = useState ( false ) ;
189
+ const [ showAllResources , setShowAllResources ] = useState ( allResources ) ;
126
190
127
191
const handleActionCheckChange = async (
128
192
e : ChangeEvent < HTMLInputElement > ,
0 commit comments