Skip to content

Commit 8d93e98

Browse files
authored
fix: allow spaces in the name filter (supabase#41788)
1 parent dc31696 commit 8d93e98

File tree

2 files changed

+101
-88
lines changed

2 files changed

+101
-88
lines changed

apps/studio/components/interfaces/Auth/Users/UsersSearch.tsx

Lines changed: 77 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,29 @@
1+
import { AuthUsersSearchSubmittedEvent } from 'common/telemetry-constants'
12
import { Search, X } from 'lucide-react'
2-
import { SetStateAction } from 'react'
3+
import { parseAsString, parseAsStringEnum, useQueryState } from 'nuqs'
4+
import { useState } from 'react'
5+
import {
6+
Button,
7+
SelectContent_Shadcn_,
8+
SelectGroup_Shadcn_,
9+
SelectItem_Shadcn_,
10+
SelectSeparator_Shadcn_,
11+
SelectTrigger_Shadcn_,
12+
SelectValue_Shadcn_,
13+
Select_Shadcn_,
14+
Tooltip,
15+
TooltipContent,
16+
TooltipTrigger,
17+
cn,
18+
} from 'ui'
19+
import { Input } from 'ui-patterns/DataInputs/Input'
320

4-
import { SpecificFilterColumn } from './Users.constants'
21+
import {
22+
PHONE_NUMBER_LEFT_PREFIX_REGEX,
23+
SpecificFilterColumn,
24+
UUIDV4_LEFT_PREFIX_REGEX,
25+
} from './Users.constants'
26+
import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
527

628
const getSearchPlaceholder = (column: SpecificFilterColumn): string => {
729
switch (column) {
@@ -20,41 +42,63 @@ const getSearchPlaceholder = (column: SpecificFilterColumn): string => {
2042
}
2143
}
2244

23-
import {
24-
Button,
25-
cn,
26-
Select_Shadcn_,
27-
SelectContent_Shadcn_,
28-
SelectGroup_Shadcn_,
29-
SelectItem_Shadcn_,
30-
SelectSeparator_Shadcn_,
31-
SelectTrigger_Shadcn_,
32-
SelectValue_Shadcn_,
33-
Tooltip,
34-
TooltipContent,
35-
TooltipTrigger,
36-
} from 'ui'
37-
import { Input } from 'ui-patterns/DataInputs/Input'
38-
3945
interface UsersSearchProps {
40-
search: string
41-
searchInvalid: boolean
42-
specificFilterColumn: SpecificFilterColumn
43-
setSearch: (value: SetStateAction<string>) => void
44-
setFilterKeywords: (value: string) => void
45-
setSpecificFilterColumn: (value: SpecificFilterColumn) => void
4646
improvedSearchEnabled?: boolean
47+
telemetryProps: Omit<AuthUsersSearchSubmittedEvent['properties'], 'trigger'>
48+
telemetryGroups: AuthUsersSearchSubmittedEvent['groups']
49+
onSelectFilterColumn: (value: SpecificFilterColumn) => void
4750
}
4851

4952
export const UsersSearch = ({
50-
search,
51-
searchInvalid,
52-
specificFilterColumn,
53-
setSearch,
54-
setFilterKeywords,
55-
setSpecificFilterColumn,
5653
improvedSearchEnabled = false,
54+
telemetryProps,
55+
telemetryGroups,
56+
onSelectFilterColumn,
5757
}: UsersSearchProps) => {
58+
const [_, setSelectedId] = useQueryState(
59+
'show',
60+
parseAsString.withOptions({ history: 'push', clearOnDefault: true })
61+
)
62+
const [filterKeywords, setFilterKeywords] = useQueryState('keywords', { defaultValue: '' })
63+
const [specificFilterColumn] = useQueryState<SpecificFilterColumn>(
64+
'filter',
65+
parseAsStringEnum<SpecificFilterColumn>([
66+
'id',
67+
'email',
68+
'phone',
69+
'name',
70+
'freeform',
71+
]).withDefault('email')
72+
)
73+
74+
const [search, setSearch] = useState(filterKeywords)
75+
const { mutate: sendEvent } = useSendEventMutation()
76+
77+
const searchInvalid =
78+
!search ||
79+
specificFilterColumn === 'freeform' ||
80+
specificFilterColumn === 'email' ||
81+
specificFilterColumn === 'name'
82+
? false
83+
: specificFilterColumn === 'id'
84+
? !search.match(UUIDV4_LEFT_PREFIX_REGEX)
85+
: !search.match(PHONE_NUMBER_LEFT_PREFIX_REGEX)
86+
87+
const onSubmitSearch = () => {
88+
const s = search.trim().toLocaleLowerCase()
89+
setFilterKeywords(s)
90+
setSelectedId(null)
91+
sendEvent({
92+
action: 'auth_users_search_submitted',
93+
properties: {
94+
trigger: 'search_input',
95+
...telemetryProps,
96+
keywords: s,
97+
},
98+
groups: telemetryGroups,
99+
})
100+
}
101+
58102
return (
59103
<div className="flex items-center">
60104
<div className="text-xs h-[26px] flex items-center px-1.5 border border-strong rounded-l-md bg-surface-300">
@@ -63,7 +107,7 @@ export const UsersSearch = ({
63107

64108
<Select_Shadcn_
65109
value={specificFilterColumn}
66-
onValueChange={(v) => setSpecificFilterColumn(v as typeof specificFilterColumn)}
110+
onValueChange={(v) => onSelectFilterColumn(v as typeof specificFilterColumn)}
67111
>
68112
<SelectTrigger_Shadcn_
69113
size="tiny"
@@ -119,13 +163,10 @@ export const UsersSearch = ({
119163
)}
120164
placeholder={getSearchPlaceholder(specificFilterColumn)}
121165
value={search}
122-
onChange={(e) => {
123-
const value = e.target.value.replace(/\s+/g, '').toLowerCase()
124-
setSearch(value)
125-
}}
166+
onChange={(e) => setSearch(e.target.value)}
126167
onKeyDown={(e) => {
127168
if (e.code === 'Enter' || e.code === 'NumpadEnter') {
128-
if (!searchInvalid) setFilterKeywords(search.trim().toLocaleLowerCase())
169+
if (!searchInvalid) onSubmitSearch()
129170
}
130171
}}
131172
actions={

apps/studio/components/interfaces/Auth/Users/UsersV2.tsx

Lines changed: 24 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,10 @@ import pgMeta from '@supabase/pg-meta'
22
import type { OptimizedSearchColumns } from '@supabase/pg-meta/src/sql/studio/get-users-types'
33
import { keepPreviousData, useQueryClient } from '@tanstack/react-query'
44
import AwesomeDebouncePromise from 'awesome-debounce-promise'
5-
import {
6-
ExternalLinkIcon,
7-
InfoIcon,
8-
RefreshCw,
9-
Trash,
10-
Users,
11-
WandSparklesIcon,
12-
X,
13-
} from 'lucide-react'
14-
import Link from 'next/link'
15-
import { parseAsArrayOf, parseAsString, parseAsStringEnum, useQueryState } from 'nuqs'
16-
import { UIEvent, useEffect, useMemo, useRef, useState } from 'react'
17-
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
18-
import { toast } from 'sonner'
19-
205
import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common'
216
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
22-
import { AlertError } from 'components/ui/AlertError'
237
import { APIDocsButton } from 'components/ui/APIDocsButton'
8+
import { AlertError } from 'components/ui/AlertError'
249
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
2510
import { FilterPopover } from 'components/ui/FilterPopover'
2611
import { FormHeader } from 'components/ui/Forms/FormHeader'
@@ -40,26 +25,41 @@ import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization
4025
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
4126
import { cleanPointerEventsNoneOnBody, isAtBottom } from 'lib/helpers'
4227
import {
43-
Alert_Shadcn_,
28+
ExternalLinkIcon,
29+
InfoIcon,
30+
RefreshCw,
31+
Trash,
32+
Users,
33+
WandSparklesIcon,
34+
X,
35+
} from 'lucide-react'
36+
import Link from 'next/link'
37+
import { parseAsArrayOf, parseAsString, parseAsStringEnum, useQueryState } from 'nuqs'
38+
import { UIEvent, useEffect, useMemo, useRef, useState } from 'react'
39+
import DataGrid, { Column, DataGridHandle, Row } from 'react-data-grid'
40+
import { toast } from 'sonner'
41+
import {
4442
AlertDescription_Shadcn_,
4543
AlertTitle_Shadcn_,
44+
Alert_Shadcn_,
4645
Button,
47-
cn,
4846
LoadingLine,
4947
ResizablePanel,
5048
ResizablePanelGroup,
51-
Select_Shadcn_,
5249
SelectContent_Shadcn_,
5350
SelectGroup_Shadcn_,
5451
SelectItem_Shadcn_,
5552
SelectTrigger_Shadcn_,
5653
SelectValue_Shadcn_,
54+
Select_Shadcn_,
5755
Tooltip,
5856
TooltipContent,
5957
TooltipTrigger,
58+
cn,
6059
} from 'ui'
6160
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
6261
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
62+
6363
import { AddUserDropdown } from './AddUserDropdown'
6464
import { DeleteUserModal } from './DeleteUserModal'
6565
import { SortDropdown } from './SortDropdown'
@@ -69,10 +69,8 @@ import {
6969
ColumnConfiguration,
7070
Filter,
7171
MAX_BULK_DELETE,
72-
PHONE_NUMBER_LEFT_PREFIX_REGEX,
7372
PROVIDER_FILTER_OPTIONS,
7473
USERS_TABLE_COLUMNS,
75-
UUIDV4_LEFT_PREFIX_REGEX,
7674
} from './Users.constants'
7775
import { formatUserColumns, formatUsersData } from './Users.utils'
7876
import { UsersFooter } from './UsersFooter'
@@ -137,7 +135,7 @@ export const UsersV2 = () => {
137135
'userType',
138136
parseAsStringEnum(['all', 'verified', 'unverified', 'anonymous']).withDefault('all')
139137
)
140-
const [filterKeywords, setFilterKeywords] = useQueryState('keywords', { defaultValue: '' })
138+
const [filterKeywords] = useQueryState('keywords', { defaultValue: '' })
141139
const [sortByValue, setSortByValue] = useQueryState('sortBy', { defaultValue: 'created_at:desc' })
142140
const [sortColumn, sortOrder] = sortByValue.split(':')
143141
const [selectedColumns, setSelectedColumns] = useQueryState(
@@ -185,7 +183,6 @@ export const UsersV2 = () => {
185183
)
186184

187185
const [columns, setColumns] = useState<Column<any>[]>([])
188-
const [search, setSearch] = useState(filterKeywords)
189186
const [selectedUsers, setSelectedUsers] = useState<Set<any>>(new Set([]))
190187
const [selectedUserToDelete, setSelectedUserToDelete] = useState<User>()
191188
const [showDeleteModal, setShowDeleteModal] = useState(false)
@@ -330,16 +327,6 @@ export const UsersV2 = () => {
330327
// [Joshen] Only relevant for when selecting one user only
331328
const selectedUserFromCheckbox = users.find((u) => u.id === [...selectedUsers][0])
332329

333-
const searchInvalid =
334-
!search ||
335-
specificFilterColumn === 'freeform' ||
336-
specificFilterColumn === 'email' ||
337-
specificFilterColumn === 'name'
338-
? false
339-
: specificFilterColumn === 'id'
340-
? !search.match(UUIDV4_LEFT_PREFIX_REGEX)
341-
: !search.match(PHONE_NUMBER_LEFT_PREFIX_REGEX)
342-
343330
const telemetryProps = {
344331
sort_column: sortColumn,
345332
sort_order: sortOrder,
@@ -566,24 +553,10 @@ export const UsersV2 = () => {
566553
<>
567554
<div className="flex flex-wrap items-center gap-2">
568555
<UsersSearch
569-
search={search}
570-
searchInvalid={searchInvalid}
571-
specificFilterColumn={specificFilterColumn}
572-
setSearch={setSearch}
573-
setFilterKeywords={(s) => {
574-
setFilterKeywords(s)
575-
setSelectedId(null)
576-
sendEvent({
577-
action: 'auth_users_search_submitted',
578-
properties: {
579-
trigger: 'search_input',
580-
...telemetryProps,
581-
keywords: s,
582-
},
583-
groups: telemetryGroups,
584-
})
585-
}}
586-
setSpecificFilterColumn={(value) => {
556+
improvedSearchEnabled={improvedSearchEnabled}
557+
telemetryProps={telemetryProps}
558+
telemetryGroups={telemetryGroups}
559+
onSelectFilterColumn={(value) => {
587560
if (value === 'freeform') {
588561
if (isCountWithinThresholdForSortBy) {
589562
updateStorageFilter(value)
@@ -594,7 +567,6 @@ export const UsersV2 = () => {
594567
updateStorageFilter(value)
595568
}
596569
}}
597-
improvedSearchEnabled={improvedSearchEnabled}
598570
/>
599571

600572
{showUserTypeFilter &&

0 commit comments

Comments
 (0)