hooks.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useParams } from 'common'
  3. import { useRouter } from 'next/router'
  4. import { useCallback, useEffect, useMemo, useState } from 'react'
  5. import { toast } from 'sonner'
  6. import { ContentDiff, DiffType } from './SQLEditor.types'
  7. import {
  8. compareAsAddition,
  9. compareAsModification,
  10. compareAsNewSnippet,
  11. createSqlSnippetSkeletonV2,
  12. } from './SQLEditor.utils'
  13. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  14. import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
  15. import { useProfile } from '@/lib/profile'
  16. import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor-v2'
  17. export const useNewQuery = () => {
  18. const router = useRouter()
  19. const { ref } = useParams()
  20. const { profile } = useProfile()
  21. const { data: project } = useSelectedProjectQuery()
  22. const snapV2 = useSqlEditorV2StateSnapshot()
  23. const { can: canCreateSQLSnippet } = useAsyncCheckPermissions(
  24. PermissionAction.CREATE,
  25. 'user_content',
  26. {
  27. resource: { type: 'sql', owner_id: profile?.id },
  28. subject: { id: profile?.id },
  29. }
  30. )
  31. const newQuery = async (sql: string, name: string, shouldRedirect: boolean = true) => {
  32. if (!ref) return console.error('Project ref is required')
  33. if (!project) return console.error('Project is required')
  34. if (!profile) return console.error('Profile is required')
  35. if (!canCreateSQLSnippet) {
  36. toast('Your queries will not be saved as you do not have sufficient permissions')
  37. return undefined
  38. }
  39. try {
  40. const snippet = createSqlSnippetSkeletonV2({
  41. name,
  42. sql,
  43. owner_id: profile?.id,
  44. project_id: project?.id,
  45. })
  46. snapV2.addSnippet({ projectRef: ref, snippet })
  47. snapV2.addNeedsSaving(snippet.id)
  48. if (shouldRedirect) {
  49. router.push(`/project/${ref}/sql/${snippet.id}`)
  50. return undefined
  51. } else {
  52. return snippet.id
  53. }
  54. } catch (error: any) {
  55. toast.error(`Failed to create new query: ${error.message}`)
  56. return undefined
  57. }
  58. }
  59. return { newQuery }
  60. }
  61. export function useSqlEditorDiff() {
  62. const [sourceSqlDiff, setSourceSqlDiff] = useState<ContentDiff>()
  63. const [selectedDiffType, setSelectedDiffType] = useState<DiffType>()
  64. const [isAcceptDiffLoading, setIsAcceptDiffLoading] = useState(false)
  65. const isDiffOpen = !!sourceSqlDiff
  66. const defaultSqlDiff = useMemo(() => {
  67. if (!sourceSqlDiff) {
  68. return { original: '', modified: '' }
  69. }
  70. switch (selectedDiffType) {
  71. case DiffType.Modification:
  72. return compareAsModification(sourceSqlDiff)
  73. case DiffType.Addition:
  74. return compareAsAddition(sourceSqlDiff)
  75. case DiffType.NewSnippet:
  76. return compareAsNewSnippet(sourceSqlDiff)
  77. default:
  78. return { original: '', modified: '' }
  79. }
  80. }, [selectedDiffType, sourceSqlDiff])
  81. const closeDiff = useCallback(() => {
  82. setSourceSqlDiff(undefined)
  83. setSelectedDiffType(undefined)
  84. }, [])
  85. return {
  86. sourceSqlDiff,
  87. setSourceSqlDiff,
  88. selectedDiffType,
  89. setSelectedDiffType,
  90. isAcceptDiffLoading,
  91. setIsAcceptDiffLoading,
  92. isDiffOpen,
  93. defaultSqlDiff,
  94. closeDiff,
  95. }
  96. }
  97. interface PromptState {
  98. isOpen: boolean
  99. selection: string
  100. beforeSelection: string
  101. afterSelection: string
  102. startLineNumber: number
  103. endLineNumber: number
  104. }
  105. const initialPromptState: PromptState = {
  106. isOpen: false,
  107. selection: '',
  108. beforeSelection: '',
  109. afterSelection: '',
  110. startLineNumber: 0,
  111. endLineNumber: 0,
  112. }
  113. export function useSqlEditorPrompt() {
  114. const [promptState, setPromptState] = useState<PromptState>(initialPromptState)
  115. const [promptInput, setPromptInput] = useState('')
  116. useEffect(() => {
  117. if (!promptState.isOpen) {
  118. setPromptInput('')
  119. }
  120. }, [promptState.isOpen])
  121. const resetPrompt = () => {
  122. setPromptState(initialPromptState)
  123. setPromptInput('')
  124. }
  125. return {
  126. promptState,
  127. setPromptState,
  128. promptInput,
  129. setPromptInput,
  130. resetPrompt,
  131. }
  132. }
  133. export default useNewQuery