Skip to content

Commit 8ce0299

Browse files
TheodoreSpeaksTheodore Li
andauthored
fix(ui) Fix oauth redirect on connector modal (#3926)
* Fix oauth redirect on connector modal * Fix lint --------- Co-authored-by: Theodore Li <theo@sim.ai>
1 parent a0796f0 commit 8ce0299

File tree

5 files changed

+72
-15
lines changed

5 files changed

+72
-15
lines changed

apps/sim/app/workspace/[workspaceId]/components/oauth-modal.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
} from '@/components/emcn'
1717
import { client, useSession } from '@/lib/auth/auth-client'
1818
import type { OAuthReturnContext } from '@/lib/credentials/client-state'
19-
import { writeOAuthReturnContext } from '@/lib/credentials/client-state'
19+
import { ADD_CONNECTOR_SEARCH_PARAM, writeOAuthReturnContext } from '@/lib/credentials/client-state'
2020
import {
2121
getCanonicalScopesForProvider,
2222
getProviderIdFromServiceId,
@@ -59,8 +59,8 @@ type OAuthModalConnectProps = OAuthModalBaseProps & {
5959
workspaceId: string
6060
credentialCount: number
6161
} & (
62-
| { workflowId: string; knowledgeBaseId?: never }
63-
| { workflowId?: never; knowledgeBaseId: string }
62+
| { workflowId: string; knowledgeBaseId?: never; connectorType?: never }
63+
| { workflowId?: never; knowledgeBaseId: string; connectorType?: string }
6464
)
6565

6666
interface OAuthModalReauthorizeProps extends OAuthModalBaseProps {
@@ -81,6 +81,7 @@ export function OAuthModal(props: OAuthModalProps) {
8181
const workspaceId = isConnect ? props.workspaceId : ''
8282
const workflowId = isConnect ? props.workflowId : undefined
8383
const knowledgeBaseId = isConnect ? props.knowledgeBaseId : undefined
84+
const connectorType = isConnect ? props.connectorType : undefined
8485
const toolName = !isConnect ? props.toolName : ''
8586
const requiredScopes = !isConnect ? (props.requiredScopes ?? EMPTY_SCOPES) : EMPTY_SCOPES
8687
const newScopes = !isConnect ? (props.newScopes ?? EMPTY_SCOPES) : EMPTY_SCOPES
@@ -172,7 +173,7 @@ export function OAuthModal(props: OAuthModalProps) {
172173
}
173174

174175
const returnContext: OAuthReturnContext = knowledgeBaseId
175-
? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId }
176+
? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId, connectorType }
176177
: { ...baseContext, origin: 'workflow' as const, workflowId: workflowId! }
177178

178179
writeOAuthReturnContext(returnContext)
@@ -205,7 +206,11 @@ export function OAuthModal(props: OAuthModalProps) {
205206
return
206207
}
207208

208-
await client.oauth2.link({ providerId, callbackURL: window.location.href })
209+
const callbackURL = new URL(window.location.href)
210+
if (connectorType) {
211+
callbackURL.searchParams.set(ADD_CONNECTOR_SEARCH_PARAM, connectorType)
212+
}
213+
await client.oauth2.link({ providerId, callbackURL: callbackURL.toString() })
209214
handleClose()
210215
} catch (err) {
211216
logger.error('Failed to initiate OAuth connection', { error: err })

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { format } from 'date-fns'
66
import { AlertCircle, Loader2, Pencil, Plus, Tag, X } from 'lucide-react'
7-
import { useParams, useRouter } from 'next/navigation'
7+
import { useParams, usePathname, useRouter, useSearchParams } from 'next/navigation'
88
import { usePostHog } from 'posthog-js/react'
99
import {
1010
Badge,
@@ -25,6 +25,7 @@ import {
2525
import { Database, DatabaseX } from '@/components/emcn/icons'
2626
import { SearchHighlight } from '@/components/ui/search-highlight'
2727
import { cn } from '@/lib/core/utils/cn'
28+
import { ADD_CONNECTOR_SEARCH_PARAM } from '@/lib/credentials/client-state'
2829
import { ALL_TAG_SLOTS, type AllTagSlot, getFieldTypeForSlot } from '@/lib/knowledge/constants'
2930
import type { DocumentSortField, SortOrder } from '@/lib/knowledge/documents/types'
3031
import { type FilterFieldType, getOperatorsForFieldType } from '@/lib/knowledge/filters/types'
@@ -192,6 +193,10 @@ export function KnowledgeBase({
192193
}: KnowledgeBaseProps) {
193194
const params = useParams()
194195
const workspaceId = propWorkspaceId || (params.workspaceId as string)
196+
const router = useRouter()
197+
const searchParams = useSearchParams()
198+
const pathname = usePathname()
199+
const addConnectorParam = searchParams.get(ADD_CONNECTOR_SEARCH_PARAM)
195200
const posthog = usePostHog()
196201

197202
useEffect(() => {
@@ -278,7 +283,29 @@ export function KnowledgeBase({
278283
const [contextMenuDocument, setContextMenuDocument] = useState<DocumentData | null>(null)
279284
const [showRenameModal, setShowRenameModal] = useState(false)
280285
const [documentToRename, setDocumentToRename] = useState<DocumentData | null>(null)
281-
const [showAddConnectorModal, setShowAddConnectorModal] = useState(false)
286+
const showAddConnectorModal = addConnectorParam != null
287+
const searchParamsRef = useRef(searchParams)
288+
searchParamsRef.current = searchParams
289+
const updateAddConnectorParam = useCallback(
290+
(value: string | null) => {
291+
const current = searchParamsRef.current
292+
const currentValue = current.get(ADD_CONNECTOR_SEARCH_PARAM)
293+
if (value === currentValue || (value === null && currentValue === null)) return
294+
const next = new URLSearchParams(current.toString())
295+
if (value === null) {
296+
next.delete(ADD_CONNECTOR_SEARCH_PARAM)
297+
} else {
298+
next.set(ADD_CONNECTOR_SEARCH_PARAM, value)
299+
}
300+
const qs = next.toString()
301+
router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false })
302+
},
303+
[pathname, router]
304+
)
305+
const setShowAddConnectorModal = useCallback(
306+
(open: boolean) => updateAddConnectorParam(open ? '' : null),
307+
[updateAddConnectorParam]
308+
)
282309

283310
const {
284311
isOpen: isContextMenuOpen,
@@ -340,8 +367,6 @@ export function KnowledgeBase({
340367
prevHadSyncingRef.current = hasSyncingConnectors
341368
}, [hasSyncingConnectors, refreshKnowledgeBase, refreshDocuments])
342369

343-
const router = useRouter()
344-
345370
const knowledgeBaseName = knowledgeBase?.name || passedKnowledgeBaseName || 'Knowledge Base'
346371
const error = knowledgeBaseError || documentsError
347372

@@ -1254,7 +1279,13 @@ export function KnowledgeBase({
12541279
/>
12551280

12561281
{showAddConnectorModal && (
1257-
<AddConnectorModal open onOpenChange={setShowAddConnectorModal} knowledgeBaseId={id} />
1282+
<AddConnectorModal
1283+
open
1284+
onOpenChange={setShowAddConnectorModal}
1285+
onConnectorTypeChange={updateAddConnectorParam}
1286+
knowledgeBaseId={id}
1287+
initialConnectorType={addConnectorParam || undefined}
1288+
/>
12581289
)}
12591290

12601291
{documentToRename && (

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,22 @@ const CONNECTOR_ENTRIES = Object.entries(CONNECTOR_REGISTRY)
4444
interface AddConnectorModalProps {
4545
open: boolean
4646
onOpenChange: (open: boolean) => void
47+
onConnectorTypeChange?: (connectorType: string | null) => void
4748
knowledgeBaseId: string
49+
initialConnectorType?: string | null
4850
}
4951

5052
type Step = 'select-type' | 'configure'
5153

52-
export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddConnectorModalProps) {
53-
const [step, setStep] = useState<Step>('select-type')
54-
const [selectedType, setSelectedType] = useState<string | null>(null)
54+
export function AddConnectorModal({
55+
open,
56+
onOpenChange,
57+
onConnectorTypeChange,
58+
knowledgeBaseId,
59+
initialConnectorType,
60+
}: AddConnectorModalProps) {
61+
const [step, setStep] = useState<Step>(() => (initialConnectorType ? 'configure' : 'select-type'))
62+
const [selectedType, setSelectedType] = useState<string | null>(initialConnectorType ?? null)
5563
const [sourceConfig, setSourceConfig] = useState<Record<string, string>>({})
5664
const [syncInterval, setSyncInterval] = useState(1440)
5765
const [selectedCredentialId, setSelectedCredentialId] = useState<string | null>(null)
@@ -151,6 +159,7 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
151159
setError(null)
152160
setSearchTerm('')
153161
setStep('configure')
162+
onConnectorTypeChange?.(type)
154163
}
155164

156165
const handleFieldChange = useCallback(
@@ -286,7 +295,10 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
286295
<Button
287296
variant='ghost'
288297
className='mr-2 h-6 w-6 p-0'
289-
onClick={() => setStep('select-type')}
298+
onClick={() => {
299+
setStep('select-type')
300+
onConnectorTypeChange?.('')
301+
}}
290302
>
291303
<ArrowLeft className='h-4 w-4' />
292304
</Button>
@@ -565,6 +577,7 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
565577
workspaceId={workspaceId}
566578
knowledgeBaseId={knowledgeBaseId}
567579
credentialCount={credentials.length}
580+
connectorType={selectedType ?? undefined}
568581
/>
569582
)}
570583
</>

apps/sim/hooks/use-oauth-return.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useEffect, useRef } from 'react'
44
import { useParams, useRouter } from 'next/navigation'
55
import { toast } from '@/components/emcn'
66
import {
7+
ADD_CONNECTOR_SEARCH_PARAM,
78
consumeOAuthReturnContext,
89
type OAuthReturnContext,
910
readOAuthReturnContext,
@@ -98,7 +99,11 @@ export function useOAuthReturnRouter() {
9899
try {
99100
sessionStorage.removeItem(SETTINGS_RETURN_URL_KEY)
100101
} catch {}
101-
router.replace(`/workspace/${workspaceId}/knowledge/${ctx.knowledgeBaseId}`)
102+
const kbUrl = `/workspace/${workspaceId}/knowledge/${ctx.knowledgeBaseId}`
103+
const connectorParam = ctx.connectorType
104+
? `?${ADD_CONNECTOR_SEARCH_PARAM}=${encodeURIComponent(ctx.connectorType)}`
105+
: ''
106+
router.replace(`${kbUrl}${connectorParam}`)
102107
return
103108
}
104109
}, [router, workspaceId])

apps/sim/lib/credentials/client-state.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ export function clearPendingCredentialCreateRequest() {
9191
window.sessionStorage.removeItem(PENDING_CREDENTIAL_CREATE_REQUEST_KEY)
9292
}
9393

94+
export const ADD_CONNECTOR_SEARCH_PARAM = 'addConnector' as const
95+
9496
const OAUTH_RETURN_CONTEXT_KEY = 'sim.oauth-return-context'
9597

9698
export type OAuthReturnOrigin = 'workflow' | 'integrations' | 'kb-connectors'
@@ -116,6 +118,7 @@ interface OAuthReturnIntegrations extends OAuthReturnBase {
116118
interface OAuthReturnKBConnectors extends OAuthReturnBase {
117119
origin: 'kb-connectors'
118120
knowledgeBaseId: string
121+
connectorType?: string
119122
}
120123

121124
export type OAuthReturnContext =

0 commit comments

Comments
 (0)