1
- import { Fragment , useCallback , useMemo } from 'react' ;
1
+ import { Fragment , memo , useCallback , useMemo , useState } from 'react' ;
2
2
import styled from '@emotion/styled' ;
3
3
4
4
import { Tag as Badge } from 'sentry/components/core/badge/tag' ;
5
+ import { InputGroup } from 'sentry/components/core/input/inputGroup' ;
5
6
import MultipleCheckbox from 'sentry/components/forms/controls/multipleCheckbox' ;
6
7
import { DrawerBody , DrawerHeader } from 'sentry/components/globalDrawer/components' ;
7
8
import { IconSearch } from 'sentry/icons' ;
@@ -24,6 +25,8 @@ function SchemaHintsDrawer({hints}: SchemaHintsDrawerProps) {
24
25
const exploreQuery = useExploreQuery ( ) ;
25
26
const setExploreQuery = useSetExploreQuery ( ) ;
26
27
28
+ const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
29
+
27
30
const selectedFilterKeys = useMemo ( ( ) => {
28
31
const filterQuery = new MutableSearch ( exploreQuery ) ;
29
32
return filterQuery . getFilterKeys ( ) ;
@@ -52,6 +55,18 @@ function SchemaHintsDrawer({hints}: SchemaHintsDrawerProps) {
52
55
] ;
53
56
} , [ hints , sortedSelectedHints ] ) ;
54
57
58
+ const sortedAndFilteredHints = useMemo ( ( ) => {
59
+ if ( ! searchQuery . trim ( ) ) {
60
+ return sortedHints ;
61
+ }
62
+
63
+ const searchFor = searchQuery . toLocaleLowerCase ( ) . trim ( ) ;
64
+
65
+ return sortedHints . filter ( hint =>
66
+ prettifyTagKey ( hint . key ) . toLocaleLowerCase ( ) . trim ( ) . includes ( searchFor )
67
+ ) ;
68
+ } , [ sortedHints , searchQuery ] ) ;
69
+
55
70
const handleCheckboxChange = useCallback (
56
71
( hint : Tag ) => {
57
72
const filterQuery = new MutableSearch ( exploreQuery ) ;
@@ -73,36 +88,68 @@ function SchemaHintsDrawer({hints}: SchemaHintsDrawerProps) {
73
88
[ exploreQuery , setExploreQuery ]
74
89
) ;
75
90
91
+ const noAttributesMessage = (
92
+ < NoAttributesMessage >
93
+ < p > { t ( 'No attributes found.' ) } </ p >
94
+ </ NoAttributesMessage >
95
+ ) ;
96
+
97
+ const HintItem = memo (
98
+ ( { hint} : { hint : Tag } ) => {
99
+ const hintFieldDefinition = useMemo (
100
+ ( ) => getFieldDefinition ( hint . key , 'span' , hint . kind ) ,
101
+ [ hint . key , hint . kind ]
102
+ ) ;
103
+
104
+ const hintType = useMemo (
105
+ ( ) =>
106
+ hintFieldDefinition ?. valueType === FieldValueType . BOOLEAN
107
+ ? t ( 'boolean' )
108
+ : hint . kind === FieldKind . MEASUREMENT
109
+ ? t ( 'number' )
110
+ : t ( 'string' ) ,
111
+ [ hintFieldDefinition ?. valueType , hint . kind ]
112
+ ) ;
113
+ return (
114
+ < StyledMultipleCheckboxItem
115
+ key = { hint . key }
116
+ value = { hint . key }
117
+ onChange = { ( ) => handleCheckboxChange ( hint ) }
118
+ >
119
+ < CheckboxLabelContainer >
120
+ < CheckboxLabel > { prettifyTagKey ( hint . key ) } </ CheckboxLabel >
121
+ < Badge > { hintType } </ Badge >
122
+ </ CheckboxLabelContainer >
123
+ </ StyledMultipleCheckboxItem >
124
+ ) ;
125
+ } ,
126
+ ( prevProps , nextProps ) => {
127
+ return prevProps . hint . key === nextProps . hint . key ;
128
+ }
129
+ ) ;
130
+
76
131
return (
77
132
< Fragment >
78
133
< DrawerHeader hideBar />
79
134
< DrawerBody >
80
135
< HeaderContainer >
81
136
< SchemaHintsHeader > { t ( 'Filter Attributes' ) } </ SchemaHintsHeader >
82
- < IconSearch size = "md" />
137
+ < StyledInputGroup >
138
+ < SearchInput
139
+ size = "sm"
140
+ value = { searchQuery }
141
+ onChange = { e => setSearchQuery ( e . target . value ) }
142
+ aria-label = { t ( 'Search attributes' ) }
143
+ />
144
+ < InputGroup . TrailingItems disablePointerEvents >
145
+ < IconSearch size = "md" />
146
+ </ InputGroup . TrailingItems >
147
+ </ StyledInputGroup >
83
148
</ HeaderContainer >
84
149
< StyledMultipleCheckbox name = { t ( 'Filter keys' ) } value = { selectedFilterKeys } >
85
- { sortedHints . map ( hint => {
86
- const hintFieldDefinition = getFieldDefinition ( hint . key , 'span' , hint . kind ) ;
87
- const hintType =
88
- hintFieldDefinition ?. valueType === FieldValueType . BOOLEAN
89
- ? t ( 'boolean' )
90
- : hint . kind === FieldKind . MEASUREMENT
91
- ? t ( 'number' )
92
- : t ( 'string' ) ;
93
- return (
94
- < StyledMultipleCheckboxItem
95
- key = { hint . key }
96
- value = { hint . key }
97
- onChange = { ( ) => handleCheckboxChange ( hint ) }
98
- >
99
- < CheckboxLabelContainer >
100
- < CheckboxLabel > { prettifyTagKey ( hint . key ) } </ CheckboxLabel >
101
- < Badge > { hintType } </ Badge >
102
- </ CheckboxLabelContainer >
103
- </ StyledMultipleCheckboxItem >
104
- ) ;
105
- } ) }
150
+ { sortedAndFilteredHints . length === 0
151
+ ? noAttributesMessage
152
+ : sortedAndFilteredHints . map ( hint => < HintItem key = { hint . key } hint = { hint } /> ) }
106
153
</ StyledMultipleCheckbox >
107
154
</ DrawerBody >
108
155
</ Fragment >
@@ -174,3 +221,23 @@ const StyledMultipleCheckboxItem = styled(MultipleCheckbox.Item)`
174
221
${ p => p . theme . overflowEllipsis } ;
175
222
}
176
223
` ;
224
+
225
+ const SearchInput = styled ( InputGroup . Input ) `
226
+ border: 0;
227
+ box-shadow: unset;
228
+ color: inherit;
229
+ ` ;
230
+
231
+ const NoAttributesMessage = styled ( 'div' ) `
232
+ display: flex;
233
+ justify-content: center;
234
+ align-items: center;
235
+ margin-top: ${ space ( 4 ) } ;
236
+ color: ${ p => p . theme . subText } ;
237
+ ` ;
238
+
239
+ const StyledInputGroup = styled ( InputGroup ) `
240
+ @media (max-width: ${ p => p . theme . breakpoints . medium } ) {
241
+ max-width: 175px;
242
+ }
243
+ ` ;
0 commit comments