1- import React , { forwardRef , useRef } from 'react' ;
1+ import React , { forwardRef , useEffect , useRef } from 'react' ;
22import { Subuser } from '@/state/server/subusers' ;
33import { Form , Formik , FormikHelpers , useFormikContext } from 'formik' ;
44import { array , object , string } from 'yup' ;
@@ -16,6 +16,7 @@ import { httpErrorToHuman } from '@/api/http';
1616import FlashMessageRender from '@/components/FlashMessageRender' ;
1717import Can from '@/components/elements/Can' ;
1818import { usePermissions } from '@/plugins/usePermissions' ;
19+ import { useDeepMemo } from '@/plugins/useDeepMemo' ;
1920
2021type Props = {
2122 subuser ?: Subuser ;
@@ -37,12 +38,38 @@ const PermissionLabel = styled.label`
3738 ${ tw `border-neutral-500 bg-neutral-800` } ;
3839 }
3940 }
41+
42+ &.disabled {
43+ ${ tw `opacity-50` } ;
44+
45+ & input[type="checkbox"]:not(:checked) {
46+ ${ tw `border-0` } ;
47+ }
48+ }
4049` ;
4150
4251const EditSubuserModal = forwardRef < HTMLHeadingElement , Props > ( ( { subuser, ...props } , ref ) => {
4352 const { values, isSubmitting, setFieldValue } = useFormikContext < Values > ( ) ;
44- const [ canEditUser ] = usePermissions ( [ 'user.update' ] ) ;
45- const permissions = useStoreState ( ( state : ApplicationStore ) => state . permissions . data ) ;
53+ const [ canEditUser ] = usePermissions ( subuser ? [ 'user.update' ] : [ 'user.create' ] ) ;
54+ const permissions = useStoreState ( state => state . permissions . data ) ;
55+
56+ // The currently logged in user's permissions. We're going to filter out any permissions
57+ // that they should not need.
58+ const loggedInPermissions = ServerContext . useStoreState ( state => state . server . permissions ) ;
59+
60+ // The permissions that can be modified by this user.
61+ const editablePermissions = useDeepMemo ( ( ) => {
62+ const cleaned = Object . keys ( permissions )
63+ . map ( key => Object . keys ( permissions [ key ] . keys ) . map ( pkey => `${ key } .${ pkey } ` ) ) ;
64+
65+ const list : string [ ] = ( [ ] as string [ ] ) . concat . apply ( [ ] , Object . values ( cleaned ) ) ;
66+
67+ if ( loggedInPermissions . length === 1 && loggedInPermissions [ 0 ] === '*' ) {
68+ return list ;
69+ }
70+
71+ return list . filter ( key => loggedInPermissions . indexOf ( key ) >= 0 ) ;
72+ } , [ permissions , loggedInPermissions ] ) ;
4673
4774 return (
4875 < Modal { ...props } top = { false } showSpinnerOverlay = { isSubmitting } >
@@ -54,6 +81,12 @@ const EditSubuserModal = forwardRef<HTMLHeadingElement, Props>(({ subuser, ...pr
5481 }
5582 </ h3 >
5683 < FlashMessageRender byKey = { 'user:edit' } className = { 'mt-4' } />
84+ < div className = { 'mt-4 pl-4 py-2 border-l-4 border-cyan-400' } >
85+ < p className = { 'text-sm text-neutral-300' } >
86+ Only permissions which your account is currently assigned may be selected when creating or
87+ modifying other users.
88+ </ p >
89+ </ div >
5790 { ! subuser &&
5891 < div className = { 'mt-6' } >
5992 < Field
@@ -70,7 +103,7 @@ const EditSubuserModal = forwardRef<HTMLHeadingElement, Props>(({ subuser, ...pr
70103 title = {
71104 < div className = { 'flex items-center' } >
72105 < p className = { 'text-sm uppercase flex-1' } > { key } </ p >
73- { canEditUser &&
106+ { canEditUser && editablePermissions . indexOf ( key ) >= 0 &&
74107 < input
75108 type = { 'checkbox' }
76109 onClick = { e => {
@@ -106,7 +139,7 @@ const EditSubuserModal = forwardRef<HTMLHeadingElement, Props>(({ subuser, ...pr
106139 htmlFor = { `permission_${ key } _${ pkey } ` }
107140 className = { classNames ( 'transition-colors duration-75' , {
108141 'mt-2' : index !== 0 ,
109- disabled : ! canEditUser ,
142+ disabled : ! canEditUser || editablePermissions . indexOf ( ` ${ key } . ${ pkey } ` ) < 0 ,
110143 } ) }
111144 >
112145 < div className = { 'p-2' } >
@@ -115,7 +148,7 @@ const EditSubuserModal = forwardRef<HTMLHeadingElement, Props>(({ subuser, ...pr
115148 name = { 'permissions' }
116149 value = { `${ key } .${ pkey } ` }
117150 className = { 'w-5 h-5 mr-2' }
118- disabled = { ! canEditUser }
151+ disabled = { ! canEditUser || editablePermissions . indexOf ( ` ${ key } . ${ pkey } ` ) < 0 }
119152 />
120153 </ div >
121154 < div className = { 'flex-1' } >
@@ -133,7 +166,7 @@ const EditSubuserModal = forwardRef<HTMLHeadingElement, Props>(({ subuser, ...pr
133166 </ TitledGreyBox >
134167 ) ) }
135168 </ div >
136- < Can action = { subuser ? 'user.update' : 'user.delete ' } >
169+ < Can action = { subuser ? 'user.update' : 'user.create ' } >
137170 < div className = { 'pb-6 flex justify-end' } >
138171 < button className = { 'btn btn-primary btn-sm' } type = { 'submit' } >
139172 { subuser ? 'Save' : 'Invite User' }
@@ -169,6 +202,10 @@ export default ({ subuser, ...props }: Props) => {
169202 } ) ;
170203 } ;
171204
205+ useEffect ( ( ) => {
206+ clearFlashes ( 'user:edit' ) ;
207+ } , [ ] ) ;
208+
172209 return (
173210 < Formik
174211 onSubmit = { submit }
0 commit comments