@@ -14,6 +14,7 @@ import {
1414 ChipSwitch ,
1515 toast ,
1616} from '@sim/emcn'
17+ import { Plus } from '@sim/emcn/icons'
1718import { getErrorMessage } from '@sim/utils/errors'
1819import { useRouter } from 'next/navigation'
1920import type { SearchIntegrationApproval } from '@/lib/api/contracts/knowledge/search-integrations'
@@ -25,6 +26,7 @@ import {
2526 type LiveSearchPolicy ,
2627 normalizeLiveSearchPolicy ,
2728} from '@/lib/sim-search/live/policy-schema'
29+ import { searchSetupParam , serializeSearchSetup } from '@/lib/sim-search/search-params'
2830import { SearchSourcePagination } from '@/app/o/[organizationId]/settings/components/integrations/search-source-pagination'
2931import { useSearchSources } from '@/hooks/queries/kb/connectors'
3032import { useUpdateSearchIntegration } from '@/hooks/queries/search-integrations'
@@ -59,7 +61,7 @@ export function LiveSearchPolicyModal({
5961 const close = ( ) => {
6062 if ( ! update . isPending ) onClose ( )
6163 }
62- const save = ( ) => {
64+ const save = ( openSetup = needsServiceSetup ) => {
6365 if ( update . isPending ) return
6466 try {
6567 const policy = normalizeLiveSearchPolicy ( provider , {
@@ -78,8 +80,13 @@ export function LiveSearchPolicyModal({
7880 {
7981 onSuccess : ( ) => {
8082 onClose ( )
81- if ( needsServiceSetup )
82- router . push ( organizationRoutes ( organizationId ) . searchProvider ( provider ) )
83+ if ( openSetup )
84+ router . push (
85+ serializeSearchSetup ( organizationRoutes ( organizationId ) . searchProvider ( provider ) , {
86+ addConnector : searchSetupParam . parser . parse ( provider ) ,
87+ 'source-access' : null ,
88+ } )
89+ )
8390 else toast . success ( 'Search settings saved' )
8491 } ,
8592 }
@@ -161,6 +168,8 @@ export function LiveSearchPolicyModal({
161168 sourceId = { sourceId }
162169 onChange = { setSourceId }
163170 canManage = { integration . approved }
171+ onAdd = { ( ) => save ( true ) }
172+ disabled = { update . isPending }
164173 />
165174 ) ) }
166175 < ChipModalError > { error || update . error ?. message } </ ChipModalError >
@@ -173,12 +182,12 @@ export function LiveSearchPolicyModal({
173182 ? 'Saving…'
174183 : needsServiceSetup
175184 ? provider === 'github'
176- ? 'Save and add repositories '
185+ ? 'Add repository '
177186 : provider === 'gitlab'
178- ? 'Save and add projects '
179- : 'Save and add connection'
187+ ? 'Add project '
188+ : 'Add connection'
180189 : 'Save settings' ,
181- onClick : save ,
190+ onClick : ( ) => save ( ) ,
182191 disabled : update . isPending ,
183192 } }
184193 />
@@ -192,6 +201,8 @@ interface ServiceAccountSourceProps {
192201 sourceId : string
193202 onChange : ( sourceId : string ) => void
194203 canManage : boolean
204+ onAdd : ( ) => void
205+ disabled : boolean
195206}
196207
197208function ServiceAccountSource ( {
@@ -200,6 +211,8 @@ function ServiceAccountSource({
200211 sourceId,
201212 onChange,
202213 canManage,
214+ onAdd,
215+ disabled,
203216} : ServiceAccountSourceProps ) {
204217 const sources = useSearchSources (
205218 { kind : 'organization' , organizationId } ,
@@ -212,28 +225,36 @@ function ServiceAccountSource({
212225 label : `${ source . sourceDescription || connectorDisplayName ( provider ) } ${ source . enabled ? '' : ' · Paused' } ` ,
213226 disabled : ! source . enabled || source . availability !== 'available' ,
214227 } ) )
228+ if (
229+ ! sourceId &&
230+ ! sources . isPending &&
231+ ! sources . isError &&
232+ ! options . length &&
233+ ! sources . hasNextPage
234+ )
235+ return null
215236 return (
216- < ChipModalField
217- type = 'custom'
218- title = 'Service account connection'
219- hint = { ! sourceId && canManage ? 'Select a connection before search can run.' : undefined }
220- >
237+ < ChipModalField type = 'custom' title = 'Service account connection' >
221238 < div className = 'flex flex-col items-start gap-2' >
222- < ChipSelect
223- aria-label = 'Service account connection'
224- options = { options }
225- value = { sourceId }
226- onChange = { onChange }
227- placeholder = { sources . isPending ? 'Loading connections…' : 'Select a connection' }
228- displayLabel = {
229- sourceId && ! options . some ( ( option ) => option . value === sourceId )
230- ? 'Configured connection'
231- : undefined
232- }
233- disabled = { sources . isPending || sources . isError }
234- searchable
235- fullWidth
236- />
239+ { ( sourceId || options . length > 0 || sources . isPending ) && (
240+ < ChipSelect
241+ aria-label = 'Service account connection'
242+ options = { options }
243+ value = { sourceId }
244+ onChange = { onChange }
245+ placeholder = { sources . isPending ? 'Loading connections…' : 'Select a connection' }
246+ displayLabel = {
247+ sourceId && ! options . some ( ( option ) => option . value === sourceId )
248+ ? 'Configured connection'
249+ : undefined
250+ }
251+ disabled = { disabled || sources . isPending || sources . isError || ! options . length }
252+ searchable
253+ fullWidth
254+ dropdownWidth = 'trigger'
255+ align = 'start'
256+ />
257+ ) }
237258 { sources . isError && ! sources . isFetchNextPageError && (
238259 < >
239260 < ChipModalError > { sources . error ?. message } </ ChipModalError >
@@ -243,17 +264,18 @@ function ServiceAccountSource({
243264 </ >
244265 ) }
245266 < SearchSourcePagination { ...sources } />
246- { canManage ? (
247- < ChipLink
248- href = {
249- sourceId
250- ? organizationRoutes ( organizationId ) . searchSource ( sourceId )
251- : organizationRoutes ( organizationId ) . searchProvider ( provider )
252- }
253- >
254- { sourceId ? 'Edit connection and resources' : 'Set up service account' }
255- </ ChipLink >
256- ) : null }
267+ { sourceId && (
268+ < div className = 'flex flex-wrap gap-2' >
269+ { canManage && (
270+ < ChipLink href = { organizationRoutes ( organizationId ) . searchSource ( sourceId ) } >
271+ Edit connection
272+ </ ChipLink >
273+ ) }
274+ < Chip leftIcon = { Plus } disabled = { disabled } onClick = { onAdd } >
275+ Add connection
276+ </ Chip >
277+ </ div >
278+ ) }
257279 </ div >
258280 </ ChipModalField >
259281 )
0 commit comments