TableDefinition.tsx 3.4 KB

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