diff --git a/apps/studio/components/interfaces/DataWarehouse/CollectionForm.tsx b/apps/studio/components/interfaces/DataWarehouse/CollectionForm.tsx new file mode 100644 index 00000000000..98543751db2 --- /dev/null +++ b/apps/studio/components/interfaces/DataWarehouse/CollectionForm.tsx @@ -0,0 +1,152 @@ +import { zodResolver } from '@hookform/resolvers/zod' +import { useForm } from 'react-hook-form' +import { z } from 'zod' + +import { + Button, + FormControl_Shadcn_, + FormField_Shadcn_, + FormMessage_Shadcn_, + Form_Shadcn_, + Input_Shadcn_, + Modal, +} from 'ui' +import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' +import { useCurrentOrgPlan } from 'hooks/misc/useCurrentOrgPlan' +import { Admonition } from 'ui-patterns' +import { useRouter } from 'next/router' +import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' + +export interface CollectionFormValues { + name: string + retention_days: number +} + +interface CollectionFormProps { + initialValues?: Partial + onSubmit: (values: CollectionFormValues) => void + isLoading?: boolean + onCancelClick: () => void +} + +export const CollectionForm = ({ + initialValues, + onSubmit, + isLoading, + onCancelClick, +}: CollectionFormProps) => { + const { plan, isLoading: planLoading } = useCurrentOrgPlan() + const router = useRouter() + const currentOrg = useSelectedOrganization() + + function getMaxRetentionDays() { + if (planLoading) return 1 + if (plan?.id === 'free') return 3 + else return 90 + } + const maxRetentionDays = getMaxRetentionDays() + + const FormSchema = z.object({ + name: z.string().min(1), + retention_days: z.coerce.number().min(1).max(maxRetentionDays).multipleOf(1).positive().int(), + }) + + const form = useForm({ + resolver: zodResolver(FormSchema), + defaultValues: { + name: initialValues?.name || '', + retention_days: initialValues?.retention_days || maxRetentionDays, + }, + }) + + const handleSubmit = form.handleSubmit(onSubmit) + + const formatDays = (days: number) => { + return days === 1 ? `1 day` : `${days} days` + } + + const retentionDescription = (days: number) => { + if (!Boolean(days) || days < 1) + return <>Your plan allows for a maximum of {formatDays(maxRetentionDays)}. + return ( + <> + Your logs will be removed after {formatDays(days)}.
+ Your plan allows for a maximum of {formatDays(maxRetentionDays)}. + + ) + } + + return ( + +
+ + ( + + + + + + )} + /> + ( + + +
+ + + days + +
+
+
+ )} + /> +
+ + {plan?.id === 'free' && ( + <> + + + Upgrade to the pro plan to increase retention to 90 days. + + + } + /> + + )} + + + + + + +
+ ) +} diff --git a/apps/studio/components/interfaces/DataWarehouse/CreateWarehouseCollection.tsx b/apps/studio/components/interfaces/DataWarehouse/CreateWarehouseCollection.tsx index 08e637a2dce..4b2126065e4 100644 --- a/apps/studio/components/interfaces/DataWarehouse/CreateWarehouseCollection.tsx +++ b/apps/studio/components/interfaces/DataWarehouse/CreateWarehouseCollection.tsx @@ -1,25 +1,10 @@ -import { zodResolver } from '@hookform/resolvers/zod' import { useRouter } from 'next/router' -import { useEffect } from 'react' -import { useForm } from 'react-hook-form' import { toast } from 'sonner' -import { z } from 'zod' import { useParams } from 'common' import { useCreateCollection } from 'data/analytics/warehouse-collections-create-mutation' -import { useCurrentOrgPlan } from 'hooks/misc/useCurrentOrgPlan' -import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' -import { - Button, - FormControl_Shadcn_, - FormField_Shadcn_, - FormMessage_Shadcn_, - Form_Shadcn_, - Input_Shadcn_, - Modal, -} from 'ui' -import { Admonition } from 'ui-patterns/admonition' -import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' +import { Modal } from 'ui' +import { CollectionForm } from './CollectionForm' export const CreateWarehouseCollectionModal = ({ open, @@ -30,8 +15,6 @@ export const CreateWarehouseCollectionModal = ({ }) => { const router = useRouter() const { ref } = useParams() - const { plan, isLoading: planLoading } = useCurrentOrgPlan() - const currentOrg = useSelectedOrganization() const { mutate: createCollection, isLoading } = useCreateCollection({ onSuccess: (data) => { @@ -44,64 +27,6 @@ export const CreateWarehouseCollectionModal = ({ }, }) - function getMaxRetentionDays() { - if (planLoading) return 1 - if (plan?.id === 'free') return 3 - else return 90 - } - const FormSchema = z.object({ - name: z.string().min(1), - retention_days: z.coerce - .number() - .min(1) - .max(getMaxRetentionDays()) - .multipleOf(1) - .positive() - .int(), - }) - - const form = useForm>({ - resolver: zodResolver(FormSchema), - defaultValues: { - retention_days: getMaxRetentionDays(), - }, - }) - - useEffect(() => { - if (!open) { - form.reset() - } - }, [open, form]) - - const onSubmit = form.handleSubmit(async (vals) => { - if (!ref) { - toast.error('Project ref not found') - return - } - createCollection({ - projectRef: ref, - name: vals.name, - retention_days: vals.retention_days, - }) - }) - - const formatDays = (days: number) => { - if (days === 1) return `1 day` - return `${days} days` - } - const retentionDescription = (days: number) => { - const maxRetentionDays = getMaxRetentionDays() - if (planLoading) return '' - if (!Boolean(days) || days < 1) - return <>Your plan allows for a maximum of {formatDays(maxRetentionDays)}. - return ( - <> - Your logs will be removed after {formatDays(days)}.
- Your plan allows for a maximum of {formatDays(maxRetentionDays)}. - - ) - } - return ( - -
- -

- An event collection stores time-based data and related information in Supabase's - analytics system. You can use SQL to analyze this data without affecting the - performance of your main database operations. -

-
- ( - - - - - - )} - /> - ( - - -
- - - days - -
-
-
- )} - /> -
- -
- - {plan?.id === 'free' && ( - <> - - - Upgrade to the pro plan to increase retention to 90 days. - - - } - /> - - )} - - - - - -
+ onOpenChange(false)} + isLoading={isLoading} + onSubmit={(vals) => { + if (!ref) { + return + } + createCollection({ + projectRef: ref, + name: vals.name, + retention_days: vals.retention_days, + }) + }} + />
) } diff --git a/apps/studio/components/interfaces/DataWarehouse/WarehouseMenuItem.tsx b/apps/studio/components/interfaces/DataWarehouse/WarehouseMenuItem.tsx index 6f1548a3110..78977d77feb 100644 --- a/apps/studio/components/interfaces/DataWarehouse/WarehouseMenuItem.tsx +++ b/apps/studio/components/interfaces/DataWarehouse/WarehouseMenuItem.tsx @@ -1,44 +1,32 @@ -import { zodResolver } from '@hookform/resolvers/zod' import { PermissionAction } from '@supabase/shared-types/out/constants' -import { Database, EditIcon, MoreHorizontal, TrashIcon } from 'lucide-react' -import Link from 'next/link' +import { Database, EditIcon, TrashIcon } from 'lucide-react' import { useRouter } from 'next/router' import { useState } from 'react' -import { useForm } from 'react-hook-form' import { toast } from 'sonner' -import { z } from 'zod' -import { FormMessage } from '@ui/components/shadcn/ui/form' import { useParams } from 'common' import { useDeleteCollectionMutation } from 'data/analytics/warehouse-collections-delete-mutation' import { useUpdateCollection } from 'data/analytics/warehouse-collections-update-mutation' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' import { - Button, - DropdownMenu, - DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, - DropdownMenuTrigger, - FormControl_Shadcn_, - FormField_Shadcn_, - Form_Shadcn_, - Input_Shadcn_, Modal, TooltipContent_Shadcn_, TooltipTrigger_Shadcn_, Tooltip_Shadcn_, - cn, } from 'ui' -import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' + import { LogsSidebarItem } from '../Settings/Logs/SidebarV2/SidebarItem' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' +import { CollectionForm } from './CollectionForm' type Props = { item: { id: number token: string name: string + retention_days: number } } @@ -71,16 +59,6 @@ export const WarehouseMenuItem = ({ item }: Props) => { const isLoading = updateCollection.isLoading || deleteCollection.isLoading - const UpdateFormSchema = z.object({ - name: z.string().min(1, { - message: 'Collection name is required', - }), - }) - - const updateForm = useForm>({ - resolver: zodResolver(UpdateFormSchema), - }) - return ( <> { }} > -
Rename collection
+
Update collection
{!canUpdateCollection && ( - You need additional permissions to rename collections + You need additional permissions to update collections )} @@ -140,48 +118,19 @@ export const WarehouseMenuItem = ({ item }: Props) => { hideFooter header={`Update collection "${item.name}"`} > - -
- updateCollection.mutate({ - projectRef, - collectionToken: item.token, - name: data.name, - }) - )} - > - - ( - - - - - - )} - /> - - -
- - -
- -
+ setShowUpdateDialog(false)} + isLoading={isLoading} + initialValues={{ name: item.name, retention_days: item.retention_days }} + onSubmit={({ name, retention_days }) => { + updateCollection.mutate({ + projectRef, + collectionToken: item.token, + name, + retention_days, + }) + }} + /> updateCollection( { projectRef: payload.projectRef, collectionToken: payload.collectionToken }, - { name: payload.name } + { name: payload.name, retention_days: payload.retention_days } ), { async onSuccess(data, variables, context) {