@@ -264,14 +264,54 @@ function HighlightedName({ name, query }: { name: string; query: string }) {
264264 ) ;
265265}
266266
267+ // "processors", "caches or rate limits" — plural label for the slot's allowed types.
268+ function pluralTypeLabel ( types ?: ConnectComponentType [ ] ) : string {
269+ if ( ! types || types . length === 0 ) {
270+ return 'components' ;
271+ }
272+ return types . map ( ( type ) => `${ type . replace ( / _ / g, ' ' ) } s` ) . join ( ' or ' ) ;
273+ }
274+
275+ const STARTS_WITH_VOWEL = / ^ [ a e i o u ] / ;
276+
277+ // "an input", "an input or a processor" — out-of-scope types with indefinite articles.
278+ function withArticles ( types : ConnectComponentType [ ] ) : string {
279+ const labeled = types . map ( ( type ) => {
280+ const label = type . replace ( / _ / g, ' ' ) ;
281+ return `${ STARTS_WITH_VOWEL . test ( label ) ? 'an' : 'a' } ${ label } ` ;
282+ } ) ;
283+ if ( labeled . length <= 1 ) {
284+ return labeled [ 0 ] ?? '' ;
285+ }
286+ return `${ labeled . slice ( 0 , - 1 ) . join ( ', ' ) } or ${ labeled . at ( - 1 ) } ` ;
287+ }
288+
289+ // Empty-state copy. A type-locked miss that matches other component types is explained
290+ // ("it exists as an input") so it doesn't read as a missing integration.
291+ export function buildEmptyMessage (
292+ query : string ,
293+ allowedTypes ?: ConnectComponentType [ ] ,
294+ outOfScopeTypes : ConnectComponentType [ ] = [ ]
295+ ) : string {
296+ if ( ! query ) {
297+ return 'No components available.' ;
298+ }
299+ if ( outOfScopeTypes . length === 0 ) {
300+ return `No ${ pluralTypeLabel ( allowedTypes ) } match “${ query } ”.` ;
301+ }
302+ return `No ${ pluralTypeLabel ( allowedTypes ) } match “${ query } ” — it exists as ${ withArticles ( outOfScopeTypes ) } .` ;
303+ }
304+
267305function Row ( {
268306 component,
269307 query,
270308 onPreview,
309+ onCommit,
271310} : {
272311 component : ConnectComponentSpec ;
273312 query : string ;
274313 onPreview : ( component : ConnectComponentSpec ) => void ;
314+ onCommit : ( component : ConnectComponentSpec ) => void ;
275315} ) {
276316 const category = component . categories ?. [ 0 ] ;
277317 // Fall back to the humanized type (cache / rate_limit / …) so same-named components of different
@@ -281,6 +321,7 @@ function Row({
281321 < CommandItem
282322 className = "gap-3 hover:bg-accent/50"
283323 key = { `${ component . type } -${ component . name } ` }
324+ onDoubleClick = { ( ) => onCommit ( component ) }
284325 onSelect = { ( ) => onPreview ( component ) }
285326 value = { `${ component . type } :${ component . name } ` }
286327 >
@@ -378,7 +419,7 @@ function DetailPane({ component }: { component?: ConnectComponentSpec }) {
378419type ConnectCommandPaletteProps = {
379420 components ?: ComponentList ;
380421 additionalComponents ?: ExtendedConnectComponentSpec [ ] ;
381- /** Component types valid in the slot being filled — the palette locks to these unless "Show all" is toggled . */
422+ /** Component types valid in the slot being filled — the palette only lists components of these types . */
382423 allowedTypes ?: ConnectComponentType [ ] ;
383424 onSelect : ( connectionName : string , connectionType : ConnectComponentType ) => void ;
384425 /** Dismisses the picker without adding anything (wired to the footer Cancel button). */
@@ -447,6 +488,21 @@ export const ConnectCommandPalette = ({
447488 ) ;
448489 } , [ inScope , q ] ) ;
449490
491+ // When a type-locked search comes up empty, the component types (outside the slot's scope)
492+ // that DO match the query — surfaced in the empty state so the miss isn't read as a gap.
493+ const outOfScopeTypes = useMemo ( ( ) => {
494+ if ( ! q || results . length > 0 || ! allowedTypes || allowedTypes . length === 0 ) {
495+ return [ ] ;
496+ }
497+ const types = new Set < ConnectComponentType > ( ) ;
498+ for ( const component of allComponents ) {
499+ if ( ! typeAllowed ( component . type ) && matchRank ( component , q , searchableText ( component ) ) >= 0 ) {
500+ types . add ( component . type ) ;
501+ }
502+ }
503+ return [ ...types ] . sort ( ) ;
504+ } , [ q , results , allowedTypes , allComponents , typeAllowed ] ) ;
505+
450506 // Browse facets (no query): recents + suggested + everything grouped by category.
451507 const recentComponents = useMemo (
452508 ( ) => recents . map ( ( r ) => byName . get ( r . name ) ) . filter ( ( c ) : c is ConnectComponentSpec => Boolean ( c ) ) ,
@@ -532,7 +588,8 @@ export const ConnectCommandPalette = ({
532588 return null ; // "all" renders the grouped view, not a flat list.
533589 } , [ currentTab , recentComponents , suggested , grouped ] ) ;
534590
535- // Enter adds the highlighted component (fast keyboard path); clicking only previews, keeping insertion explicit.
591+ // Enter adds the highlighted component (fast keyboard path); a single click only previews,
592+ // keeping insertion explicit, while double-click commits directly.
536593 const handleKeyDown = ( event : React . KeyboardEvent ) => {
537594 if ( event . key === 'Enter' && ! event . nativeEvent . isComposing && activeComponent ) {
538595 event . preventDefault ( ) ;
@@ -574,14 +631,15 @@ export const ConnectCommandPalette = ({
574631
575632 < div className = "flex min-h-0 flex-1" >
576633 < CommandList className = "h-full max-h-none min-w-0 flex-1 md:max-w-[28rem] md:border-r" >
577- < CommandEmpty > No components match “ { query } ”. </ CommandEmpty >
634+ < CommandEmpty > { buildEmptyMessage ( query . trim ( ) , allowedTypes , outOfScopeTypes ) } </ CommandEmpty >
578635
579636 { q ? (
580637 < CommandGroup heading = "Results" >
581638 { results . map ( ( component ) => (
582639 < Row
583640 component = { component }
584641 key = { `${ component . type } -${ component . name } ` }
642+ onCommit = { handleCommit }
585643 onPreview = { handlePreview }
586644 query = { q }
587645 />
@@ -593,6 +651,7 @@ export const ConnectCommandPalette = ({
593651 < Row
594652 component = { component }
595653 key = { `${ component . type } -${ component . name } ` }
654+ onCommit = { handleCommit }
596655 onPreview = { handlePreview }
597656 query = ""
598657 />
@@ -605,6 +664,7 @@ export const ConnectCommandPalette = ({
605664 < Row
606665 component = { component }
607666 key = { `${ component . type } -${ component . name } ` }
667+ onCommit = { handleCommit }
608668 onPreview = { handlePreview }
609669 query = ""
610670 />
0 commit comments