@@ -29,12 +29,14 @@ type IntegrationsManagerProps = {
2929 showCreateDialog : boolean ;
3030 onCreateDialogClose ?: ( ) => void ;
3131 onIntegrationChange ?: ( ) => void ;
32+ filter ?: string ;
3233} ;
3334
3435export function IntegrationsManager ( {
3536 showCreateDialog : externalShowCreateDialog ,
3637 onCreateDialogClose,
3738 onIntegrationChange,
39+ filter = "" ,
3840} : IntegrationsManagerProps ) {
3941 const [ integrations , setIntegrations ] = useState < Integration [ ] > ( [ ] ) ;
4042 const [ loading , setLoading ] = useState ( true ) ;
@@ -69,6 +71,7 @@ export function IntegrationsManager({
6971 // Get integrations with their labels, sorted by label then name
7072 const integrationsWithLabels = useMemo ( ( ) => {
7173 const labels = getIntegrationLabels ( ) as Record < string , string > ;
74+ const filterLower = filter . toLowerCase ( ) ;
7275
7376 return integrations
7477 . map ( ( integration ) => ( {
@@ -78,14 +81,22 @@ export function IntegrationsManager({
7881 SYSTEM_INTEGRATION_LABELS [ integration . type ] ||
7982 integration . type ,
8083 } ) )
84+ . filter ( ( integration ) => {
85+ if ( ! filter ) return true ;
86+ return (
87+ integration . label . toLowerCase ( ) . includes ( filterLower ) ||
88+ integration . name . toLowerCase ( ) . includes ( filterLower ) ||
89+ integration . type . toLowerCase ( ) . includes ( filterLower )
90+ ) ;
91+ } )
8192 . sort ( ( a , b ) => {
8293 const labelCompare = a . label . localeCompare ( b . label ) ;
8394 if ( labelCompare !== 0 ) {
8495 return labelCompare ;
8596 }
8697 return a . name . localeCompare ( b . name ) ;
8798 } ) ;
88- } , [ integrations ] ) ;
99+ } , [ integrations , filter ] ) ;
89100
90101 const handleDelete = async ( id : string ) => {
91102 try {
@@ -139,70 +150,88 @@ export function IntegrationsManager({
139150 ) ;
140151 }
141152
142- return (
143- < div className = "space-y-1" >
144- { integrations . length === 0 ? (
153+ const renderIntegrationsList = ( ) => {
154+ if ( integrations . length === 0 ) {
155+ return (
145156 < div className = "py-8 text-center" >
146157 < p className = "text-muted-foreground text-sm" >
147158 No connections configured yet
148159 </ p >
149160 </ div >
150- ) : (
151- < div className = "space-y-1" >
152- { integrationsWithLabels . map ( ( integration ) => (
153- < div
154- className = "flex items-center justify-between rounded-md px-2 py-1.5"
155- key = { integration . id }
156- >
157- < div className = "flex items-center gap-2" >
158- < IntegrationIcon
159- className = "size-4"
160- integration = {
161- integration . type === "ai-gateway"
162- ? "vercel"
163- : integration . type
164- }
165- />
166- < span className = "font-medium text-sm" > { integration . label } </ span >
167- < span className = "text-muted-foreground text-sm" >
168- { integration . name }
169- </ span >
170- </ div >
171- < div className = "flex items-center gap-1" >
172- < Button
173- className = "h-7 px-2"
174- disabled = { testingId === integration . id }
175- onClick = { ( ) => handleTest ( integration . id ) }
176- size = "sm"
177- variant = "outline"
178- >
179- { testingId === integration . id ? (
180- < Spinner className = "size-3" />
181- ) : (
182- < span className = "text-xs" > Test</ span >
183- ) }
184- </ Button >
185- < Button
186- className = "size-7"
187- onClick = { ( ) => setEditingIntegration ( integration ) }
188- size = "icon"
189- variant = "outline"
190- >
191- < Pencil className = "size-3" />
192- </ Button >
193- < Button
194- className = "size-7"
195- onClick = { ( ) => setDeletingId ( integration . id ) }
196- size = "icon"
197- variant = "outline"
198- >
199- < Trash2 className = "size-3" />
200- </ Button >
201- </ div >
202- </ div >
203- ) ) }
161+ ) ;
162+ }
163+
164+ if ( integrationsWithLabels . length === 0 ) {
165+ return (
166+ < div className = "py-8 text-center" >
167+ < p className = "text-muted-foreground text-sm" >
168+ No connections match your filter
169+ </ p >
204170 </ div >
205- ) }
171+ ) ;
172+ }
173+
174+ return (
175+ < div className = "space-y-1" >
176+ { integrationsWithLabels . map ( ( integration ) => (
177+ < div
178+ className = "flex items-center justify-between rounded-md px-2 py-1.5"
179+ key = { integration . id }
180+ >
181+ < div className = "flex items-center gap-2" >
182+ < IntegrationIcon
183+ className = "size-4"
184+ integration = {
185+ integration . type === "ai-gateway"
186+ ? "vercel"
187+ : integration . type
188+ }
189+ />
190+ < span className = "font-medium text-sm" > { integration . label } </ span >
191+ < span className = "text-muted-foreground text-sm" >
192+ { integration . name }
193+ </ span >
194+ </ div >
195+ < div className = "flex items-center gap-1" >
196+ < Button
197+ className = "h-7 px-2"
198+ disabled = { testingId === integration . id }
199+ onClick = { ( ) => handleTest ( integration . id ) }
200+ size = "sm"
201+ variant = "outline"
202+ >
203+ { testingId === integration . id ? (
204+ < Spinner className = "size-3" />
205+ ) : (
206+ < span className = "text-xs" > Test</ span >
207+ ) }
208+ </ Button >
209+ < Button
210+ className = "size-7"
211+ onClick = { ( ) => setEditingIntegration ( integration ) }
212+ size = "icon"
213+ variant = "outline"
214+ >
215+ < Pencil className = "size-3" />
216+ </ Button >
217+ < Button
218+ className = "size-7"
219+ onClick = { ( ) => setDeletingId ( integration . id ) }
220+ size = "icon"
221+ variant = "outline"
222+ >
223+ < Trash2 className = "size-3" />
224+ </ Button >
225+ </ div >
226+ </ div >
227+ ) ) }
228+ </ div >
229+ ) ;
230+ } ;
231+
232+ return (
233+ < div className = "space-y-1" >
234+ { renderIntegrationsList ( ) }
206235
207236 { ( showCreateDialog || editingIntegration ) && (
208237 < IntegrationFormDialog
0 commit comments