1- import {
2- Box ,
3- Button ,
4- Flex ,
5- HStack ,
6- Icon ,
7- Input ,
8- Text ,
9- Menu ,
10- } from '@chakra-ui/react' ;
1+ import { Box , Button , Flex , HStack , Icon , Input , Text , Menu } from '@chakra-ui/react' ;
112import { X } from 'lucide-react' ;
123import type { LiveStatusParams } from '@/api/types' ;
134import { MdSearch , MdExpandMore } from 'react-icons/md' ;
145import { ComboboxSelect } from '../common/ComboboxSelect' ;
15- // import { EndpointCombobox } from '../common/ComboboxSelect';
166
177interface StatusFiltersProps {
188 filters : LiveStatusParams ;
@@ -61,7 +51,6 @@ export function StatusFilters({
6151
6252 const clearSearch = ( ) => {
6353 onSearchChange ?.( '' ) ;
64-
6554 } ;
6655
6756 return (
@@ -85,129 +74,145 @@ export function StatusFilters({
8574 } }
8675 data-testid = 'status-filters'
8776 >
88- < HStack gap = { { base : 2 , md : 4 } } align = 'center' flexWrap = { { base : 'wrap' , md : 'nowrap' } } >
77+ < HStack
78+ gap = { { base : 2 , md : 4 } }
79+ align = 'center'
80+ justifyContent = { 'flex-start' }
81+ flexWrap = { { base : 'wrap' , md : 'nowrap' } }
82+ >
8983 { /* Group Filter */ }
90-
91- { /* Search Input */ }
92- < Flex w = '80' position = 'relative' align = 'center' >
93- < Icon
94- as = { MdSearch }
95- color = 'gray.400'
96- position = 'absolute'
97- left = '3'
98- top = '50%'
99- transform = 'translateY(-50%)'
100- zIndex = { 2 }
101- fontSize = { '18px' }
102- />
103- < Input
104- placeholder = 'Search endpoints by name or host...'
105- pl = '10'
106- pr = { searchTerm ? '10' : '4' }
107- value = { searchTerm }
108- onChange = { e => handleSearchChange ( e . target . value ) }
109- data-testid = 'search-input'
84+ < Box >
85+ < ComboboxSelect
86+ items = { groups . map ( g => ( { label : g . name , value : g . id } ) ) }
87+ selectedValue = { selectedGroup ? selectedGroup : '' }
88+ onChange = { handleGroupChange }
89+ isLoading = { false }
11090 />
111- { searchTerm && (
112- < Box
113- px = { 3 }
114- onClick = { clearSearch }
115- data-testid = 'clear-search'
91+ </ Box >
92+ { /* Search Input */ }
93+ < Box >
94+ < Flex w = '80' position = 'relative' align = 'center' >
95+ < Icon
96+ as = { MdSearch }
97+ color = 'gray.400'
11698 position = 'absolute'
117- right = '0 '
99+ left = '3 '
118100 top = '50%'
119101 transform = 'translateY(-50%)'
120- zIndex = { 10 }
121- cursor = { 'pointer' }
122- >
123- < X size = { 16 } />
124- </ Box >
125- ) }
126- </ Flex >
127-
128- { /* Group By Dropdown */ }
129- < Menu . Root >
130- < Menu . Trigger asChild >
131- < Button variant = 'outline' >
132- < Text fontSize = 'sm' >
133- { groupByOptions . length > 0
134- ? groupByOptions
135- . map ( opt => ( opt === 'status' ? 'Status' : opt === 'group' ? 'Group' : opt ) )
136- . join ( ' + ' )
137- : 'Group By' }
138- </ Text >
139- < MdExpandMore />
140- </ Button >
141- </ Menu . Trigger >
142- < Menu . Positioner px = { 4 } >
143- < Menu . Content minWidth = '200px' >
144- < Flex
145- justify = 'flex-end'
146- px = { 2 }
147- py = { 1 }
148- borderBottom = '1px solid'
149- borderColor = 'gray.200'
150- _dark = { { borderColor : 'gray.600' } }
102+ zIndex = { 2 }
103+ fontSize = { '18px' }
104+ />
105+ < Input
106+ placeholder = 'Search endpoints by name or host...'
107+ pl = '10'
108+ pr = { searchTerm ? '10' : '4' }
109+ value = { searchTerm }
110+ onChange = { e => handleSearchChange ( e . target . value ) }
111+ data-testid = 'search-input'
112+ />
113+ { searchTerm && (
114+ < Box
115+ px = { 3 }
116+ onClick = { clearSearch }
117+ data-testid = 'clear-search'
118+ position = 'absolute'
119+ right = '0'
120+ top = '50%'
121+ transform = 'translateY(-50%)'
122+ zIndex = { 10 }
123+ cursor = { 'pointer' }
151124 >
152- < HStack gap = { 2 } >
153- < Button
154- size = 'xs'
155- variant = 'ghost'
156- onClick = { ( ) => {
157- [ 'status' , 'group' ] . forEach (
158- opt => onToggleGroupBy && onToggleGroupBy ( opt , true )
159- ) ;
125+ < X size = { 16 } />
126+ </ Box >
127+ ) }
128+ </ Flex >
129+ </ Box >
130+ { /* Group By Dropdown */ }
131+ < Box >
132+ < Menu . Root >
133+ < Menu . Trigger asChild >
134+ < Button variant = 'outline' >
135+ < Text fontSize = 'sm' >
136+ { groupByOptions . length > 0
137+ ? groupByOptions
138+ . map ( opt => ( opt === 'status' ? 'Status' : opt === 'group' ? 'Group' : opt ) )
139+ . join ( ' + ' )
140+ : 'Group By' }
141+ </ Text >
142+ < MdExpandMore />
143+ </ Button >
144+ </ Menu . Trigger >
145+ < Menu . Positioner px = { 4 } >
146+ < Menu . Content minWidth = '200px' >
147+ < Flex
148+ justify = 'flex-end'
149+ px = { 2 }
150+ py = { 1 }
151+ borderBottom = '1px solid'
152+ borderColor = 'gray.200'
153+ _dark = { { borderColor : 'gray.600' } }
154+ >
155+ < HStack gap = { 2 } >
156+ < Button
157+ size = 'xs'
158+ variant = 'ghost'
159+ onClick = { ( ) => {
160+ [ 'status' , 'group' ] . forEach (
161+ opt => onToggleGroupBy && onToggleGroupBy ( opt , true )
162+ ) ;
163+ } }
164+ textDecoration = { 'underline' }
165+ >
166+ Select All
167+ </ Button >
168+ < Button
169+ size = 'xs'
170+ variant = 'ghost'
171+ onClick = { ( ) => {
172+ [ 'status' , 'group' ] . forEach (
173+ opt => onToggleGroupBy && onToggleGroupBy ( opt , false )
174+ ) ;
175+ } }
176+ textDecoration = { 'underline' }
177+ >
178+ Clear
179+ </ Button >
180+ </ HStack >
181+ </ Flex >
182+ < Menu . ItemGroup >
183+ < Menu . CheckboxItem
184+ cursor = { 'pointer' }
185+ value = 'status'
186+ checked = { groupByOptions . includes ( 'status' ) }
187+ onCheckedChange = { ( ) => {
188+ onToggleGroupBy &&
189+ onToggleGroupBy ( 'status' , ! groupByOptions . includes ( 'status' ) ) ;
160190 } }
161- textDecoration = { 'underline' }
162191 >
163- Select All
164- </ Button >
165- < Button
166- size = 'xs'
167- variant = 'ghost'
168- onClick = { ( ) => {
169- [ 'status' , 'group' ] . forEach (
170- opt => onToggleGroupBy && onToggleGroupBy ( opt , false )
171- ) ;
192+ < Flex w = 'full' justify = 'flex-start' align = 'center' gap = { 3 } >
193+ < Text as = 'span' > Group by Status</ Text >
194+ < Menu . ItemIndicator />
195+ </ Flex >
196+ </ Menu . CheckboxItem >
197+ < Menu . CheckboxItem
198+ cursor = { 'pointer' }
199+ value = 'group'
200+ checked = { groupByOptions . includes ( 'group' ) }
201+ onCheckedChange = { ( ) => {
202+ onToggleGroupBy &&
203+ onToggleGroupBy ( 'group' , ! groupByOptions . includes ( 'group' ) ) ;
172204 } }
173- textDecoration = { 'underline' }
174205 >
175- Clear
176- </ Button >
177- </ HStack >
178- </ Flex >
179- < Menu . ItemGroup >
180- < Menu . CheckboxItem
181- cursor = { 'pointer' }
182- value = 'status'
183- checked = { groupByOptions . includes ( 'status' ) }
184- onCheckedChange = { ( ) => {
185- onToggleGroupBy &&
186- onToggleGroupBy ( 'status' , ! groupByOptions . includes ( 'status' ) ) ;
187- } }
188- >
189- < Flex w = 'full' justify = 'flex-start' align = 'center' gap = { 3 } >
190- < Text as = 'span' > Group by Status</ Text >
191- < Menu . ItemIndicator />
192- </ Flex >
193- </ Menu . CheckboxItem >
194- < Menu . CheckboxItem
195- cursor = { 'pointer' }
196- value = 'group'
197- checked = { groupByOptions . includes ( 'group' ) }
198- onCheckedChange = { ( ) => {
199- onToggleGroupBy && onToggleGroupBy ( 'group' , ! groupByOptions . includes ( 'group' ) ) ;
200- } }
201- >
202- < Flex w = 'full' justify = 'flex-start' align = 'center' gap = { 3 } >
203- < Text as = 'span' > Group by Group</ Text >
204- < Menu . ItemIndicator />
205- </ Flex >
206- </ Menu . CheckboxItem >
207- </ Menu . ItemGroup >
208- </ Menu . Content >
209- </ Menu . Positioner >
210- </ Menu . Root >
206+ < Flex w = 'full' justify = 'flex-start' align = 'center' gap = { 3 } >
207+ < Text as = 'span' > Group by Group</ Text >
208+ < Menu . ItemIndicator />
209+ </ Flex >
210+ </ Menu . CheckboxItem >
211+ </ Menu . ItemGroup >
212+ </ Menu . Content >
213+ </ Menu . Positioner >
214+ </ Menu . Root >
215+ </ Box >
211216 </ HStack >
212217 </ Box >
213218 ) ;
0 commit comments