@@ -20,7 +20,10 @@ import {
2020} from '@/lib/api/contracts/workspace-files'
2121import { createMcpToolId } from '@/lib/mcp/shared'
2222import type { Credential } from '@/lib/oauth'
23- import { stableStringifyWorkflowSearchValue } from '@/lib/workflows/search-replace/resources'
23+ import {
24+ getWorkflowSearchMatchResourceGroupKey ,
25+ stableStringifyWorkflowSearchValue ,
26+ } from '@/lib/workflows/search-replace/resources'
2427import type {
2528 WorkflowSearchMatch ,
2629 WorkflowSearchReplacementOption ,
@@ -151,6 +154,22 @@ function uniqueSelectorOptionGroups(matches: WorkflowSearchMatch[]): WorkflowSea
151154 } )
152155}
153156
157+ function uniqueResourceOptionGroups (
158+ matches : WorkflowSearchMatch [ ] ,
159+ kind : WorkflowSearchMatch [ 'kind' ] ,
160+ predicate ?: ( match : WorkflowSearchMatch ) => boolean
161+ ) : WorkflowSearchMatch [ ] {
162+ const seen = new Set < string > ( )
163+ return matches . filter ( ( match ) => {
164+ if ( match . kind !== kind || predicate ?.( match ) === false ) return false
165+
166+ const key = getWorkflowSearchMatchResourceGroupKey ( match )
167+ if ( seen . has ( key ) ) return false
168+ seen . add ( key )
169+ return true
170+ } )
171+ }
172+
154173export function useWorkflowSearchOAuthCredentialDetails (
155174 matches : WorkflowSearchMatch [ ] ,
156175 workflowId ?: string
@@ -445,7 +464,7 @@ export function useWorkflowSearchTableReplacementOptions(
445464 matches : WorkflowSearchMatch [ ] ,
446465 workspaceId ?: string
447466) {
448- const tableMatch = useMemo ( ( ) => matches . find ( ( match ) => match . kind === 'table' ) , [ matches ] )
467+ const tableGroups = useMemo ( ( ) => uniqueResourceOptionGroups ( matches , 'table' ) , [ matches ] )
449468
450469 return useQueries ( {
451470 queries : [
@@ -456,15 +475,17 @@ export function useWorkflowSearchTableReplacementOptions(
456475 query : { workspaceId : workspaceId as string , scope : 'active' } ,
457476 signal,
458477 } ) ,
459- enabled : Boolean ( workspaceId && tableMatch ) ,
478+ enabled : Boolean ( workspaceId && tableGroups . length > 0 ) ,
460479 staleTime : 60 * 1000 ,
461480 select : ( response : ListTablesResponse ) : WorkflowSearchReplacementOption [ ] =>
462- response . data . tables . map ( ( table ) => ( {
463- kind : 'table' ,
464- value : table . id ,
465- label : table . name ,
466- resourceGroupKey : tableMatch ?. resource ?. resourceGroupKey ,
467- } ) ) ,
481+ tableGroups . flatMap ( ( match ) =>
482+ response . data . tables . map ( ( table ) => ( {
483+ kind : 'table' ,
484+ value : table . id ,
485+ label : table . name ,
486+ resourceGroupKey : match . resource ?. resourceGroupKey ,
487+ } ) )
488+ ) ,
468489 } ,
469490 ] ,
470491 } )
@@ -474,8 +495,8 @@ export function useWorkflowSearchFileReplacementOptions(
474495 matches : WorkflowSearchMatch [ ] ,
475496 workspaceId ?: string
476497) {
477- const fileMatch = useMemo (
478- ( ) => matches . find ( ( match ) => match . kind === 'file' && ! match . resource ?. selectorKey ) ,
498+ const fileGroups = useMemo (
499+ ( ) => uniqueResourceOptionGroups ( matches , 'file' , ( match ) => ! match . resource ?. selectorKey ) ,
479500 [ matches ]
480501 )
481502
@@ -489,21 +510,23 @@ export function useWorkflowSearchFileReplacementOptions(
489510 query : { scope : 'active' } ,
490511 signal,
491512 } ) ,
492- enabled : Boolean ( workspaceId && fileMatch ) ,
513+ enabled : Boolean ( workspaceId && fileGroups . length > 0 ) ,
493514 staleTime : 60 * 1000 ,
494515 select : ( response : ListWorkspaceFilesResponse ) : WorkflowSearchReplacementOption [ ] =>
495- response . files . map ( ( file ) => ( {
496- kind : 'file' ,
497- value : JSON . stringify ( {
498- name : file . name ,
499- path : file . path ,
500- key : file . key ,
501- size : file . size ,
502- type : file . type ,
503- } ) ,
504- label : file . name ,
505- resourceGroupKey : fileMatch ?. resource ?. resourceGroupKey ,
506- } ) ) ,
516+ fileGroups . flatMap ( ( match ) =>
517+ response . files . map ( ( file ) => ( {
518+ kind : 'file' ,
519+ value : JSON . stringify ( {
520+ name : file . name ,
521+ path : file . path ,
522+ key : file . key ,
523+ size : file . size ,
524+ type : file . type ,
525+ } ) ,
526+ label : file . name ,
527+ resourceGroupKey : match . resource ?. resourceGroupKey ,
528+ } ) )
529+ ) ,
507530 } ,
508531 ] ,
509532 } )
@@ -513,7 +536,7 @@ export function useWorkflowSearchMcpServerReplacementOptions(
513536 matches : WorkflowSearchMatch [ ] ,
514537 workspaceId ?: string
515538) {
516- const serverMatch = useMemo ( ( ) => matches . find ( ( match ) => match . kind === 'mcp-server' ) , [ matches ] )
539+ const serverGroups = useMemo ( ( ) => uniqueResourceOptionGroups ( matches , 'mcp-server' ) , [ matches ] )
517540
518541 return useQueries ( {
519542 queries : [
@@ -524,15 +547,17 @@ export function useWorkflowSearchMcpServerReplacementOptions(
524547 query : { workspaceId : workspaceId as string } ,
525548 signal,
526549 } ) ,
527- enabled : Boolean ( workspaceId && serverMatch ) ,
550+ enabled : Boolean ( workspaceId && serverGroups . length > 0 ) ,
528551 staleTime : 60 * 1000 ,
529552 select : ( response : ListMcpServersResponse ) : WorkflowSearchReplacementOption [ ] =>
530- response . data . servers . map ( ( server ) => ( {
531- kind : 'mcp-server' ,
532- value : server . id ,
533- label : server . name ,
534- resourceGroupKey : serverMatch ?. resource ?. resourceGroupKey ,
535- } ) ) ,
553+ serverGroups . flatMap ( ( match ) =>
554+ response . data . servers . map ( ( server ) => ( {
555+ kind : 'mcp-server' ,
556+ value : server . id ,
557+ label : server . name ,
558+ resourceGroupKey : match . resource ?. resourceGroupKey ,
559+ } ) )
560+ ) ,
536561 } ,
537562 ] ,
538563 } )
@@ -542,7 +567,7 @@ export function useWorkflowSearchMcpToolReplacementOptions(
542567 matches : WorkflowSearchMatch [ ] ,
543568 workspaceId ?: string
544569) {
545- const toolMatch = useMemo ( ( ) => matches . find ( ( match ) => match . kind === 'mcp-tool' ) , [ matches ] )
570+ const toolGroups = useMemo ( ( ) => uniqueResourceOptionGroups ( matches , 'mcp-tool' ) , [ matches ] )
546571
547572 return useQueries ( {
548573 queries : [
@@ -553,15 +578,17 @@ export function useWorkflowSearchMcpToolReplacementOptions(
553578 query : { workspaceId : workspaceId as string } ,
554579 signal,
555580 } ) ,
556- enabled : Boolean ( workspaceId && toolMatch ) ,
581+ enabled : Boolean ( workspaceId && toolGroups . length > 0 ) ,
557582 staleTime : 60 * 1000 ,
558583 select : ( response : DiscoverMcpToolsResponse ) : WorkflowSearchReplacementOption [ ] =>
559- response . data . tools . map ( ( tool ) => ( {
560- kind : 'mcp-tool' ,
561- value : createMcpToolId ( tool . serverId , tool . name ) ,
562- label : `${ tool . serverName } : ${ tool . name } ` ,
563- resourceGroupKey : toolMatch ?. resource ?. resourceGroupKey ,
564- } ) ) ,
584+ toolGroups . flatMap ( ( match ) =>
585+ response . data . tools . map ( ( tool ) => ( {
586+ kind : 'mcp-tool' ,
587+ value : createMcpToolId ( tool . serverId , tool . name ) ,
588+ label : `${ tool . serverName } : ${ tool . name } ` ,
589+ resourceGroupKey : match . resource ?. resourceGroupKey ,
590+ } ) )
591+ ) ,
565592 } ,
566593 ] ,
567594 } )
0 commit comments