diff --git a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyRoles.tsx b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyRoles.tsx index 39f620969bc..42a935d974c 100644 --- a/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyRoles.tsx +++ b/apps/studio/components/interfaces/Auth/Policies/PolicyEditor/PolicyRoles.tsx @@ -5,11 +5,13 @@ import AlertError from 'components/ui/AlertError' import MultiSelect from 'components/ui/MultiSelect' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query' +import { sortBy } from 'lodash' interface PolicyRolesProps { selectedRoles: string[] onUpdateSelectedRoles: (roles: string[]) => void } +type SystemRole = (typeof SYSTEM_ROLES)[number] const PolicyRoles = ({ selectedRoles, onUpdateSelectedRoles }: PolicyRolesProps) => { const { project } = useProjectContext() @@ -17,9 +19,10 @@ const PolicyRoles = ({ selectedRoles, onUpdateSelectedRoles }: PolicyRolesProps) projectRef: project?.ref, connectionString: project?.connectionString, }) - const roles = (data ?? []) - .filter((role) => !SYSTEM_ROLES.includes(role.name)) - .sort((a, b) => a.name.localeCompare(b.name)) + const roles = sortBy( + (data ?? []).filter((role) => !SYSTEM_ROLES.includes(role.name as SystemRole)), + (r) => r.name.toLocaleLowerCase() + ) const formattedRoles = roles.map((role) => { return { diff --git a/apps/studio/components/interfaces/Database/Roles/CreateRolePanel.tsx b/apps/studio/components/interfaces/Database/Roles/CreateRolePanel.tsx index d8f8d8be7aa..64d3c815fc2 100644 --- a/apps/studio/components/interfaces/Database/Roles/CreateRolePanel.tsx +++ b/apps/studio/components/interfaces/Database/Roles/CreateRolePanel.tsx @@ -1,10 +1,21 @@ -import * as Tooltip from '@radix-ui/react-tooltip' -import { useRef } from 'react' +import { zodResolver } from '@hookform/resolvers/zod' +import { SubmitHandler, useForm } from 'react-hook-form' import toast from 'react-hot-toast' -import { Button, Form, IconHelpCircle, Input, SidePanel, Toggle } from 'ui' +import { + FormControl_Shadcn_, + FormField_Shadcn_, + FormItem_Shadcn_, + FormLabel_Shadcn_, + FormMessage_Shadcn_, + Form_Shadcn_, + Input_Shadcn_, + SidePanel, + Switch, +} from 'ui' +import z from 'zod' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' -import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms' +import { FormActions } from 'components/ui/Forms' import { useDatabaseRoleCreateMutation } from 'data/database-roles/database-role-create-mutation' import { ROLE_PERMISSIONS } from './Roles.constants' @@ -13,26 +24,34 @@ interface CreateRolePanelProps { onClose: () => void } +const FormSchema = z.object({ + name: z.string().trim().min(1, 'You must provide a name').default(''), + is_superuser: z.boolean().default(false), + can_login: z.boolean().default(false), + can_create_role: z.boolean().default(false), + can_create_db: z.boolean().default(false), + is_replication_role: z.boolean().default(false), + can_bypass_rls: z.boolean().default(false), +}) + +const initialValues = { + name: '', + is_superuser: false, + can_login: false, + can_create_role: false, + can_create_db: false, + is_replication_role: false, + can_bypass_rls: false, +} + const CreateRolePanel = ({ visible, onClose }: CreateRolePanelProps) => { const formId = 'create-new-role' - const submitRef: any = useRef() + const { project } = useProjectContext() - const initialValues = { - name: '', - is_superuser: false, - can_login: false, - can_create_role: false, - can_create_db: false, - is_replication_role: false, - can_bypass_rls: false, - } - - const validate = (values: any) => { - const errors: any = {} - if (values.name.length === 0) errors.name = 'Please provide a name for your role' - return errors - } + const form = useForm>({ + resolver: zodResolver(FormSchema), + }) const { mutate: createDatabaseRole, isLoading: isCreating } = useDatabaseRoleCreateMutation({ onSuccess: (res) => { @@ -41,7 +60,7 @@ const CreateRolePanel = ({ visible, onClose }: CreateRolePanelProps) => { }, }) - const onSubmit = async (values: any) => { + const onSubmit: SubmitHandler> = async (values) => { if (!project) return console.error('Project is required') createDatabaseRole({ projectRef: project.ref, @@ -50,6 +69,11 @@ const CreateRolePanel = ({ visible, onClose }: CreateRolePanelProps) => { }) } + const handleClose = () => { + onClose() + form.reset() + } + return ( { header="Create a new role" className="mr-0 transform transition-all duration-300 ease-in-out" loading={false} - onCancel={onClose} + onCancel={handleClose} customFooter={
- - + form.reset()} + />
} > -
- {({ isSubmitting, handleReset, values, initialValues }: any) => { - return ( -
- Role Configuration - } - > - - - - - - Role Privileges - } - > - -
- {Object.keys(ROLE_PERMISSIONS).map((permission) => ( - - - - - - -
- - This privilege cannot be granted via the dashboard - -
-
- - ) - } - /> - ))} -
-
-
-