Home / Function/ RowHeader() — supabase Function Reference

RowHeader() — supabase Function Reference

Architecture documentation for the RowHeader() function in Header.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  45a20a70_0227_f399_758d_7761ce34992b["RowHeader()"]
  461e5ae4_2848_627b_8597_976e56b82b69["formatRowsForCSV()"]
  45a20a70_0227_f399_758d_7761ce34992b -->|calls| 461e5ae4_2848_627b_8597_976e56b82b69
  style 45a20a70_0227_f399_758d_7761ce34992b fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/grid/components/header/Header.tsx lines 224–521

const RowHeader = ({ tableQueriesEnabled = true }: RowHeaderProps) => {
  const queryClient = useQueryClient()
  const { data: project } = useSelectedProjectQuery()
  const tableEditorSnap = useTableEditorStateSnapshot()
  const snap = useTableEditorTableStateSnapshot()
  const isQueueOperationsEnabled = useIsQueueOperationsEnabled()

  const roleImpersonationState = useRoleImpersonationStateSnapshot()
  const isImpersonatingRole = roleImpersonationState.role !== undefined

  const { filters } = useTableFilter()
  const { sorts } = useTableSort()

  const [isExporting, setIsExporting] = useState(false)
  const [showExportModal, setShowExportModal] = useState(false)

  const { data } = useTableRowsQuery(
    {
      projectRef: project?.ref,
      connectionString: project?.connectionString,
      tableId: snap.table.id,
      sorts,
      filters,
      page: snap.page,
      limit: tableEditorSnap.rowsPerPage,
      roleImpersonationState: roleImpersonationState as RoleImpersonationState,
    },
    { enabled: tableQueriesEnabled }
  )

  const { data: countData } = useTableRowsCountQuery(
    {
      projectRef: project?.ref,
      connectionString: project?.connectionString,
      tableId: snap.table.id,
      filters,
      enforceExactCount: snap.enforceExactCount,
      roleImpersonationState: roleImpersonationState as RoleImpersonationState,
    },
    { placeholderData: keepPreviousData, enabled: tableQueriesEnabled }
  )

  const allRows = data?.rows ?? []
  const totalRows = countData?.count ?? 0

  const onSelectAllRows = () => {
    snap.setSelectedRows(new Set(allRows.map((row) => row.idx)), true)
  }

  const onRowsDelete = () => {
    const rowIdxs = Array.from(snap.selectedRows) as number[]
    const rows = allRows.filter((x) => rowIdxs.includes(x.idx))

    // Queue delete operations directly if queue mode is enabled (and not all rows selected)
    if (isQueueOperationsEnabled && !snap.allRowsSelected) {
      queueRowDeletesWithOptimisticUpdate({
        rows,
        table: snap.originalTable,
        queryClient,
        queueOperation: tableEditorSnap.queueOperation,
        projectRef: project?.ref,
      })
      snap.resetSelectedRows()
      return
    }

    // Fall back to confirmation dialog
    tableEditorSnap.onDeleteRows(rows, {
      allRowsSelected: snap.allRowsSelected,
      numRows: snap.allRowsSelected ? totalRows : rows.length,
      callback: () => {
        snap.resetSelectedRows()
      },
    })
  }

  const onCopyRows = (type: 'csv' | 'json' | 'sql') => {
    const rows = allRows.filter((x) => snap.selectedRows.has(x.idx))

    if (type === 'csv') {
      const csv = formatRowsForCSV({
        rows,
        columns: snap.table!.columns.map((column) => column.name),
      })
      copyToClipboard(csv)
    } else if (type === 'sql') {
      const sqlStatements = formatTableRowsToSQL(snap.table, rows)
      copyToClipboard(sqlStatements)
    } else if (type === 'json') {
      copyToClipboard(JSON.stringify(rows))
    }

    toast.success('Copied rows to clipboard')
  }

  const exportParams = snap.allRowsSelected
    ? ({ type: 'fetch_all', filters, sorts } as const)
    : ({
        type: 'provided_rows',
        table: snap.table,
        rows: allRows.filter((x) => snap.selectedRows.has(x.idx)),
      } as const)

  const { exportCsv, confirmationModal: exportCsvConfirmationModal } = useExportAllRowsAsCsv(
    project
      ? {
          enabled: true,
          projectRef: project.ref,
          connectionString: project?.connectionString ?? null,
          entity: snap.table,
          totalRows,
          ...exportParams,
        }
      : { enabled: false }
  )
  const onRowsExportCSV = async () => {
    setIsExporting(true)

    if (!project) {
      toast.error('Project is required')
      return setIsExporting(false)
    }

    exportCsv()

    setIsExporting(false)
  }

  const { exportSql, confirmationModal: exportSqlConfirmationModal } = useExportAllRowsAsSql(
    project
      ? {
          enabled: true,
          projectRef: project.ref,
          connectionString: project?.connectionString ?? null,
          entity: snap.table,
          ...exportParams,
        }
      : { enabled: false }
  )
  const onRowsExportSQL = async () => {
    setIsExporting(true)

    if (!project) {
      toast.error('Project is required')
      return setIsExporting(false)
    }

    exportSql()

    setIsExporting(false)
  }

  const { exportJson, confirmationModal: exportJsonConfirmationModal } = useExportAllRowsAsJson(
    project
      ? {
          enabled: true,
          projectRef: project.ref,
          connectionString: project?.connectionString ?? null,
          entity: snap.table,
          ...exportParams,
        }
      : { enabled: false }
  )
  const onRowsExportJSON = async () => {
    if (!project) {
      return toast.error('Project is required')
    }

    setIsExporting(true)

    exportJson()

    setIsExporting(false)
  }

  useSubscribeToImpersonatedRole(() => {
    if (snap.allRowsSelected || snap.selectedRows.size > 0) {
      snap.resetSelectedRows()
    }
  })

  return (
    <>
      <div className="flex items-center gap-x-2">
        {snap.editable && (
          <ButtonTooltip
            type="default"
            size="tiny"
            icon={<Trash />}
            onClick={onRowsDelete}
            disabled={snap.allRowsSelected && isImpersonatingRole}
            tooltip={{
              content: {
                side: 'bottom',
                text:
                  snap.allRowsSelected && isImpersonatingRole
                    ? 'Table truncation is not supported when impersonating a role'
                    : undefined,
              },
            }}
          >
            {snap.allRowsSelected
              ? `Delete all rows in table`
              : snap.selectedRows.size > 1
                ? `Delete ${snap.selectedRows.size} rows`
                : `Delete ${snap.selectedRows.size} row`}
          </ButtonTooltip>
        )}

        {!snap.allRowsSelected ? (
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <Button
                type="default"
                size="tiny"
                iconRight={<ChevronDown />}
                loading={isExporting}
                disabled={isExporting}
              >
                Copy
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="start" className="w-40">
              <DropdownMenuItem onClick={() => onCopyRows('csv')}>Copy as CSV</DropdownMenuItem>
              <DropdownMenuItem onClick={() => onCopyRows('sql')}>Copy as SQL</DropdownMenuItem>
              <DropdownMenuItem onClick={() => onCopyRows('json')}>Copy as JSON</DropdownMenuItem>
            </DropdownMenuContent>
          </DropdownMenu>
        ) : (
          <ButtonTooltip
            disabled
            type="default"
            tooltip={{
              content: {
                side: 'bottom',
                className: 'w-64 text-center',
                text: 'Copy to clipboard is not supported while all rows in the table are selected',
              },
            }}
          >
            Copy
          </ButtonTooltip>
        )}

        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              type="default"
              size="tiny"
              iconRight={<ChevronDown />}
              loading={isExporting}
              disabled={isExporting}
            >
              Export
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="start" className={snap.allRowsSelected ? 'w-52' : 'w-40'}>
            <DropdownMenuItem onClick={onRowsExportCSV}>Export as CSV</DropdownMenuItem>
            <DropdownMenuItem onClick={onRowsExportSQL}>Export as SQL</DropdownMenuItem>
            {snap.allRowsSelected ? (
              <DropdownMenuItem className="group" onClick={() => setShowExportModal(true)}>
                <div>
                  <p className="group-hover:text-foreground">Export via CLI</p>
                  <p className="text-foreground-lighter">Recommended for large tables</p>
                </div>
              </DropdownMenuItem>
            ) : (
              <DropdownMenuItem onClick={onRowsExportJSON}>Export as JSON</DropdownMenuItem>
            )}
          </DropdownMenuContent>
        </DropdownMenu>

        {!snap.allRowsSelected && totalRows > allRows.length && (
          <>
            <div className="h-6 ml-0.5">
              <Separator orientation="vertical" />
            </div>
            <Button type="text" onClick={() => onSelectAllRows()}>
              Select all rows in table
            </Button>
          </>
        )}
      </div>

      <ExportDialog
        table={snap.table}
        filters={filters}
        sorts={sorts}
        open={showExportModal}
        onOpenChange={() => setShowExportModal(false)}
      />

      {exportCsvConfirmationModal}
      {exportSqlConfirmationModal}
      {exportJsonConfirmationModal}
    </>
  )
}

Subdomains

Frequently Asked Questions

What does RowHeader() do?
RowHeader() is a function in the supabase codebase.
What does RowHeader() call?
RowHeader() calls 1 function(s): formatRowsForCSV.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free