Skip to content

Commit 991e2b8

Browse files
committed
fix(knowledge): fix document processing stuck in processing state
1 parent e9c94fa commit 991e2b8

File tree

10 files changed

+171
-133
lines changed

10 files changed

+171
-133
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,11 @@ export function KnowledgeBase({
900900
onClick={() => setShowConnectorsModal(true)}
901901
className='flex shrink-0 cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-[var(--text-secondary)] text-caption shadow-[inset_0_0_0_1px_var(--border)] transition-colors hover-hover:bg-[var(--surface-3)]'
902902
>
903-
{ConnectorIcon && <ConnectorIcon className='h-[14px] w-[14px]' />}
903+
{connector.status === 'syncing' ? (
904+
<Loader2 className='h-[14px] w-[14px] animate-spin' />
905+
) : (
906+
ConnectorIcon && <ConnectorIcon className='h-[14px] w-[14px]' />
907+
)}
904908
{def?.name || connector.connectorType}
905909
</button>
906910
)

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

Lines changed: 49 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,10 @@ import {
1919
ModalHeader,
2020
Tooltip,
2121
} from '@/components/emcn'
22-
import { useSession } from '@/lib/auth/auth-client'
23-
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
24-
import {
25-
getCanonicalScopesForProvider,
26-
getProviderIdFromServiceId,
27-
type OAuthProvider,
28-
} from '@/lib/oauth'
22+
import { consumeOAuthReturnContext } from '@/lib/credentials/client-state'
23+
import { getProviderIdFromServiceId, type OAuthProvider } from '@/lib/oauth'
2924
import { ConnectorSelectorField } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/components/connector-selector-field'
30-
import { OAuthRequiredModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal'
25+
import { ConnectCredentialModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/connect-credential-modal'
3126
import { getDependsOnFields } from '@/blocks/utils'
3227
import { CONNECTOR_REGISTRY } from '@/connectors/registry'
3328
import type { ConnectorConfig, ConnectorConfigField } from '@/connectors/types'
@@ -69,7 +64,6 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
6964
const [searchTerm, setSearchTerm] = useState('')
7065

7166
const { workspaceId } = useParams<{ workspaceId: string }>()
72-
const { data: session } = useSession()
7367
const { mutate: createConnector, isPending: isCreating } = useCreateConnector()
7468

7569
const connectorConfig = selectedType ? CONNECTOR_REGISTRY[selectedType] : null
@@ -263,51 +257,9 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
263257
)
264258
}
265259

266-
const handleConnectNewAccount = useCallback(async () => {
267-
if (!connectorConfig || !connectorProviderId || !workspaceId) return
268-
269-
const userName = session?.user?.name
270-
const integrationName = connectorConfig.name
271-
const displayName = userName ? `${userName}'s ${integrationName}` : integrationName
272-
273-
try {
274-
const res = await fetch('/api/credentials/draft', {
275-
method: 'POST',
276-
headers: { 'Content-Type': 'application/json' },
277-
body: JSON.stringify({
278-
workspaceId,
279-
providerId: connectorProviderId,
280-
displayName,
281-
}),
282-
})
283-
if (!res.ok) {
284-
setError('Failed to prepare credential. Please try again.')
285-
return
286-
}
287-
} catch {
288-
setError('Failed to prepare credential. Please try again.')
289-
return
290-
}
291-
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-
260+
const handleConnectNewAccount = useCallback(() => {
302261
setShowOAuthModal(true)
303-
}, [
304-
connectorConfig,
305-
connectorProviderId,
306-
workspaceId,
307-
session?.user?.name,
308-
knowledgeBaseId,
309-
credentials.length,
310-
])
262+
}, [])
311263

312264
const filteredEntries = useMemo(() => {
313265
const term = searchTerm.toLowerCase().trim()
@@ -396,40 +348,34 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
396348
) : (
397349
<div className='flex flex-col gap-2'>
398350
<Label>Account</Label>
399-
{credentialsLoading ? (
400-
<div className='flex items-center gap-2 text-[var(--text-muted)] text-small'>
401-
<Loader2 className='h-4 w-4 animate-spin' />
402-
Loading credentials...
403-
</div>
404-
) : (
405-
<Combobox
406-
size='sm'
407-
options={[
408-
...credentials.map(
409-
(cred): ComboboxOption => ({
410-
label: cred.name || cred.provider,
411-
value: cred.id,
412-
icon: connectorConfig.icon,
413-
})
414-
),
415-
{
416-
label: 'Connect new account',
417-
value: '__connect_new__',
418-
icon: Plus,
419-
onSelect: () => {
420-
void handleConnectNewAccount()
421-
},
351+
<Combobox
352+
size='sm'
353+
options={[
354+
...credentials.map(
355+
(cred): ComboboxOption => ({
356+
label: cred.name || cred.provider,
357+
value: cred.id,
358+
icon: connectorConfig.icon,
359+
})
360+
),
361+
{
362+
label: 'Connect new account',
363+
value: '__connect_new__',
364+
icon: Plus,
365+
onSelect: () => {
366+
void handleConnectNewAccount()
422367
},
423-
]}
424-
value={effectiveCredentialId ?? undefined}
425-
onChange={(value) => setSelectedCredentialId(value)}
426-
placeholder={
427-
credentials.length === 0
428-
? `No ${connectorConfig.name} accounts`
429-
: 'Select account'
430-
}
431-
/>
432-
)}
368+
},
369+
]}
370+
value={effectiveCredentialId ?? undefined}
371+
onChange={(value) => setSelectedCredentialId(value)}
372+
placeholder={
373+
credentials.length === 0
374+
? `No ${connectorConfig.name} accounts`
375+
: 'Select account'
376+
}
377+
isLoading={credentialsLoading}
378+
/>
433379
</div>
434380
)}
435381

@@ -590,20 +536,23 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo
590536
)}
591537
</ModalContent>
592538
</Modal>
593-
{connectorConfig && connectorConfig.auth.mode === 'oauth' && connectorProviderId && (
594-
<OAuthRequiredModal
595-
isOpen={showOAuthModal}
596-
onClose={() => {
597-
consumeOAuthReturnContext()
598-
setShowOAuthModal(false)
599-
}}
600-
provider={connectorProviderId}
601-
toolName={connectorConfig.name}
602-
requiredScopes={getCanonicalScopesForProvider(connectorProviderId)}
603-
newScopes={[]}
604-
serviceId={connectorConfig.auth.provider}
605-
/>
606-
)}
539+
{showOAuthModal &&
540+
connectorConfig &&
541+
connectorConfig.auth.mode === 'oauth' &&
542+
connectorProviderId && (
543+
<ConnectCredentialModal
544+
isOpen={showOAuthModal}
545+
onClose={() => {
546+
consumeOAuthReturnContext()
547+
setShowOAuthModal(false)
548+
}}
549+
provider={connectorProviderId}
550+
serviceId={connectorConfig.auth.provider}
551+
workspaceId={workspaceId}
552+
knowledgeBaseId={knowledgeBaseId}
553+
credentialCount={credentials.length}
554+
/>
555+
)}
607556
</>
608557
)
609558
}

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

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {
3636
} from '@/lib/oauth'
3737
import { getMissingRequiredScopes } from '@/lib/oauth/utils'
3838
import { EditConnectorModal } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/edit-connector-modal'
39+
import { ConnectCredentialModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/connect-credential-modal'
3940
import { OAuthRequiredModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/components/oauth-required-modal'
4041
import { CONNECTOR_REGISTRY } from '@/connectors/registry'
4142
import type { ConnectorData, SyncLogData } from '@/hooks/queries/kb/connectors'
@@ -333,6 +334,7 @@ function ConnectorCard({
333334
const missingScopes = useMemo(() => {
334335
if (!credentials || !connector.credentialId) return []
335336
const credential = credentials.find((c) => c.id === connector.credentialId)
337+
if (!credential) return []
336338
return getMissingRequiredScopes(credential, requiredScopes)
337339
}, [credentials, connector.credentialId, requiredScopes])
338340

@@ -484,15 +486,17 @@ function ConnectorCard({
484486
<Button
485487
variant='active'
486488
onClick={() => {
487-
writeOAuthReturnContext({
488-
origin: 'kb-connectors',
489-
knowledgeBaseId,
490-
displayName: connectorDef?.name ?? connector.connectorType,
491-
providerId: providerId!,
492-
preCount: credentials?.length ?? 0,
493-
workspaceId,
494-
requestedAt: Date.now(),
495-
})
489+
if (connector.credentialId) {
490+
writeOAuthReturnContext({
491+
origin: 'kb-connectors',
492+
knowledgeBaseId,
493+
displayName: connectorDef?.name ?? connector.connectorType,
494+
providerId: providerId!,
495+
preCount: credentials?.length ?? 0,
496+
workspaceId,
497+
requestedAt: Date.now(),
498+
})
499+
}
496500
setShowOAuthModal(true)
497501
}}
498502
className='w-full px-2 py-1 font-medium text-caption'
@@ -510,7 +514,22 @@ function ConnectorCard({
510514
</div>
511515
)}
512516

513-
{showOAuthModal && serviceId && providerId && (
517+
{showOAuthModal && serviceId && providerId && !connector.credentialId && (
518+
<ConnectCredentialModal
519+
isOpen={showOAuthModal}
520+
onClose={() => {
521+
consumeOAuthReturnContext()
522+
setShowOAuthModal(false)
523+
}}
524+
provider={providerId as OAuthProvider}
525+
serviceId={serviceId}
526+
workspaceId={workspaceId}
527+
knowledgeBaseId={knowledgeBaseId}
528+
credentialCount={credentials?.length ?? 0}
529+
/>
530+
)}
531+
532+
{showOAuthModal && serviceId && providerId && connector.credentialId && (
514533
<OAuthRequiredModal
515534
isOpen={showOAuthModal}
516535
onClose={() => {

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
ModalHeader,
1515
} from '@/components/emcn'
1616
import { client } from '@/lib/auth/auth-client'
17+
import type { OAuthReturnContext } from '@/lib/credentials/client-state'
1718
import { writeOAuthReturnContext } from '@/lib/credentials/client-state'
1819
import {
1920
getCanonicalScopesForProvider,
@@ -27,24 +28,30 @@ import { useCreateCredentialDraft } from '@/hooks/queries/credentials'
2728

2829
const logger = createLogger('ConnectCredentialModal')
2930

30-
export interface ConnectCredentialModalProps {
31+
interface ConnectCredentialModalBaseProps {
3132
isOpen: boolean
3233
onClose: () => void
3334
provider: OAuthProvider
3435
serviceId: string
3536
workspaceId: string
36-
workflowId: string
3737
/** Number of existing credentials for this provider — used to detect a successful new connection. */
3838
credentialCount: number
3939
}
4040

41+
export type ConnectCredentialModalProps = ConnectCredentialModalBaseProps &
42+
(
43+
| { workflowId: string; knowledgeBaseId?: never }
44+
| { workflowId?: never; knowledgeBaseId: string }
45+
)
46+
4147
export function ConnectCredentialModal({
4248
isOpen,
4349
onClose,
4450
provider,
4551
serviceId,
4652
workspaceId,
4753
workflowId,
54+
knowledgeBaseId,
4855
credentialCount,
4956
}: ConnectCredentialModalProps) {
5057
const [displayName, setDisplayName] = useState('')
@@ -97,15 +104,19 @@ export function ConnectCredentialModal({
97104
try {
98105
await createDraft.mutateAsync({ workspaceId, providerId, displayName: trimmedName })
99106

100-
writeOAuthReturnContext({
101-
origin: 'workflow',
102-
workflowId,
107+
const baseContext = {
103108
displayName: trimmedName,
104109
providerId,
105110
preCount: credentialCount,
106111
workspaceId,
107112
requestedAt: Date.now(),
108-
})
113+
}
114+
115+
const returnContext: OAuthReturnContext = knowledgeBaseId
116+
? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId }
117+
: { ...baseContext, origin: 'workflow' as const, workflowId: workflowId! }
118+
119+
writeOAuthReturnContext(returnContext)
109120

110121
if (providerId === 'trello') {
111122
window.location.href = '/api/auth/trello/authorize'

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Button, Combobox } from '@/components/emcn/components'
77
import { getSubscriptionAccessState } from '@/lib/billing/client'
88
import { getEnv, isTruthy } from '@/lib/core/config/env'
99
import { getPollingProviderFromOAuth } from '@/lib/credential-sets/providers'
10+
import { consumeOAuthReturnContext, writeOAuthReturnContext } from '@/lib/credentials/client-state'
1011
import {
1112
getCanonicalScopesForProvider,
1213
getProviderIdFromServiceId,
@@ -357,7 +358,18 @@ export function CredentialSelector({
357358
</div>
358359
<Button
359360
variant='active'
360-
onClick={() => setShowOAuthModal(true)}
361+
onClick={() => {
362+
writeOAuthReturnContext({
363+
origin: 'workflow',
364+
workflowId: activeWorkflowId || '',
365+
displayName: selectedCredential?.name ?? getProviderName(provider),
366+
providerId: effectiveProviderId,
367+
preCount: credentials.length,
368+
workspaceId,
369+
requestedAt: Date.now(),
370+
})
371+
setShowOAuthModal(true)
372+
}}
361373
className='w-full px-2 py-1 font-medium text-caption'
362374
>
363375
Update access
@@ -380,7 +392,10 @@ export function CredentialSelector({
380392
{showOAuthModal && (
381393
<OAuthRequiredModal
382394
isOpen={showOAuthModal}
383-
onClose={() => setShowOAuthModal(false)}
395+
onClose={() => {
396+
consumeOAuthReturnContext()
397+
setShowOAuthModal(false)
398+
}}
384399
provider={provider}
385400
toolName={getProviderName(provider)}
386401
requiredScopes={getCanonicalScopesForProvider(effectiveProviderId)}

0 commit comments

Comments
 (0)