diff --git a/apps/dashboard/src/app/(onboarding)/onboarding/onboarding-tracking.tsx b/apps/dashboard/src/app/(onboarding)/onboarding/onboarding-tracking.tsx index db7e0aa3..db62506c 100644 --- a/apps/dashboard/src/app/(onboarding)/onboarding/onboarding-tracking.tsx +++ b/apps/dashboard/src/app/(onboarding)/onboarding/onboarding-tracking.tsx @@ -50,7 +50,8 @@ const Tracking = ({ defaultValues: { organization: '', project: '', - domain: null, + domain: '', + cors: [], website: false, app: false, backend: false, @@ -75,6 +76,7 @@ const Tracking = ({ useEffect(() => { if (!isWebsite) { form.setValue('domain', null); + form.setValue('cors', []); } }, [isWebsite, form]); @@ -156,36 +158,53 @@ const Tracking = ({ >
+ { + const value = e.target.value.trim(); + if ( + value.includes('.') && + form.getValues().cors.length === 0 && + !form.formState.errors.domain + ) { + form.setValue('cors', [value]); + } + }} + /> + ( - + - tag === '*' ? 'Allow all domains' : tag + tag === '*' + ? 'Accept events from any domains' + : tag } onChange={(newValue) => { field.onChange( - newValue - .map((item) => { - const trimmed = item.trim(); - if ( - trimmed.startsWith('http://') || - trimmed.startsWith('https://') || - trimmed === '*' - ) { - return trimmed; - } - return `https://${trimmed}`; - }) - .join(','), + newValue.map((item) => { + const trimmed = item.trim(); + if ( + trimmed.startsWith('http://') || + trimmed.startsWith('https://') || + trimmed === '*' + ) { + return trimmed; + } + return `https://${trimmed}`; + }), ); }} /> diff --git a/apps/dashboard/src/components/projects/project-actions.tsx b/apps/dashboard/src/components/projects/project-actions.tsx deleted file mode 100644 index 34a7f743..00000000 --- a/apps/dashboard/src/components/projects/project-actions.tsx +++ /dev/null @@ -1,56 +0,0 @@ -'use client'; - -import { pushModal, showConfirm } from '@/modals'; -import { api } from '@/trpc/client'; -import { Edit2Icon, TrashIcon } from 'lucide-react'; -import { useRouter } from 'next/navigation'; -import { toast } from 'sonner'; - -import type { IServiceProject } from '@openpanel/db'; - -import { Button } from '../ui/button'; - -export function ProjectActions(project: Exclude) { - const { id } = project; - const router = useRouter(); - const deletion = api.project.remove.useMutation({ - onSuccess() { - toast('Success', { - description: 'Project deleted successfully.', - }); - router.refresh(); - }, - }); - - return ( -
- - -
- ); -} diff --git a/apps/dashboard/src/components/projects/table.tsx b/apps/dashboard/src/components/projects/table.tsx deleted file mode 100644 index 33bf7404..00000000 --- a/apps/dashboard/src/components/projects/table.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { formatDate } from '@/utils/date'; -import type { ColumnDef } from '@tanstack/react-table'; - -import type { IServiceProject } from '@openpanel/db'; - -import { ACTIONS } from '../data-table'; -import { ProjectActions } from './project-actions'; - -export type Project = IServiceProject; -export const columns: ColumnDef[] = [ - { - accessorKey: 'name', - header: 'Name', - }, - { - accessorKey: 'createdAt', - header: 'Created at', - cell({ row }) { - const date = row.original.createdAt; - return
{formatDate(date)}
; - }, - }, - { - id: ACTIONS, - header: 'Actions', - cell: ({ row }) => , - }, -]; diff --git a/apps/dashboard/src/modals/EditProject.tsx b/apps/dashboard/src/modals/EditProject.tsx deleted file mode 100644 index 12e45bc4..00000000 --- a/apps/dashboard/src/modals/EditProject.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { ButtonContainer } from '@/components/button-container'; -import { InputWithLabel } from '@/components/forms/input-with-label'; -import { Button } from '@/components/ui/button'; -import { api, handleError } from '@/trpc/client'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { useRouter } from 'next/navigation'; -import { useForm } from 'react-hook-form'; -import { toast } from 'sonner'; -import { z } from 'zod'; - -import type { IServiceProject } from '@openpanel/db'; - -import { popModal } from '.'; -import { ModalContent, ModalHeader } from './Modal/Container'; - -type EditProjectProps = Exclude; - -const validator = z.object({ - id: z.string().min(1), - name: z.string().min(1), -}); - -type IForm = z.infer; - -export default function EditProject({ id, name }: EditProjectProps) { - const router = useRouter(); - const { register, handleSubmit, reset, formState } = useForm({ - resolver: zodResolver(validator), - defaultValues: { - id, - name, - }, - }); - - const mutation = api.project.update.useMutation({ - onError: handleError, - onSuccess() { - reset(); - router.refresh(); - toast('Success', { - description: 'Project updated.', - }); - popModal(); - }, - }); - - return ( - - -
{ - mutation.mutate(values); - })} - > - - - - - - -
- ); -} diff --git a/apps/dashboard/src/modals/index.tsx b/apps/dashboard/src/modals/index.tsx index 58a917a8..ef74fcae 100644 --- a/apps/dashboard/src/modals/index.tsx +++ b/apps/dashboard/src/modals/index.tsx @@ -20,9 +20,6 @@ const modals = { EventDetails: dynamic(() => import('./event-details'), { loading: Loading, }), - EditProject: dynamic(() => import('./EditProject'), { - loading: Loading, - }), EditClient: dynamic(() => import('./EditClient'), { loading: Loading, }), diff --git a/packages/trpc/src/routers/onboarding.ts b/packages/trpc/src/routers/onboarding.ts index beda7e74..d38f3015 100644 --- a/packages/trpc/src/routers/onboarding.ts +++ b/packages/trpc/src/routers/onboarding.ts @@ -88,12 +88,18 @@ export const onboardingRouter = createTRPCRouter({ }); } + if (input.cors.length === 0 && input.website) { + input.cors.push('*'); + } + const project = await db.project.create({ data: { id: await getId('project', input.project), name: input.project, organizationId: organization.id, types, + domain: input.domain ? stripTrailingSlash(input.domain) : null, + cors: input.cors.map((c) => stripTrailingSlash(c)), }, }); diff --git a/packages/trpc/src/routers/project.ts b/packages/trpc/src/routers/project.ts index 87d9e7e4..59b6a4ed 100644 --- a/packages/trpc/src/routers/project.ts +++ b/packages/trpc/src/routers/project.ts @@ -9,6 +9,7 @@ import { getProjectsByOrganizationId, } from '@openpanel/db'; +import { stripTrailingSlash } from '@openpanel/common'; import { zProject } from '@openpanel/validation'; import { getProjectAccess } from '../access'; import { TRPCAccessError } from '../errors'; @@ -50,8 +51,8 @@ export const projectRouter = createTRPCRouter({ name: input.name, crossDomain: input.crossDomain, filters: input.filters, - cors: input.cors, - domain: input.domain, + domain: input.domain ? stripTrailingSlash(input.domain) : null, + cors: input.cors?.map((c) => stripTrailingSlash(c)) || [], }, include: { clients: { diff --git a/packages/validation/src/index.ts b/packages/validation/src/index.ts index 6c9845a7..22499cd4 100644 --- a/packages/validation/src/index.ts +++ b/packages/validation/src/index.ts @@ -113,6 +113,7 @@ export const zOnboardingProject = z organizationId: z.string().optional(), project: z.string().min(3), domain: z.string().url().or(z.literal('').or(z.null())), + cors: z.array(z.string()).default([]), website: z.boolean(), app: z.boolean(), backend: z.boolean(),