import dayjs from 'dayjs' import { PERMISSION_LIST, ScopedAccessTokenPermission } from './AccessToken.constants' import { AccessTokenSort, AccessTokenSortColumn, AccessTokenSortOrder, BaseToken, } from './AccessToken.types' export const handleSortChange = ( currentSort: AccessTokenSort, column: AccessTokenSortColumn, setSort: (sort: AccessTokenSort) => void ) => { const [currentCol, currentOrder] = currentSort.split(':') as [ AccessTokenSortColumn, AccessTokenSortOrder, ] if (currentCol === column) { if (currentOrder === 'asc') { setSort(`${column}:desc` as AccessTokenSort) } else { setSort('created_at:desc') } } else { setSort(`${column}:asc` as AccessTokenSort) } } export const filterAndSortTokens = ( tokens: T[] | undefined, searchString: string, sort: AccessTokenSort ): T[] | undefined => { const filtered = !searchString ? tokens : tokens?.filter((token) => token.name.toLowerCase().includes(searchString.toLowerCase())) if (!filtered) return filtered const [sortCol, sortOrder] = sort.split(':') as [AccessTokenSortColumn, AccessTokenSortOrder] const orderMultiplier = sortOrder === 'asc' ? 1 : -1 return [...filtered].sort((a, b) => { if (sortCol === 'created_at') { return (new Date(a.created_at).getTime() - new Date(b.created_at).getTime()) * orderMultiplier } if (sortCol === 'last_used_at') { if (!a.last_used_at && !b.last_used_at) return 0 if (!a.last_used_at) return 1 if (!b.last_used_at) return -1 return ( (new Date(a.last_used_at).getTime() - new Date(b.last_used_at).getTime()) * orderMultiplier ) } if (sortCol === 'expires_at') { if (!a.expires_at && !b.expires_at) return 0 if (!a.expires_at) return 1 if (!b.expires_at) return -1 return (new Date(a.expires_at).getTime() - new Date(b.expires_at).getTime()) * orderMultiplier } return 0 }) } export const mapPermissionToFGA = ( resourceKey: string, action: string ): ScopedAccessTokenPermission[] => { const [scope, resource] = resourceKey.split(':') const match = PERMISSION_LIST.find( (p) => p.scope === scope && p.resource === resource && p.action === action ) return match ? [match.id as ScopedAccessTokenPermission] : [] } // [kemal]: Not sure how efficient this will be, but it should get permissions from shared types and transform them whenever @supabase/shared-types updates. export const getResourcePermissions = ( resourceKey: string ): Record => { const [scope, resource] = resourceKey.split(':') const result: Record = { 'no access': [] } PERMISSION_LIST.filter((p) => p.scope === scope && p.resource === resource).forEach((p) => { result[p.action] = [p.id as ScopedAccessTokenPermission] }) if (result['read'] && result['write']) { result['read-write'] = [...result['read'], ...result['write']] } return result } export const getRealAccess = (resource: string, tokenPermissions: string[]) => { const resourcePermissions = getResourcePermissions(resource) const actionTypes = ['read', 'write', 'create', 'delete'] as const const grantedActions = actionTypes.filter((action) => resourcePermissions[action]?.some((p) => tokenPermissions.includes(p)) ) if (grantedActions.length === 0) { return 'no access' } if (grantedActions.length === 1) { return grantedActions[0] } if ( grantedActions.length === 2 && grantedActions[0] === 'read' && grantedActions[1] === 'write' ) { return 'read-write' } return grantedActions.join('-') } export const formatAccessText = (action: string): string => { switch (action) { case 'no access': return 'No access' default: return action .split('-') .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join('-') } } export const getExpirationDate = (key: string): string | undefined => { switch (key) { case 'hour': return dayjs().add(1, 'hours').toISOString() case 'day': return dayjs().add(1, 'day').toISOString() case 'week': return dayjs().add(7, 'days').toISOString() case 'month': return dayjs().add(30, 'days').toISOString() case 'never': return undefined default: return undefined } }