SQLTemplates.tsx100 lines · main
1// @ts-nocheck
2import { PermissionAction } from '@supabase/shared-types/out/constants'
3import { useParams } from 'common'
4import { partition } from 'lodash'
5import { useRouter } from 'next/router'
6import { toast } from 'sonner'
7import { cn, SQL_ICON } from 'ui'
8
9import { createSqlSnippetSkeletonV2 } from '../SQLEditor.utils'
10import { SQL_TEMPLATES } from '@/components/interfaces/SQLEditor/SQLEditor.queries'
11import { ActionCard } from '@/components/layouts/Tabs/ActionCard'
12import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
13import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
14import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
15import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
16import { useProfile } from '@/lib/profile'
17import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
18
19const SQLTemplates = () => {
20 const router = useRouter()
21 const { ref } = useParams()
22 const { profile } = useProfile()
23 const { data: project } = useSelectedProjectQuery()
24 const { data: org } = useSelectedOrganizationQuery()
25 const [sql] = partition(SQL_TEMPLATES, { type: 'template' })
26
27 const snapV2 = useSqlEditorV2StateSnapshot()
28
29 const { can: canCreateSQLSnippet } = useAsyncCheckPermissions(
30 PermissionAction.CREATE,
31 'user_content',
32 {
33 resource: { type: 'sql', owner_id: profile?.id },
34 subject: { id: profile?.id },
35 }
36 )
37
38 const { mutate: sendEvent } = useSendEventMutation()
39
40 const handleNewQuery = async (sql: string, name: string) => {
41 if (!ref) return console.error('Project ref is required')
42 if (!project) return console.error('Project is required')
43 if (!profile) return console.error('Profile is required')
44
45 if (!canCreateSQLSnippet) {
46 return toast('Your queries will not be saved as you do not have sufficient permissions')
47 }
48
49 try {
50 const snippet = createSqlSnippetSkeletonV2({
51 name,
52 sql,
53 owner_id: profile?.id,
54 project_id: project?.id,
55 })
56 snapV2.addSnippet({ projectRef: ref, snippet })
57 snapV2.addNeedsSaving(snippet.id)
58
59 router.push(`/project/${ref}/sql/${snippet.id}`)
60 } catch (error: any) {
61 toast.error(`Failed to create new query: ${error.message}`)
62 }
63 }
64
65 return (
66 <div className="block h-full space-y-8 overflow-y-auto p-6 px-10 bg-dash-sidebar dark:bg-surface-100">
67 <div>
68 <div className="mb-6">
69 <h2 className="mb-1">Scripts</h2>
70 <p className="text-foreground-light text-sm">Quick scripts to run on your database.</p>
71 <p className="text-foreground-light text-sm">
72 Click on any script to fill the query box, modify the script, then click
73 <span className="text-code">Run</span>.
74 </p>
75 </div>
76 <div className="grid gap-4 sm:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 ">
77 {sql.map((x, i) => (
78 <ActionCard
79 key={`action-card-${i}`}
80 title={x.title}
81 description={x.description}
82 bgColor="bg-alternative border"
83 icon={<SQL_ICON className={cn('fill-foreground', 'w-4 h-4')} strokeWidth={1.5} />}
84 onClick={() => {
85 handleNewQuery(x.sql, x.title)
86 sendEvent({
87 action: 'sql_editor_template_clicked',
88 properties: { templateName: x.title },
89 groups: { project: ref ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
90 })
91 }}
92 />
93 ))}
94 </div>
95 </div>
96 </div>
97 )
98}
99
100export default SQLTemplates