Skip to content

Commit 6ca206f

Browse files
committed
fix(knowledge): scope sync/update state per-connector to prevent race conditions
1 parent fb233d0 commit 6ca206f

File tree

1 file changed

+28
-14
lines changed

1 file changed

+28
-14
lines changed

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

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,14 @@ export function ConnectorsSection({
7373
isLoading,
7474
canEdit,
7575
}: ConnectorsSectionProps) {
76-
const { mutate: triggerSync, isPending: isSyncing } = useTriggerSync()
77-
const { mutate: updateConnector, isPending: isUpdating } = useUpdateConnector()
76+
const { mutate: triggerSync } = useTriggerSync()
77+
const { mutate: updateConnector } = useUpdateConnector()
7878
const { mutate: deleteConnector, isPending: isDeleting } = useDeleteConnector()
7979
const [deleteTarget, setDeleteTarget] = useState<string | null>(null)
8080
const [editingConnector, setEditingConnector] = useState<ConnectorData | null>(null)
8181
const [error, setError] = useState<string | null>(null)
82-
const [syncingConnectorId, setSyncingConnectorId] = useState<string | null>(null)
82+
const [syncingIds, setSyncingIds] = useState<Set<string>>(() => new Set())
83+
const [updatingIds, setUpdatingIds] = useState<Set<string>>(() => new Set())
8384

8485
const syncTriggeredAt = useRef<Record<string, number>>({})
8586
const cooldownTimers = useRef<Set<ReturnType<typeof setTimeout>>>(new Set())
@@ -104,14 +105,18 @@ export function ConnectorsSection({
104105
if (isSyncOnCooldown(connectorId)) return
105106

106107
syncTriggeredAt.current[connectorId] = Date.now()
107-
setSyncingConnectorId(connectorId)
108+
setSyncingIds((prev) => new Set(prev).add(connectorId))
108109

109110
triggerSync(
110111
{ knowledgeBaseId, connectorId },
111112
{
112113
onSuccess: () => {
113114
setError(null)
114-
setSyncingConnectorId(null)
115+
setSyncingIds((prev) => {
116+
const next = new Set(prev)
117+
next.delete(connectorId)
118+
return next
119+
})
115120
const timer = setTimeout(() => {
116121
cooldownTimers.current.delete(timer)
117122
forceUpdate((n) => n + 1)
@@ -121,7 +126,11 @@ export function ConnectorsSection({
121126
onError: (err) => {
122127
logger.error('Sync trigger failed', { error: err.message })
123128
setError(err.message)
124-
setSyncingConnectorId(null)
129+
setSyncingIds((prev) => {
130+
const next = new Set(prev)
131+
next.delete(connectorId)
132+
return next
133+
})
125134
delete syncTriggeredAt.current[connectorId]
126135
forceUpdate((n) => n + 1)
127136
},
@@ -167,12 +176,12 @@ export function ConnectorsSection({
167176
workspaceId={workspaceId}
168177
knowledgeBaseId={knowledgeBaseId}
169178
canEdit={canEdit}
170-
isSyncing={isSyncing}
171-
isSyncPending={syncingConnectorId === connector.id}
172-
isUpdating={isUpdating}
179+
isSyncPending={syncingIds.has(connector.id)}
180+
isUpdating={updatingIds.has(connector.id)}
173181
syncCooldown={isSyncOnCooldown(connector.id)}
174182
onSync={() => handleSync(connector.id)}
175-
onTogglePause={() =>
183+
onTogglePause={() => {
184+
setUpdatingIds((prev) => new Set(prev).add(connector.id))
176185
updateConnector(
177186
{
178187
knowledgeBaseId,
@@ -182,14 +191,21 @@ export function ConnectorsSection({
182191
},
183192
},
184193
{
194+
onSettled: () => {
195+
setUpdatingIds((prev) => {
196+
const next = new Set(prev)
197+
next.delete(connector.id)
198+
return next
199+
})
200+
},
185201
onSuccess: () => setError(null),
186202
onError: (err) => {
187203
logger.error('Toggle pause failed', { error: err.message })
188204
setError(err.message)
189205
},
190206
}
191207
)
192-
}
208+
}}
193209
onEdit={() => setEditingConnector(connector)}
194210
onDelete={() => setDeleteTarget(connector.id)}
195211
/>
@@ -260,7 +276,6 @@ interface ConnectorCardProps {
260276
workspaceId: string
261277
knowledgeBaseId: string
262278
canEdit: boolean
263-
isSyncing: boolean
264279
isSyncPending: boolean
265280
isUpdating: boolean
266281
syncCooldown: boolean
@@ -275,7 +290,6 @@ function ConnectorCard({
275290
workspaceId,
276291
knowledgeBaseId,
277292
canEdit,
278-
isSyncing,
279293
isSyncPending,
280294
isUpdating,
281295
syncCooldown,
@@ -368,7 +382,7 @@ function ConnectorCard({
368382
variant='ghost'
369383
className='h-7 w-7 p-0'
370384
onClick={onSync}
371-
disabled={connector.status === 'syncing' || isSyncing || syncCooldown}
385+
disabled={connector.status === 'syncing' || isSyncPending || syncCooldown}
372386
>
373387
<RefreshCw
374388
className={cn(

0 commit comments

Comments
 (0)