Skip to content

Commit 8906439

Browse files
fix(notifications): credentials connection notifs showing up in right resource (#3599)
* fix(notifications): credentials connection notifs showing up in right resource * fix new label * address comments * reset ref correctly:
1 parent ad68dc1 commit 8906439

File tree

9 files changed

+315
-86
lines changed

9 files changed

+315
-86
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {
7272
useUpdateKnowledgeBase,
7373
} from '@/hooks/queries/kb/knowledge'
7474
import { useInlineRename } from '@/hooks/use-inline-rename'
75+
import { useOAuthReturnForKBConnectors } from '@/hooks/use-oauth-return'
7576

7677
const logger = createLogger('KnowledgeBase')
7778

@@ -189,6 +190,7 @@ export function KnowledgeBase({
189190
}: KnowledgeBaseProps) {
190191
const params = useParams()
191192
const workspaceId = propWorkspaceId || (params.workspaceId as string)
193+
useOAuthReturnForKBConnectors(id)
192194
const { removeKnowledgeBase } = useKnowledgeBasesList(workspaceId, { enabled: false })
193195
const userPermissions = useUserPermissionsContext()
194196

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
Tooltip,
2121
} from '@/components/emcn'
2222
import { useSession } from '@/lib/auth/auth-client'
23+
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
2324
import {
2425
getCanonicalScopesForProvider,
2526
getProviderIdFromServiceId,
@@ -288,8 +289,25 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
288289
return
289290
}
290291

292+
writeOAuthReturnContext({
293+
origin: 'kb-connectors',
294+
knowledgeBaseId,
295+
displayName,
296+
providerId: connectorProviderId,
297+
preCount: credentials.length,
298+
workspaceId,
299+
requestedAt: Date.now(),
300+
})
301+
291302
setShowOAuthModal(true)
292-
}, [connectorConfig, connectorProviderId, workspaceId, session?.user?.name])
303+
}, [
304+
connectorConfig,
305+
connectorProviderId,
306+
workspaceId,
307+
session?.user?.name,
308+
knowledgeBaseId,
309+
credentials.length,
310+
])
293311

294312
const filteredEntries = useMemo(() => {
295313
const term = searchTerm.toLowerCase().trim()
@@ -575,11 +593,14 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
575593
{connectorConfig && connectorConfig.auth.mode === 'oauth' && connectorProviderId && (
576594
<OAuthRequiredModal
577595
isOpen={showOAuthModal}
578-
onClose={() => setShowOAuthModal(false)}
596+
onClose={() => {
597+
consumeOAuthReturnContext()
598+
setShowOAuthModal(false)
599+
}}
579600
provider={connectorProviderId}
580601
toolName={connectorConfig.name}
581602
requiredScopes={getCanonicalScopesForProvider(connectorProviderId)}
582-
newScopes={connectorConfig.auth.requiredScopes || []}
603+
newScopes={[]}
583604
serviceId={connectorConfig.auth.provider}
584605
/>
585606
)}

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connectors-section.tsx

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
Tooltip,
2828
} from '@/components/emcn'
2929
import { cn } from '@/lib/core/utils/cn'
30+
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
3031
import {
3132
getCanonicalScopesForProvider,
3233
getProviderIdFromServiceId,
@@ -444,7 +445,18 @@ function ConnectorCard({
444445
{canEdit && (
445446
<Button
446447
variant='active'
447-
onClick={() => setShowOAuthModal(true)}
448+
onClick={() => {
449+
writeOAuthReturnContext({
450+
origin: 'kb-connectors',
451+
knowledgeBaseId,
452+
displayName: connectorDef?.name ?? connector.connectorType,
453+
providerId: providerId!,
454+
preCount: credentials?.length ?? 0,
455+
workspaceId,
456+
requestedAt: Date.now(),
457+
})
458+
setShowOAuthModal(true)
459+
}}
448460
className='w-full px-[8px] py-[4px] font-medium text-[12px]'
449461
>
450462
Update access
@@ -463,7 +475,10 @@ function ConnectorCard({
463475
{showOAuthModal && serviceId && providerId && (
464476
<OAuthRequiredModal
465477
isOpen={showOAuthModal}
466-
onClose={() => setShowOAuthModal(false)}
478+
onClose={() => {
479+
consumeOAuthReturnContext()
480+
setShowOAuthModal(false)
481+
}}
467482
provider={providerId as OAuthProvider}
468483
toolName={connectorDef?.name ?? connector.connectorType}
469484
requiredScopes={getCanonicalScopesForProvider(providerId)}

apps/sim/app/workspace/[workspaceId]/layout.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import { ToastProvider } from '@/components/emcn'
34
import { GlobalCommandsProvider } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
45
import { ProviderModelsLoader } from '@/app/workspace/[workspaceId]/providers/provider-models-loader'
56
import { SettingsLoader } from '@/app/workspace/[workspaceId]/providers/settings-loader'
@@ -8,7 +9,7 @@ import { Sidebar } from '@/app/workspace/[workspaceId]/w/components/sidebar/side
89

910
export default function WorkspaceLayout({ children }: { children: React.ReactNode }) {
1011
return (
11-
<>
12+
<ToastProvider>
1213
<SettingsLoader />
1314
<ProviderModelsLoader />
1415
<GlobalCommandsProvider>
@@ -25,6 +26,6 @@ export default function WorkspaceLayout({ children }: { children: React.ReactNod
2526
</WorkspacePermissionsProvider>
2627
</div>
2728
</GlobalCommandsProvider>
28-
</>
29+
</ToastProvider>
2930
)
3031
}

apps/sim/app/workspace/[workspaceId]/settings/components/integrations/integrations-manager.tsx

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { createElement, useCallback, useEffect, useMemo, useState } from 'react'
3+
import { createElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
44
import { createLogger } from '@sim/logger'
55
import { AlertTriangle, Check, Clipboard, Plus, Search, Share2 } from 'lucide-react'
66
import { useParams } from 'next/navigation'
@@ -28,6 +28,7 @@ import {
2828
PENDING_CREDENTIAL_CREATE_REQUEST_EVENT,
2929
type PendingCredentialCreateRequest,
3030
readPendingCredentialCreateRequest,
31+
writeOAuthReturnContext,
3132
} from '@/lib/credentials/client-state'
3233
import {
3334
getCanonicalScopesForProvider,
@@ -54,6 +55,7 @@ import {
5455
useOAuthConnections,
5556
} from '@/hooks/queries/oauth/oauth-connections'
5657
import { useWorkspacePermissionsQuery } from '@/hooks/queries/workspace'
58+
import { useOAuthReturnRouter } from '@/hooks/use-oauth-return'
5759

5860
const logger = createLogger('IntegrationsManager')
5961

@@ -66,6 +68,8 @@ export function IntegrationsManager() {
6668
const params = useParams()
6769
const workspaceId = (params?.workspaceId as string) || ''
6870

71+
useOAuthReturnRouter()
72+
6973
const [searchTerm, setSearchTerm] = useState('')
7074
const [selectedCredentialId, setSelectedCredentialId] = useState<string | null>(null)
7175
const [memberRole, setMemberRole] = useState<WorkspaceCredentialRole>('admin')
@@ -84,6 +88,11 @@ export function IntegrationsManager() {
8488
const [showDeleteConfirmDialog, setShowDeleteConfirmDialog] = useState(false)
8589
const [deleteError, setDeleteError] = useState<string | null>(null)
8690
const [showUnsavedChangesAlert, setShowUnsavedChangesAlert] = useState(false)
91+
const pendingReturnOriginRef = useRef<
92+
| { type: 'workflow'; workflowId: string }
93+
| { type: 'kb-connectors'; knowledgeBaseId: string }
94+
| undefined
95+
>(undefined)
8796
const { data: session } = useSession()
8897
const currentUserId = session?.user?.id || ''
8998

@@ -278,6 +287,8 @@ export function IntegrationsManager() {
278287

279288
if (request.type !== 'oauth') return
280289

290+
pendingReturnOriginRef.current = request.returnOrigin
291+
281292
setShowCreateModal(true)
282293
setShowCreateOAuthRequiredModal(false)
283294
setCreateError(null)
@@ -350,6 +361,7 @@ export function IntegrationsManager() {
350361
setCreateOAuthProviderId('')
351362
setCreateError(null)
352363
setShowCreateOAuthRequiredModal(false)
364+
pendingReturnOriginRef.current = undefined
353365
}
354366

355367
const handleSelectCredential = (credential: WorkspaceCredential) => {
@@ -397,15 +409,42 @@ export function IntegrationsManager() {
397409
}),
398410
})
399411

400-
window.sessionStorage.setItem(
401-
'sim.oauth-connect-pending',
402-
JSON.stringify({
412+
const oauthPreCount = credentials.filter(
413+
(c) => c.type === 'oauth' && c.providerId === selectedOAuthService.providerId
414+
).length
415+
const returnOrigin = pendingReturnOriginRef.current
416+
pendingReturnOriginRef.current = undefined
417+
418+
if (returnOrigin?.type === 'workflow') {
419+
writeOAuthReturnContext({
420+
origin: 'workflow',
421+
workflowId: returnOrigin.workflowId,
403422
displayName,
404423
providerId: selectedOAuthService.providerId,
405-
preCount: credentials.filter((c) => c.type === 'oauth').length,
424+
preCount: oauthPreCount,
406425
workspaceId,
426+
requestedAt: Date.now(),
407427
})
408-
)
428+
} else if (returnOrigin?.type === 'kb-connectors') {
429+
writeOAuthReturnContext({
430+
origin: 'kb-connectors',
431+
knowledgeBaseId: returnOrigin.knowledgeBaseId,
432+
displayName,
433+
providerId: selectedOAuthService.providerId,
434+
preCount: oauthPreCount,
435+
workspaceId,
436+
requestedAt: Date.now(),
437+
})
438+
} else {
439+
writeOAuthReturnContext({
440+
origin: 'integrations',
441+
displayName,
442+
providerId: selectedOAuthService.providerId,
443+
preCount: oauthPreCount,
444+
workspaceId,
445+
requestedAt: Date.now(),
446+
})
447+
}
409448

410449
await connectOAuthService.mutateAsync({
411450
providerId: selectedOAuthService.providerId,
@@ -512,16 +551,18 @@ export function IntegrationsManager() {
512551
}),
513552
})
514553

515-
window.sessionStorage.setItem(
516-
'sim.oauth-connect-pending',
517-
JSON.stringify({
518-
displayName: selectedCredential.displayName,
519-
providerId: selectedCredential.providerId,
520-
preCount: credentials.filter((c) => c.type === 'oauth').length,
521-
workspaceId,
522-
reconnect: true,
523-
})
524-
)
554+
const oauthPreCount = credentials.filter(
555+
(c) => c.type === 'oauth' && c.providerId === selectedCredential.providerId
556+
).length
557+
writeOAuthReturnContext({
558+
origin: 'integrations',
559+
displayName: selectedCredential.displayName,
560+
providerId: selectedCredential.providerId,
561+
preCount: oauthPreCount,
562+
workspaceId,
563+
reconnect: true,
564+
requestedAt: Date.now(),
565+
})
525566

526567
await connectOAuthService.mutateAsync({
527568
providerId: selectedCredential.providerId,

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,13 @@ export function CredentialSelector({
207207
serviceId,
208208
requiredScopes: getCanonicalScopesForProvider(effectiveProviderId),
209209
requestedAt: Date.now(),
210+
returnOrigin: activeWorkflowId
211+
? { type: 'workflow', workflowId: activeWorkflowId }
212+
: undefined,
210213
})
211214

212215
navigateToSettings({ section: 'integrations' })
213-
}, [workspaceId, effectiveProviderId, serviceId])
216+
}, [workspaceId, effectiveProviderId, serviceId, activeWorkflowId])
214217

215218
const getProviderIcon = useCallback((providerName: OAuthProvider) => {
216219
const { baseProvider } = parseProvider(providerName)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ import { useWorkspaceEnvironment } from '@/hooks/queries/environment'
7373
import { useAutoConnect, useSnapToGridSize } from '@/hooks/queries/general-settings'
7474
import { useCanvasViewport } from '@/hooks/use-canvas-viewport'
7575
import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow'
76+
import { useOAuthReturnForWorkflow } from '@/hooks/use-oauth-return'
7677
import { useStreamCleanup } from '@/hooks/use-stream-cleanup'
7778
import { useCanvasModeStore } from '@/stores/canvas-mode'
7879
import { useChatStore } from '@/stores/chat/store'
@@ -268,68 +269,7 @@ const WorkflowContent = React.memo(
268269

269270
const addNotification = useNotificationStore((state) => state.addNotification)
270271

271-
useEffect(() => {
272-
const OAUTH_CONNECT_PENDING_KEY = 'sim.oauth-connect-pending'
273-
const pending = window.sessionStorage.getItem(OAUTH_CONNECT_PENDING_KEY)
274-
if (!pending) return
275-
window.sessionStorage.removeItem(OAUTH_CONNECT_PENDING_KEY)
276-
277-
;(async () => {
278-
try {
279-
const {
280-
displayName,
281-
providerId,
282-
preCount,
283-
workspaceId: wsId,
284-
reconnect,
285-
} = JSON.parse(pending) as {
286-
displayName: string
287-
providerId: string
288-
preCount: number
289-
workspaceId: string
290-
reconnect?: boolean
291-
}
292-
293-
if (reconnect) {
294-
addNotification({
295-
level: 'info',
296-
message: `"${displayName}" reconnected successfully.`,
297-
})
298-
window.dispatchEvent(
299-
new CustomEvent('oauth-credentials-updated', {
300-
detail: { providerId, workspaceId: wsId },
301-
})
302-
)
303-
return
304-
}
305-
306-
const response = await fetch(
307-
`/api/credentials?workspaceId=${encodeURIComponent(wsId)}&type=oauth`
308-
)
309-
const data = response.ok ? await response.json() : { credentials: [] }
310-
const oauthCredentials = (data.credentials ?? []) as Array<{
311-
displayName: string
312-
providerId: string | null
313-
}>
314-
315-
if (oauthCredentials.length > preCount) {
316-
addNotification({
317-
level: 'info',
318-
message: `"${displayName}" credential connected successfully.`,
319-
})
320-
} else {
321-
const existing = oauthCredentials.find((c) => c.providerId === providerId)
322-
const existingName = existing?.displayName || displayName
323-
addNotification({
324-
level: 'info',
325-
message: `This account is already connected as "${existingName}".`,
326-
})
327-
}
328-
} catch {
329-
// Ignore malformed sessionStorage data
330-
}
331-
})()
332-
}, [])
272+
useOAuthReturnForWorkflow(workflowIdParam)
333273

334274
const {
335275
workflows,

0 commit comments

Comments
 (0)