Home / Function/ formatUserColumns() — supabase Function Reference

formatUserColumns() — supabase Function Reference

Architecture documentation for the formatUserColumns() function in Users.utils.tsx from the supabase codebase.

Entity Profile

Dependency Diagram

graph TD
  33c633f1_2f6b_e858_57d2_f3222114d50b["formatUserColumns()"]
  18ff6832_db40_b6e5_0f16_73fa92edbfe6["UsersV2()"]
  18ff6832_db40_b6e5_0f16_73fa92edbfe6 -->|calls| 33c633f1_2f6b_e858_57d2_f3222114d50b
  style 33c633f1_2f6b_e858_57d2_f3222114d50b fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

apps/studio/components/interfaces/Auth/Users/Users.utils.tsx lines 255–439

export const formatUserColumns = ({
  specificFilterColumn,
  columns,
  config,
  users,
  visibleColumns = [],
  setSortByValue,
  onSelectDeleteUser,
}: {
  specificFilterColumn: string
  columns: UsersTableColumn[]
  config: ColumnConfiguration[]
  users: User[]
  visibleColumns?: string[]
  setSortByValue: (val: string) => void
  onSelectDeleteUser: (user: User) => void
}) => {
  const columnOrder = config.map((c) => c.id) ?? columns.map((c) => c.id)

  let gridColumns = columns.map((col) => {
    const savedConfig = config.find((c) => c.id === col.id)
    const res: Column<any> = {
      key: col.id,
      name: col.name,
      resizable: col.resizable ?? true,
      sortable: false,
      draggable: true,
      width: savedConfig?.width ?? col.width,
      minWidth: col.minWidth ?? 120,
      headerCellClass: 'z-50 outline-none !shadow-none',
      renderHeaderCell: () => {
        // [Joshen] I'm on the fence to support "Select all" for users, as the results are infinitely paginated
        // "Select all" wouldn't be an accurate representation if not all the pages have been fetched, but if decide
        // to support - the component is ready as such: Just pass selectedUsers and allRowsSelected as props from parent
        // <SelectHeaderCell selectedUsers={selectedUsers} allRowsSelected={allRowsSelected} />
        if (col.id === 'img') return undefined
        return (
          <HeaderCell
            col={col}
            specificFilterColumn={specificFilterColumn}
            setSortByValue={setSortByValue}
          />
        )
      },
      renderCell: ({ row }) => {
        // This is actually a valid React component, so we can use hooks here
        // eslint-disable-next-line react-hooks/rules-of-hooks
        const [isRowSelected, onRowSelectionChange] = useRowSelection()

        const value = row?.[col.id]
        const user = users?.find((u) => u.id === row.id)
        const formattedValue =
          value !== null && ['created_at', 'last_sign_in_at'].includes(col.id)
            ? dayjs(value).format('ddd DD MMM YYYY HH:mm:ss [GMT]ZZ')
            : Array.isArray(value)
              ? col.id === 'providers'
                ? value
                    .map((x) => {
                      const meta = PROVIDERS_SCHEMAS.find(
                        (y) => ('key' in y && y.key === x) || y.title.toLowerCase() === x
                      )
                      return meta?.title
                    })
                    .join(', ')
                : value.join(', ')
              : value
        const isConfirmed = !!user?.confirmed_at

        if (col.id === 'img') {
          return (
            <div className="flex items-center justify-center gap-x-2">
              <Checkbox_Shadcn_
                checked={isRowSelected}
                onClick={(e) => {
                  e.stopPropagation()
                  onRowSelectionChange({
                    row,
                    type: 'ROW',
                    checked: !isRowSelected,
                    isShiftClick: e.shiftKey,
                  })
                }}
              />
              <div
                className={cn(
                  'flex items-center justify-center w-6 h-6 rounded-full bg-center bg-cover bg-no-repeat',
                  !row.img ? 'bg-selection' : 'border'
                )}
                style={{ backgroundImage: row.img ? `url('${row.img}')` : 'none' }}
              >
                {!row.img && <UserIcon size={12} />}
              </div>
            </div>
          )
        }

        return (
          <ContextMenu_Shadcn_>
            <ContextMenuTrigger_Shadcn_ asChild>
              <div
                className={cn(
                  'w-full flex items-center text-xs',
                  col.id.includes('provider') ? 'capitalize' : ''
                )}
              >
                {/* [Joshen] Not convinced this is the ideal way to display the icons, but for now */}
                {col.id === 'providers' &&
                  row.provider_icons.map((icon: string, idx: number) => {
                    const provider = row.providers[idx]
                    return (
                      <div
                        className="min-w-6 min-h-6 rounded-full border flex items-center justify-center bg-surface-75"
                        style={{
                          marginLeft: idx === 0 ? 0 : `-8px`,
                          zIndex: row.provider_icons.length - idx,
                        }}
                      >
                        <img
                          key={`${user?.id}-${provider}`}
                          width={16}
                          src={icon}
                          alt={`${provider} auth icon`}
                          className={cn(
                            (provider === 'github' || provider === 'x') && 'dark:invert'
                          )}
                        />
                      </div>
                    )
                  })}
                {col.id === 'last_sign_in_at' && !isConfirmed ? (
                  <p className="text-foreground-lighter">Waiting for verification</p>
                ) : (
                  <p className={cn(col.id === 'providers' && 'ml-1')}>
                    {formattedValue === null ? '-' : formattedValue}
                  </p>
                )}
              </div>
            </ContextMenuTrigger_Shadcn_>
            <ContextMenuContent_Shadcn_ onClick={(e) => e.stopPropagation()}>
              <ContextMenuItem_Shadcn_
                className="gap-x-2"
                onFocusCapture={(e) => e.stopPropagation()}
                onSelect={() => {
                  const value = col.id === 'providers' ? row.providers.join(', ') : formattedValue
                  copyToClipboard(value)
                }}
              >
                <Copy size={12} />
                <span>Copy {col.id === 'id' ? col.name : col.name.toLowerCase()}</span>
              </ContextMenuItem_Shadcn_>
              <ContextMenuSeparator_Shadcn_ />
              <ContextMenuItem_Shadcn_
                className="gap-x-2"
                onFocusCapture={(e) => e.stopPropagation()}
                onSelect={() => {
                  if (user) onSelectDeleteUser(user)
                }}
              >
                <Trash size={12} />
                <span>Delete user</span>
              </ContextMenuItem_Shadcn_>
            </ContextMenuContent_Shadcn_>
          </ContextMenu_Shadcn_>
        )
      },
    }
    return res
  })

  const profileImageColumn = gridColumns.find((col) => col.key === 'img')

  if (columnOrder.length > 0) {
    gridColumns = gridColumns
      .filter((col) => columnOrder.includes(col.key))
      .sort((a: any, b: any) => {
        return columnOrder.indexOf(a.key) - columnOrder.indexOf(b.key)
      })
  }

  return visibleColumns.length === 0
    ? gridColumns
    : ([profileImageColumn].concat(
        gridColumns.filter((col) => visibleColumns.includes(col.key))
      ) as Column<any>[])
}

Subdomains

Called By

Frequently Asked Questions

What does formatUserColumns() do?
formatUserColumns() is a function in the supabase codebase.
What calls formatUserColumns()?
formatUserColumns() is called by 1 function(s): UsersV2.

Analyze Your Own Codebase

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

Try Supermodel Free