TableDefinition.tsx123 lines · main
1import Editor from '@monaco-editor/react'
2import { useParams } from 'common'
3import { useTheme } from 'next-themes'
4import Link from 'next/link'
5import { useMemo, useRef } from 'react'
6import { Button } from 'ui'
7import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
8
9import { Footer } from '@/components/grid/components/footer/Footer'
10import { useTableDefinitionQuery } from '@/data/database/table-definition-query'
11import { useViewDefinitionQuery } from '@/data/database/view-definition-query'
12import { Entity, isTableLike, isViewLike } from '@/data/table-editor/table-editor-types'
13import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
14import { formatSql } from '@/lib/formatSql'
15import { timeout } from '@/lib/helpers'
16
17export interface TableDefinitionProps {
18 entity?: Entity
19}
20
21export const TableDefinition = ({ entity }: TableDefinitionProps) => {
22 const { ref } = useParams()
23 const editorRef = useRef(null)
24 const monacoRef = useRef(null)
25 const { resolvedTheme } = useTheme()
26 const { data: project } = useSelectedProjectQuery()
27
28 const viewResult = useViewDefinitionQuery(
29 {
30 id: entity?.id,
31 includeCreateStatement: true,
32 projectRef: project?.ref,
33 connectionString: project?.connectionString,
34 },
35 {
36 enabled: isViewLike(entity),
37 }
38 )
39
40 const tableResult = useTableDefinitionQuery(
41 {
42 id: entity?.id,
43 projectRef: project?.ref,
44 connectionString: project?.connectionString,
45 },
46 {
47 enabled: isTableLike(entity),
48 }
49 )
50
51 const { data: definition, isLoading } = isViewLike(entity) ? viewResult : tableResult
52
53 const formattedDefinition = useMemo(
54 () => (definition ? formatSql(definition) : undefined),
55 [definition]
56 )
57
58 const handleEditorOnMount = async (editor: any, monaco: any) => {
59 editorRef.current = editor
60 monacoRef.current = monaco
61
62 // add margin above first line
63 editor.changeViewZones((accessor: any) => {
64 accessor.addZone({
65 afterLineNumber: 0,
66 heightInPx: 4,
67 domNode: document.createElement('div'),
68 })
69 })
70
71 // when editor did mount, it will need a delay before focus() works properly
72 await timeout(500)
73 editor?.focus()
74 }
75
76 if (isLoading) {
77 return (
78 <div className="h-full grid">
79 <div className="p-4">
80 <GenericSkeletonLoader />
81 </div>
82 <div className="mt-auto">
83 <Footer />
84 </div>
85 </div>
86 )
87 }
88
89 return (
90 <>
91 <div className="grow overflow-y-auto border-t border-muted relative">
92 <Button asChild type="default" className="absolute top-2 right-5 z-10">
93 <Link
94 href={`/project/${ref}/sql/new?content=${encodeURIComponent(
95 formattedDefinition ?? ''
96 )}`}
97 >
98 Open in SQL Editor
99 </Link>
100 </Button>
101 <Editor
102 className="monaco-editor"
103 theme={resolvedTheme?.includes('dark') ? 'vs-dark' : 'vs'}
104 onMount={handleEditorOnMount}
105 defaultLanguage="pgsql"
106 value={formattedDefinition}
107 path={''}
108 options={{
109 domReadOnly: true,
110 readOnly: true,
111 tabSize: 2,
112 fontSize: 13,
113 minimap: { enabled: false },
114 wordWrap: 'on',
115 fixedOverflowWidgets: true,
116 }}
117 />
118 </div>
119
120 <Footer />
121 </>
122 )
123}