Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,35 @@ import RefSubLayout from '~/layouts/ref/RefSubLayout'

import spec from '~/spec/cli_v1_commands.yaml' with { type: 'yaml' }
import Param from '~/components/Params'
import { isFeatureEnabled } from 'common'
import { getCustomContent } from '~/lib/custom-content/getCustomContent'

const { cliDisableCustomProfiles } = isFeatureEnabled(['cli:disable_custom_profiles'])

const CliGlobalFlagsHandler = () => {
// Only fetch cliProfile when custom profiles are enabled
const cliProfile = !cliDisableCustomProfiles
? getCustomContent(['cli:profile'] as any).cliProfile
: undefined

// Transform the flags based on feature flags
const processedFlags = spec.flags.map((flag: any) => {
if (flag.id === 'profile' && !cliDisableCustomProfiles) {
return {
id: 'profile',
name: `--profile ${cliProfile}`,
description: `use ${cliProfile} profile for connecting to Supabase API`,
}
}
return flag
})

return (
<RefSubLayout.EducationRow className="not-prose">
<RefSubLayout.Details>
<h3 className="text-lg text-foreground mb-3">Flags</h3>
<ul>
{spec.flags.map((flag) => {
{processedFlags.map((flag) => {
return (
<Param
{...flag}
Expand Down
1 change: 1 addition & 0 deletions apps/docs/lib/custom-content/CustomContent.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type CustomContentTypes = {
homepageHeading: string
metadataApplicationName: string
metadataTitle: string
cliProfile: string
navigationLogo: {
light: string
dark: string
Expand Down
6 changes: 3 additions & 3 deletions apps/docs/lib/custom-content/getCustomContent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ function contentToCamelCase(feature: CustomContent) {
}

type CustomContentResult<T extends CustomContent[]> = {
[key in CustomContentToCamelCase<T[number]>]:
| CustomContentTypes[CustomContentToCamelCase<T[number]>]
| null
[key in CustomContentToCamelCase<T[number]> extends keyof CustomContentTypes
? CustomContentToCamelCase<T[number]>
: never]: CustomContentTypes[key] | null
}

export const getCustomContent = <T extends CustomContent[]>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { BASE_PATH } from 'lib/constants'
import { PROVIDER_PHONE, PROVIDERS_SCHEMAS } from '../AuthProvidersFormValidation'
import { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'

export type Filter = 'all' | 'verified' | 'unverified' | 'anonymous'

export type SpecificFilterColumn = OptimizedSearchColumns | 'freeform'

export const UUIDV4_LEFT_PREFIX_REGEX =
/^(?:[0-9a-f]{1,8}|[0-9a-f]{8}-|[0-9a-f]{8}-[0-9a-f]{1,4}|[0-9a-f]{8}-[0-9a-f]{4}-|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{0,3}|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{0,3}|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-|[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{0,12})$/i

Expand Down
10 changes: 8 additions & 2 deletions apps/studio/components/interfaces/Auth/Users/UsersFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import { THRESHOLD_COUNT } from '@supabase/pg-meta/src/sql/studio/get-count-esti
import { HelpCircle, Loader2 } from 'lucide-react'
import { useEffect, useState } from 'react'

import type { Filter, SpecificFilterColumn } from './Users.constants'

import { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'
import { useParams } from 'common'
import { formatEstimatedCount } from 'components/grid/components/footer/pagination/Pagination.utils'
import { useUsersCountQuery } from 'data/auth/users-count-query'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { Filter } from './Users.constants'

interface UsersFooterProps {
filter: Filter
filterKeywords: string
selectedProviders: string[]
specificFilterColumn: string
specificFilterColumn: SpecificFilterColumn
}

export const UsersFooter = ({
Expand Down Expand Up @@ -42,6 +44,10 @@ export const UsersFooter = ({
filter: filter === 'all' ? undefined : filter,
providers: selectedProviders,
forceExactCount,
// Use optimized search when filtering by specific column
...(specificFilterColumn !== 'freeform'
? { column: specificFilterColumn as OptimizedSearchColumns }
: { column: undefined }),
},
{ keepPreviousData: true }
)
Expand Down
10 changes: 6 additions & 4 deletions apps/studio/components/interfaces/Auth/Users/UsersV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { UIEvent, useEffect, useMemo, useRef, useState } from 'react'
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
import { toast } from 'sonner'

import type { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'
import type { SpecificFilterColumn } from './Users.constants'
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
import AlertError from 'components/ui/AlertError'
Expand Down Expand Up @@ -91,9 +93,9 @@ export const UsersV2 = () => {
}
}, [showEmailPhoneColumns])

const [specificFilterColumn, setSpecificFilterColumn] = useQueryState(
const [specificFilterColumn, setSpecificFilterColumn] = useQueryState<SpecificFilterColumn>(
'filter',
parseAsStringEnum(['id', 'email', 'phone', 'freeform']).withDefault('id')
parseAsStringEnum<SpecificFilterColumn>(['id', 'email', 'phone', 'freeform']).withDefault('id')
)
const [filterUserType, setFilterUserType] = useQueryState(
'userType',
Expand Down Expand Up @@ -138,7 +140,7 @@ export const UsersV2 = () => {
)

const [columns, setColumns] = useState<Column<any>[]>([])
const [search, setSearch] = useState('')
const [search, setSearch] = useState(filterKeywords)
const [selectedUser, setSelectedUser] = useState<string>()
const [selectedUsers, setSelectedUsers] = useState<Set<any>>(new Set([]))
const [selectedUserToDelete, setSelectedUserToDelete] = useState<User>()
Expand Down Expand Up @@ -187,7 +189,7 @@ export const UsersV2 = () => {
sort: sortColumn as 'id' | 'created_at' | 'email' | 'phone',
order: sortOrder as 'asc' | 'desc',
...(specificFilterColumn !== 'freeform'
? { column: specificFilterColumn }
? { column: specificFilterColumn as OptimizedSearchColumns }
: { column: undefined }),
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const AWS_REGIONS_COORDINATES: { [key: string]: [number, number] } = {
NORTHEAST_ASIA_2: [126.98, 37.56],
CENTRAL_CANADA: [-73.6, 45.5],
WEST_US: [-121.96, 37.35],
WEST_US_2: [-122.67, 45.51],
EAST_US: [-78.45, 38.13],
WEST_EU: [-8, 53],
WEST_EU_2: [-0.1, 51],
Expand Down
3 changes: 3 additions & 0 deletions apps/studio/data/auth/keys.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'

export const authKeys = {
users: (
projectRef: string | undefined,
Expand Down Expand Up @@ -39,6 +41,7 @@ export const authKeys = {
filter: string | undefined
providers: string[] | undefined
forceExactCount?: boolean
column?: OptimizedSearchColumns
}
) =>
['projects', projectRef, 'users-count', ...(params ? [params].filter(Boolean) : [])] as const,
Expand Down
10 changes: 9 additions & 1 deletion apps/studio/data/auth/users-count-query.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'
import { getUsersCountSQL } from '@supabase/pg-meta/src/sql/studio/get-users-count'
import { useQuery } from '@tanstack/react-query'

Expand All @@ -13,6 +14,9 @@ type UsersCountVariables = {
filter?: Filter
providers?: string[]
forceExactCount?: boolean

/** If set, uses optimized prefix search for the specified column */
column?: OptimizedSearchColumns
}

export async function getUsersCount(
Expand All @@ -23,10 +27,11 @@ export async function getUsersCount(
filter,
providers,
forceExactCount,
column,
}: UsersCountVariables,
signal?: AbortSignal
) {
const sql = getUsersCountSQL({ filter, keywords, providers, forceExactCount })
const sql = getUsersCountSQL({ filter, keywords, providers, forceExactCount, column })

const { result } = await executeSql(
{
Expand Down Expand Up @@ -63,6 +68,7 @@ export const useUsersCountQuery = <TData = UsersCountData>(
filter,
providers,
forceExactCount,
column,
}: UsersCountVariables,
{ enabled = true, ...options }: UseCustomQueryOptions<UsersCountData, UsersCountError, TData> = {}
) =>
Expand All @@ -72,6 +78,7 @@ export const useUsersCountQuery = <TData = UsersCountData>(
filter,
providers,
forceExactCount,
column,
}),
queryFn: ({ signal }) =>
getUsersCount(
Expand All @@ -82,6 +89,7 @@ export const useUsersCountQuery = <TData = UsersCountData>(
filter,
providers,
forceExactCount,
column,
},
signal
),
Expand Down
5 changes: 3 additions & 2 deletions apps/studio/data/auth/users-infinite-query.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getPaginatedUsersSQL } from '@supabase/pg-meta/src/sql/studio/get-users-paginated'
import { useInfiniteQuery } from '@tanstack/react-query'

import { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'
import type { components } from 'data/api'
import { executeSql, ExecuteSqlError } from 'data/sql/execute-sql-query'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
Expand All @@ -20,8 +21,8 @@ type UsersVariables = {
providers?: string[]
sort?: 'id' | 'created_at' | 'email' | 'phone' | 'last_sign_in_at'
order?: 'asc' | 'desc'

column?: 'id' | 'email' | 'phone'
/** If set, uses optimized prefix search for the specified column */
column?: OptimizedSearchColumns
startAt?: string
}

Expand Down
2 changes: 1 addition & 1 deletion apps/www/data/ga.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ We're committed to our Free Plan - we know the importance of this for testing ho
{
number: '25,000',
text: 'Discord members',
url: 'https://discord.com/invite/R7bSpeBSJE',
url: 'https://discord.supabase.com',
icon: <IconDiscord />,
},
{
Expand Down
2 changes: 2 additions & 0 deletions packages/common/enabled-features/enabled-features.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

"branding:large_logo": false,

"cli:disable_custom_profiles": true,

"dashboard_auth:sign_up": true,
"dashboard_auth:sign_in_with_github": true,
"dashboard_auth:sign_in_with_sso": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,10 @@
"type": "boolean",
"description": "Show larger logo sizes throughout the apps"
},

"cli:disable_custom_profiles": {
"type": "boolean",
"description": "Disable custom CLI profiles feature"
},
"dashboard_auth:sign_up": {
"type": "boolean",
"description": "Enable the sign up page in the dashboard"
Expand Down
51 changes: 51 additions & 0 deletions packages/pg-meta/src/sql/studio/get-users-common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
export function prefixToUUID(prefix: string, max: boolean) {
const mapped = '00000000-0000-0000-0000-000000000000'
.split('')
.map((c, i) => (c === '-' ? c : prefix[i] ?? c))

if (prefix.length >= mapped.length) {
return mapped.join('')
}

if (prefix.length && prefix.length < 15) {
mapped[14] = '4'
}

if (prefix.length && prefix.length < 20) {
mapped[19] = max ? 'b' : '8'
}

if (max) {
for (let i = prefix.length; i < mapped.length; i += 1) {
if (mapped[i] === '0') {
mapped[i] = 'f'
}
}
}

return mapped.join('')
}

export function stringRange(prefix: string): [string, string | undefined] {
if (!prefix) {
return [prefix, undefined]
}

const lastCharCode = prefix.charCodeAt(prefix.length - 1)
const TILDE_CHAR_CODE = 126 // '~'
const Z_CHAR_CODE = 122 // 'z'

// 'z' (122): append '~' to avoid PostgreSQL collation issues with '{'
if (lastCharCode === Z_CHAR_CODE) {
return [prefix, prefix + '~']
}

// '~' (126) or beyond: append space since we can't increment further
if (lastCharCode >= TILDE_CHAR_CODE) {
return [prefix, prefix + ' ']
}

// All other characters: increment the last character
const upperBound = prefix.substring(0, prefix.length - 1) + String.fromCharCode(lastCharCode + 1)
return [prefix, upperBound]
}
Loading
Loading