Apply new eslint rules; default to prettier for styling

This commit is contained in:
DaneEveritt 2022-06-26 15:13:52 -04:00
parent f22cce8881
commit dc84af9937
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
218 changed files with 3876 additions and 3564 deletions

View file

@ -3,14 +3,12 @@ import EditSubuserModal from '@/components/server/users/EditSubuserModal';
import { Button } from '@/components/elements/button/index';
export default () => {
const [ visible, setVisible ] = useState(false);
const [visible, setVisible] = useState(false);
return (
<>
<EditSubuserModal visible={visible} onModalDismissed={() => setVisible(false)}/>
<Button onClick={() => setVisible(true)}>
New User
</Button>
<EditSubuserModal visible={visible} onModalDismissed={() => setVisible(false)} />
<Button onClick={() => setVisible(true)}>New User</Button>
</>
);
};

View file

@ -29,22 +29,25 @@ interface Values {
const EditSubuserModal = ({ subuser }: Props) => {
const ref = useRef<HTMLHeadingElement>(null);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const appendSubuser = ServerContext.useStoreActions(actions => actions.subusers.appendSubuser);
const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
const appendSubuser = ServerContext.useStoreActions((actions) => actions.subusers.appendSubuser);
const { clearFlashes, clearAndAddHttpError } = useStoreActions(
(actions: Actions<ApplicationStore>) => actions.flashes
);
const { dismiss, setPropOverrides } = useContext(ModalContext);
const isRootAdmin = useStoreState(state => state.user.data!.rootAdmin);
const permissions = useStoreState(state => state.permissions.data);
const isRootAdmin = useStoreState((state) => state.user.data!.rootAdmin);
const permissions = useStoreState((state) => state.permissions.data);
// The currently logged in user's permissions. We're going to filter out any permissions
// that they should not need.
const loggedInPermissions = ServerContext.useStoreState(state => state.server.permissions);
const [ canEditUser ] = usePermissions(subuser ? [ 'user.update' ] : [ 'user.create' ]);
const loggedInPermissions = ServerContext.useStoreState((state) => state.server.permissions);
const [canEditUser] = usePermissions(subuser ? ['user.update'] : ['user.create']);
// The permissions that can be modified by this user.
const editablePermissions = useDeepCompareMemo(() => {
const cleaned = Object.keys(permissions)
.map(key => Object.keys(permissions[key].keys).map(pkey => `${key}.${pkey}`));
const cleaned = Object.keys(permissions).map((key) =>
Object.keys(permissions[key].keys).map((pkey) => `${key}.${pkey}`)
);
const list: string[] = ([] as string[]).concat.apply([], Object.values(cleaned));
@ -52,19 +55,19 @@ const EditSubuserModal = ({ subuser }: Props) => {
return list;
}
return list.filter(key => loggedInPermissions.indexOf(key) >= 0);
}, [ isRootAdmin, permissions, loggedInPermissions ]);
return list.filter((key) => loggedInPermissions.indexOf(key) >= 0);
}, [isRootAdmin, permissions, loggedInPermissions]);
const submit = (values: Values) => {
setPropOverrides({ showSpinnerOverlay: true });
clearFlashes('user:edit');
createOrUpdateSubuser(uuid, values, subuser)
.then(subuser => {
.then((subuser) => {
appendSubuser(subuser);
dismiss();
})
.catch(error => {
.catch((error) => {
console.error(error);
setPropOverrides(null);
clearAndAddHttpError({ key: 'user:edit', error });
@ -75,17 +78,22 @@ const EditSubuserModal = ({ subuser }: Props) => {
});
};
useEffect(() => () => {
clearFlashes('user:edit');
}, []);
useEffect(
() => () => {
clearFlashes('user:edit');
},
[]
);
return (
<Formik
onSubmit={submit}
initialValues={{
email: subuser?.email || '',
permissions: subuser?.permissions || [],
} as Values}
initialValues={
{
email: subuser?.email || '',
permissions: subuser?.permissions || [],
} as Values
}
validationSchema={object().shape({
email: string()
.max(191, 'Email addresses must not exceed 191 characters.')
@ -97,7 +105,9 @@ const EditSubuserModal = ({ subuser }: Props) => {
<Form>
<div css={tw`flex justify-between`}>
<h2 css={tw`text-2xl`} ref={ref}>
{subuser ? `${canEditUser ? 'Modify' : 'View'} permissions for ${subuser.email}` : 'Create new subuser'}
{subuser
? `${canEditUser ? 'Modify' : 'View'} permissions for ${subuser.email}`
: 'Create new subuser'}
</h2>
<div>
<Button type={'submit'} css={tw`w-full sm:w-auto`}>
@ -106,44 +116,46 @@ const EditSubuserModal = ({ subuser }: Props) => {
</div>
</div>
<FlashMessageRender byKey={'user:edit'} css={tw`mt-4`} />
{(!isRootAdmin && loggedInPermissions[0] !== '*') &&
{!isRootAdmin && loggedInPermissions[0] !== '*' && (
<div css={tw`mt-4 pl-4 py-2 border-l-4 border-cyan-400`}>
<p css={tw`text-sm text-neutral-300`}>
Only permissions which your account is currently assigned may be selected when creating or
modifying other users.
</p>
</div>
}
{!subuser &&
)}
{!subuser && (
<div css={tw`mt-6`}>
<Field
name={'email'}
label={'User Email'}
description={'Enter the email address of the user you wish to invite as a subuser for this server.'}
description={
'Enter the email address of the user you wish to invite as a subuser for this server.'
}
/>
</div>
}
)}
<div css={tw`my-6`}>
{Object.keys(permissions).filter(key => key !== 'websocket').map((key, index) => (
<PermissionTitleBox
key={`permission_${key}`}
title={key}
isEditable={canEditUser}
permissions={Object.keys(permissions[key].keys).map(pkey => `${key}.${pkey}`)}
css={index > 0 ? tw`mt-4` : undefined}
>
<p css={tw`text-sm text-neutral-400 mb-4`}>
{permissions[key].description}
</p>
{Object.keys(permissions[key].keys).map(pkey => (
<PermissionRow
key={`permission_${key}.${pkey}`}
permission={`${key}.${pkey}`}
disabled={!canEditUser || editablePermissions.indexOf(`${key}.${pkey}`) < 0}
/>
))}
</PermissionTitleBox>
))}
{Object.keys(permissions)
.filter((key) => key !== 'websocket')
.map((key, index) => (
<PermissionTitleBox
key={`permission_${key}`}
title={key}
isEditable={canEditUser}
permissions={Object.keys(permissions[key].keys).map((pkey) => `${key}.${pkey}`)}
css={index > 0 ? tw`mt-4` : undefined}
>
<p css={tw`text-sm text-neutral-400 mb-4`}>{permissions[key].description}</p>
{Object.keys(permissions[key].keys).map((pkey) => (
<PermissionRow
key={`permission_${key}.${pkey}`}
permission={`${key}.${pkey}`}
disabled={!canEditUser || editablePermissions.indexOf(`${key}.${pkey}`) < 0}
/>
))}
</PermissionTitleBox>
))}
</div>
<Can action={subuser ? 'user.update' : 'user.create'}>
<div css={tw`pb-6 flex justify-end`}>

View file

@ -6,28 +6,28 @@ import { useStoreState } from 'easy-peasy';
import Label from '@/components/elements/Label';
const Container = styled.label`
${tw`flex items-center border border-transparent rounded md:p-2 transition-colors duration-75`};
text-transform: none;
${tw`flex items-center border border-transparent rounded md:p-2 transition-colors duration-75`};
text-transform: none;
&:not(.disabled) {
${tw`cursor-pointer`};
&:not(.disabled) {
${tw`cursor-pointer`};
&:hover {
${tw`border-neutral-500 bg-neutral-800`};
}
}
&:not(:first-of-type) {
${tw`mt-4 sm:mt-2`};
}
&:hover {
${tw`border-neutral-500 bg-neutral-800`};
}
}
&.disabled {
${tw`opacity-50`};
&:not(:first-of-type) {
${tw`mt-4 sm:mt-2`};
}
& input[type="checkbox"]:not(:checked) {
${tw`border-0`};
}
}
&.disabled {
${tw`opacity-50`};
& input[type='checkbox']:not(:checked) {
${tw`border-0`};
}
}
`;
interface Props {
@ -36,8 +36,8 @@ interface Props {
}
const PermissionRow = ({ permission, disabled }: Props) => {
const [ key, pkey ] = permission.split('.', 2);
const permissions = useStoreState(state => state.permissions.data);
const [key, pkey] = permission.split('.', 2);
const permissions = useStoreState((state) => state.permissions.data);
return (
<Container htmlFor={`permission_${permission}`} className={disabled ? 'disabled' : undefined}>
@ -51,12 +51,12 @@ const PermissionRow = ({ permission, disabled }: Props) => {
/>
</div>
<div css={tw`flex-1`}>
<Label as={'p'} css={tw`font-medium`}>{pkey}</Label>
{permissions[key].keys[pkey].length > 0 &&
<p css={tw`text-xs text-neutral-400 mt-1`}>
{permissions[key].keys[pkey]}
</p>
}
<Label as={'p'} css={tw`font-medium`}>
{pkey}
</Label>
{permissions[key].keys[pkey].length > 0 && (
<p css={tw`text-xs text-neutral-400 mt-1`}>{permissions[key].keys[pkey]}</p>
)}
</div>
</Container>
);

View file

@ -13,31 +13,31 @@ interface Props {
}
const PermissionTitleBox: React.FC<Props> = memo(({ isEditable, title, permissions, className, children }) => {
const [ { value }, , { setValue } ] = useField<string[]>('permissions');
const [{ value }, , { setValue }] = useField<string[]>('permissions');
const onCheckboxClicked = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
if (e.currentTarget.checked) {
setValue([
...value,
...permissions.filter(p => !value.includes(p)),
]);
} else {
setValue(value.filter(p => !permissions.includes(p)));
}
}, [ permissions, value ]);
const onCheckboxClicked = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
if (e.currentTarget.checked) {
setValue([...value, ...permissions.filter((p) => !value.includes(p))]);
} else {
setValue(value.filter((p) => !permissions.includes(p)));
}
},
[permissions, value]
);
return (
<TitledGreyBox
title={
<div css={tw`flex items-center`}>
<p css={tw`text-sm uppercase flex-1`}>{title}</p>
{isEditable &&
<Input
type={'checkbox'}
checked={permissions.every(p => value.includes(p))}
onChange={onCheckboxClicked}
/>
}
{isEditable && (
<Input
type={'checkbox'}
checked={permissions.every((p) => value.includes(p))}
onChange={onCheckboxClicked}
/>
)}
</div>
}
className={className}

View file

@ -11,11 +11,11 @@ import { httpErrorToHuman } from '@/api/http';
import tw from 'twin.macro';
export default ({ subuser }: { subuser: Subuser }) => {
const [ loading, setLoading ] = useState(false);
const [ showConfirmation, setShowConfirmation ] = useState(false);
const [loading, setLoading] = useState(false);
const [showConfirmation, setShowConfirmation] = useState(false);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const removeSubuser = ServerContext.useStoreActions(actions => actions.subusers.removeSubuser);
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
const removeSubuser = ServerContext.useStoreActions((actions) => actions.subusers.removeSubuser);
const { addError, clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
const doDeletion = () => {
@ -26,7 +26,7 @@ export default ({ subuser }: { subuser: Subuser }) => {
setLoading(false);
removeSubuser(subuser.uuid);
})
.catch(error => {
.catch((error) => {
console.error(error);
addError({ key: 'users', message: httpErrorToHuman(error) });
setShowConfirmation(false);
@ -52,7 +52,7 @@ export default ({ subuser }: { subuser: Subuser }) => {
css={tw`block text-sm p-2 text-neutral-500 hover:text-red-600 transition-colors duration-150`}
onClick={() => setShowConfirmation(true)}
>
<FontAwesomeIcon icon={faTrashAlt}/>
<FontAwesomeIcon icon={faTrashAlt} />
</button>
</>
);

View file

@ -14,18 +14,14 @@ interface Props {
}
export default ({ subuser }: Props) => {
const uuid = useStoreState(state => state.user!.data!.uuid);
const [ visible, setVisible ] = useState(false);
const uuid = useStoreState((state) => state.user!.data!.uuid);
const [visible, setVisible] = useState(false);
return (
<GreyRowBox css={tw`mb-2`}>
<EditSubuserModal
subuser={subuser}
visible={visible}
onModalDismissed={() => setVisible(false)}
/>
<EditSubuserModal subuser={subuser} visible={visible} onModalDismissed={() => setVisible(false)} />
<div css={tw`w-10 h-10 rounded-full bg-white border-2 border-neutral-800 overflow-hidden hidden md:block`}>
<img css={tw`w-full h-full`} src={`${subuser.image}?s=400`}/>
<img css={tw`w-full h-full`} src={`${subuser.image}?s=400`} />
</div>
<div css={tw`ml-4 flex-1 overflow-hidden`}>
<p css={tw`text-sm truncate`}>{subuser.email}</p>
@ -44,11 +40,11 @@ export default ({ subuser }: Props) => {
</div>
<div css={tw`ml-4 hidden md:block`}>
<p css={tw`font-medium text-center`}>
{subuser.permissions.filter(permission => permission !== 'websocket.connect').length}
{subuser.permissions.filter((permission) => permission !== 'websocket.connect').length}
</p>
<p css={tw`text-2xs text-neutral-500 uppercase`}>Permissions</p>
</div>
{subuser.uuid !== uuid &&
{subuser.uuid !== uuid && (
<>
<Can action={'user.update'}>
<button
@ -64,7 +60,7 @@ export default ({ subuser }: Props) => {
<RemoveSubuserButton subuser={subuser} />
</Can>
</>
}
)}
</GreyRowBox>
);
};

View file

@ -13,11 +13,11 @@ import ServerContentBlock from '@/components/elements/ServerContentBlock';
import tw from 'twin.macro';
export default () => {
const [ loading, setLoading ] = useState(true);
const [loading, setLoading] = useState(true);
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const subusers = ServerContext.useStoreState(state => state.subusers.data);
const setSubusers = ServerContext.useStoreActions(actions => actions.subusers.setSubusers);
const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid);
const subusers = ServerContext.useStoreState((state) => state.subusers.data);
const setSubusers = ServerContext.useStoreActions((actions) => actions.subusers.setSubusers);
const permissions = useStoreState((state: ApplicationStore) => state.permissions.data);
const getPermissions = useStoreActions((actions: Actions<ApplicationStore>) => actions.permissions.getPermissions);
@ -26,42 +26,38 @@ export default () => {
useEffect(() => {
clearFlashes('users');
getServerSubusers(uuid)
.then(subusers => {
.then((subusers) => {
setSubusers(subusers);
setLoading(false);
})
.catch(error => {
.catch((error) => {
console.error(error);
addError({ key: 'users', message: httpErrorToHuman(error) });
});
}, []);
useEffect(() => {
getPermissions().catch(error => {
getPermissions().catch((error) => {
addError({ key: 'users', message: httpErrorToHuman(error) });
console.error(error);
});
}, []);
if (!subusers.length && (loading || !Object.keys(permissions).length)) {
return <Spinner size={'large'} centered/>;
return <Spinner size={'large'} centered />;
}
return (
<ServerContentBlock title={'Users'}>
<FlashMessageRender byKey={'users'} css={tw`mb-4`}/>
{!subusers.length ?
<p css={tw`text-center text-sm text-neutral-300`}>
It looks like you don&apos;t have any subusers.
</p>
:
subusers.map(subuser => (
<UserRow key={subuser.uuid} subuser={subuser}/>
))
}
<FlashMessageRender byKey={'users'} css={tw`mb-4`} />
{!subusers.length ? (
<p css={tw`text-center text-sm text-neutral-300`}>It looks like you don&apos;t have any subusers.</p>
) : (
subusers.map((subuser) => <UserRow key={subuser.uuid} subuser={subuser} />)
)}
<Can action={'user.create'}>
<div css={tw`flex justify-end mt-6`}>
<AddSubuserButton/>
<AddSubuserButton />
</div>
</Can>
</ServerContentBlock>