mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 23:59:08 +03:00
* chore: cleanup packages - Avoid circular imports - Export API-types as types - pg-format without depending on Node internal Buffer (not browser-compatible) - Avoid importing from barrel files in ui dir * chore: avoid barrel file imports in studio (#27771) * chore: avoid barrel file imports - Removes some unused imports - Avoids barrel file import for faster builds + less memory * add eslint rule * type fixes * delete layouts barrel * delete components/grid barrel file * delete components/grid/utils barrel file * delete components/grid/components/common barrel file * delete components/grid/components/editor barrel file * delete components/grid/components/formatter barrel file * delete components/grid/components/grid barrel file * delete components/grid/components/header/filter barrel file * remote components/grid/store barrel file * remove components/interfaces/Auth/Policies barrel file * delete components/interfaces/Settings/Logs barrel file * delete components/ui/CodeEditor barrel file * delete components/ui/Forms barrel file * delete components/ui/Shimmers barrel file * delete data/analytics barrel file * delete hooks barrel file * cleanup lib/common/fetch barrel file * final * barral files cleanup * global react-data-grid styles * remove console.log --------- Co-authored-by: Kevin Grüneberg <k.grueneberg1994@gmail.com> * fix build --------- Co-authored-by: Kevin Grüneberg <k.grueneberg1994@gmail.com>
160 lines
5.0 KiB
TypeScript
160 lines
5.0 KiB
TypeScript
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
|
import { IS_PLATFORM, useParams } from 'common'
|
|
import { Copy, Download, Edit, MoreHorizontal, Share, Trash } from 'lucide-react'
|
|
import { useRouter } from 'next/router'
|
|
import toast from 'react-hot-toast'
|
|
import {
|
|
Button,
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuTrigger,
|
|
} from 'ui'
|
|
|
|
import { createSqlSnippetSkeleton } from 'components/interfaces/SQLEditor/SQLEditor.utils'
|
|
import type { SqlSnippet } from 'data/content/sql-snippets-query'
|
|
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
|
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
|
import { uuidv4 } from 'lib/helpers'
|
|
import { useProfile } from 'lib/profile'
|
|
import { useSqlEditorStateSnapshot } from 'state/sql-editor'
|
|
|
|
interface QueryItemActionsProps {
|
|
tabInfo: SqlSnippet
|
|
open: boolean
|
|
setOpen: (value: boolean) => void
|
|
onSelectRenameQuery: () => void
|
|
onSelectDeleteQuery: () => void
|
|
onSelectShareQuery: () => void
|
|
onSelectDownloadQuery: () => void
|
|
}
|
|
|
|
export const QueryItemActions = ({
|
|
tabInfo,
|
|
open,
|
|
setOpen,
|
|
onSelectRenameQuery,
|
|
onSelectDeleteQuery,
|
|
onSelectShareQuery,
|
|
onSelectDownloadQuery,
|
|
}: QueryItemActionsProps) => {
|
|
const { ref } = useParams()
|
|
const router = useRouter()
|
|
const { profile } = useProfile()
|
|
|
|
const snap = useSqlEditorStateSnapshot()
|
|
const project = useSelectedProject()
|
|
|
|
const { id, name, visibility, content } = tabInfo || {}
|
|
|
|
const canCreateSQLSnippet = useCheckPermissions(PermissionAction.CREATE, 'user_content', {
|
|
resource: { type: 'sql', owner_id: profile?.id },
|
|
subject: { id: profile?.id },
|
|
})
|
|
|
|
const { id: snippetID } = tabInfo || {}
|
|
const snippet =
|
|
snippetID !== undefined && snap.snippets && snap.snippets[snippetID] !== undefined
|
|
? snap.snippets[snippetID]
|
|
: null
|
|
|
|
const isSnippetOwner = profile?.id === snippet?.snippet.owner_id
|
|
|
|
const onClickRename = (e: any) => {
|
|
e.stopPropagation()
|
|
onSelectRenameQuery()
|
|
}
|
|
|
|
const onClickShare = (e: any) => {
|
|
e.stopPropagation()
|
|
onSelectShareQuery()
|
|
}
|
|
|
|
const onClickDelete = (e: any) => {
|
|
e.stopPropagation()
|
|
onSelectDeleteQuery()
|
|
}
|
|
|
|
const createPersonalCopy = async () => {
|
|
if (!ref) return console.error('Project ref is required')
|
|
if (!id) return console.error('Snippet ID is required')
|
|
try {
|
|
const snippet = createSqlSnippetSkeleton({
|
|
id: uuidv4(),
|
|
name,
|
|
sql: content.sql,
|
|
owner_id: profile?.id,
|
|
project_id: project?.id,
|
|
})
|
|
snap.addSnippet(snippet as SqlSnippet, ref)
|
|
snap.addNeedsSaving(snippet.id!)
|
|
router.push(`/project/${ref}/sql/${snippet.id}`)
|
|
} catch (error: any) {
|
|
toast.error(`Failed to create a personal copy of this query: ${error.message}`)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{IS_PLATFORM ? (
|
|
<DropdownMenu open={open} onOpenChange={setOpen}>
|
|
<DropdownMenuTrigger
|
|
className="opacity-0 group-hover:opacity-100 group-focus:opacity-100 focus:opacity-100 data-[state=open]:opacity-100"
|
|
asChild
|
|
name="Query actions"
|
|
>
|
|
<Button
|
|
type="text"
|
|
className="px-1 text-lighter data-[state=open]:text-foreground"
|
|
icon={<MoreHorizontal size={14} strokeWidth={2} />}
|
|
onClick={(e) => e.preventDefault()}
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent side="bottom" align="start" className="w-52">
|
|
{isSnippetOwner && (
|
|
<DropdownMenuItem onClick={onClickRename} className="flex gap-2">
|
|
<Edit size={14} />
|
|
Rename query
|
|
</DropdownMenuItem>
|
|
)}
|
|
|
|
{visibility === 'user' && canCreateSQLSnippet && (
|
|
<DropdownMenuItem onClick={onClickShare} className="flex gap-2">
|
|
<Share size={14} />
|
|
Share query
|
|
</DropdownMenuItem>
|
|
)}
|
|
{visibility === 'project' && canCreateSQLSnippet && (
|
|
<DropdownMenuItem onClick={createPersonalCopy} className="flex gap-2">
|
|
<Copy size={14} />
|
|
Duplicate personal copy
|
|
</DropdownMenuItem>
|
|
)}
|
|
|
|
{IS_PLATFORM && (
|
|
<DropdownMenuItem onClick={() => onSelectDownloadQuery()} className="flex gap-2">
|
|
<Download size={14} />
|
|
Download as migration file
|
|
</DropdownMenuItem>
|
|
)}
|
|
{isSnippetOwner && (
|
|
<>
|
|
<DropdownMenuSeparator />
|
|
<DropdownMenuItem onClick={onClickDelete} className="flex gap-2">
|
|
<Trash size={14} />
|
|
Delete query
|
|
</DropdownMenuItem>
|
|
</>
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
) : (
|
|
<Button asChild disabled type="text" style={{ padding: '3px' }}>
|
|
<span />
|
|
</Button>
|
|
)}
|
|
</>
|
|
)
|
|
}
|