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>[])
}
Domain
Subdomains
Called By
Source
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