Skip to content

Commit 5eb494d

Browse files
fix(secrets): secrets/integrations component code cleanup (#4003)
* fix(secrets): secrets/integrations component code cleanup * address comments
1 parent 8df3f20 commit 5eb494d

File tree

3 files changed

+66
-24
lines changed

3 files changed

+66
-24
lines changed

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

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,6 @@ export function CredentialsManager() {
323323
const [selectedDescriptionDraft, setSelectedDescriptionDraft] = useState('')
324324
const [copyIdSuccess, setCopyIdSuccess] = useState(false)
325325
const [detailsError, setDetailsError] = useState<string | null>(null)
326-
const [isSavingDetails, setIsSavingDetails] = useState(false)
327326
const [showDetailUnsavedChanges, setShowDetailUnsavedChanges] = useState(false)
328327
const [memberUserId, setMemberUserId] = useState('')
329328
const [memberRole, setMemberRole] = useState<WorkspaceCredentialRole>('member')
@@ -350,8 +349,9 @@ export function CredentialsManager() {
350349
[envCredentials, selectedCredentialId]
351350
)
352351

353-
if (selectedCredential?.id !== prevSelectedCredentialId) {
354-
setPrevSelectedCredentialId(selectedCredential?.id ?? null)
352+
const currentCredentialId = selectedCredential?.id ?? null
353+
if (currentCredentialId !== prevSelectedCredentialId) {
354+
setPrevSelectedCredentialId(currentCredentialId)
355355
if (!selectedCredential) {
356356
setSelectedDescriptionDraft('')
357357
setSelectedDisplayNameDraft('')
@@ -474,6 +474,11 @@ export function CredentialsManager() {
474474
return personalInvalid || workspaceInvalid
475475
}, [envVars, newWorkspaceRows])
476476

477+
const isListSaving =
478+
savePersonalMutation.isPending ||
479+
upsertWorkspaceMutation.isPending ||
480+
removeWorkspaceMutation.isPending
481+
477482
hasChangesRef.current = hasChanges
478483
shouldBlockNavRef.current = hasChanges || isDetailsDirty
479484

@@ -652,12 +657,12 @@ export function CredentialsManager() {
652657
)
653658

654659
const handleBackAttempt = useCallback(() => {
655-
if (isDetailsDirty && !isSavingDetails) {
660+
if (isDetailsDirty && !updateCredential.isPending) {
656661
setShowDetailUnsavedChanges(true)
657662
} else {
658663
setSelectedCredentialId(null)
659664
}
660-
}, [isDetailsDirty, isSavingDetails])
665+
}, [isDetailsDirty, updateCredential.isPending])
661666

662667
const handleDiscardDetailChanges = useCallback(() => {
663668
setShowDetailUnsavedChanges(false)
@@ -667,9 +672,9 @@ export function CredentialsManager() {
667672
}, [selectedCredential])
668673

669674
const handleSaveDetails = useCallback(async () => {
670-
if (!selectedCredential || !isSelectedAdmin || !isDetailsDirty) return
675+
if (!selectedCredential || !isSelectedAdmin || !isDetailsDirty || updateCredential.isPending)
676+
return
671677
setDetailsError(null)
672-
setIsSavingDetails(true)
673678

674679
try {
675680
if (isDisplayNameDirty || isDescriptionDirty) {
@@ -683,8 +688,6 @@ export function CredentialsManager() {
683688
const message = error instanceof Error ? error.message : 'Failed to save changes'
684689
setDetailsError(message)
685690
logger.error('Failed to save secret details', error)
686-
} finally {
687-
setIsSavingDetails(false)
688691
}
689692
}, [
690693
selectedCredential,
@@ -906,6 +909,8 @@ export function CredentialsManager() {
906909
const handleCancel = resetToSaved
907910

908911
const handleSave = useCallback(async () => {
912+
if (isListSaving) return
913+
909914
const prevInitialVars = [...initialVarsRef.current]
910915
const prevInitialWorkspaceVars = { ...initialWorkspaceVarsRef.current }
911916

@@ -964,6 +969,7 @@ export function CredentialsManager() {
964969
logger.error('Failed to save environment variables:', error)
965970
}
966971
}, [
972+
isListSaving,
967973
envVars,
968974
workspaceVars,
969975
newWorkspaceRows,
@@ -1316,9 +1322,9 @@ export function CredentialsManager() {
13161322
<Button
13171323
variant='primary'
13181324
onClick={handleSaveDetails}
1319-
disabled={!isDetailsDirty || isSavingDetails}
1325+
disabled={!isDetailsDirty || updateCredential.isPending}
13201326
>
1321-
{isSavingDetails ? 'Saving...' : 'Save'}
1327+
{updateCredential.isPending ? 'Saving...' : 'Save'}
13221328
</Button>
13231329
)}
13241330
</div>
@@ -1416,11 +1422,13 @@ export function CredentialsManager() {
14161422
<Tooltip.Trigger asChild>
14171423
<Button
14181424
onClick={handleSave}
1419-
disabled={isLoading || !hasChanges || hasConflicts || hasInvalidKeys}
1425+
disabled={
1426+
isLoading || !hasChanges || hasConflicts || hasInvalidKeys || isListSaving
1427+
}
14201428
variant='primary'
14211429
className={`${hasConflicts || hasInvalidKeys ? 'cursor-not-allowed opacity-50' : ''}`}
14221430
>
1423-
Save
1431+
{isListSaving ? 'Saving...' : 'Save'}
14241432
</Button>
14251433
</Tooltip.Trigger>
14261434
{hasConflicts && <Tooltip.Content>Resolve all conflicts before saving</Tooltip.Content>}

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

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,11 @@ export function IntegrationsManager() {
246246
}, [selectedCredential, selectedDisplayNameDraft])
247247

248248
const isDetailsDirty = isDescriptionDirty || isDisplayNameDirty
249-
const [isSavingDetails, setIsSavingDetails] = useState(false)
250249

251250
const handleSaveDetails = async () => {
252-
if (!selectedCredential || !isSelectedAdmin || !isDetailsDirty) return
251+
if (!selectedCredential || !isSelectedAdmin || !isDetailsDirty || updateCredential.isPending)
252+
return
253253
setDetailsError(null)
254-
setIsSavingDetails(true)
255254

256255
try {
257256
if (isDisplayNameDirty || isDescriptionDirty) {
@@ -263,26 +262,22 @@ export function IntegrationsManager() {
263262
if (isDisplayNameDirty) setSelectedDisplayNameDraft((v) => v.trim())
264263
if (isDescriptionDirty) setSelectedDescriptionDraft((v) => v.trim())
265264
}
266-
267-
await refetchCredentials()
268265
} catch (error: unknown) {
269266
const message = error instanceof Error ? error.message : 'Failed to save changes'
270267
setDetailsError(message)
271268
logger.error('Failed to save credential details', error)
272-
} finally {
273-
setIsSavingDetails(false)
274269
}
275270
}
276271

277272
const handleBackAttempt = useCallback(() => {
278-
if (isDetailsDirty && !isSavingDetails) {
273+
if (isDetailsDirty && !updateCredential.isPending) {
279274
setShowUnsavedChangesAlert(true)
280275
} else {
281276
setSelectedCredentialId(null)
282277
setSelectedDescriptionDraft('')
283278
setSelectedDisplayNameDraft('')
284279
}
285-
}, [isDetailsDirty, isSavingDetails])
280+
}, [isDetailsDirty, updateCredential.isPending])
286281

287282
const handleDiscardChanges = useCallback(() => {
288283
setShowUnsavedChangesAlert(false)
@@ -1430,9 +1425,9 @@ export function IntegrationsManager() {
14301425
<Button
14311426
variant='primary'
14321427
onClick={handleSaveDetails}
1433-
disabled={!isDetailsDirty || isSavingDetails}
1428+
disabled={!isDetailsDirty || updateCredential.isPending}
14341429
>
1435-
{isSavingDetails ? 'Saving...' : 'Save'}
1430+
{updateCredential.isPending ? 'Saving...' : 'Save'}
14361431
</Button>
14371432
)}
14381433
</div>

apps/sim/hooks/queries/credentials.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,45 @@ export function useUpdateWorkspaceCredential() {
223223
}
224224
return response.json()
225225
},
226+
onMutate: async (variables) => {
227+
await queryClient.cancelQueries({
228+
queryKey: workspaceCredentialKeys.detail(variables.credentialId),
229+
})
230+
await queryClient.cancelQueries({ queryKey: workspaceCredentialKeys.lists() })
231+
232+
const previousLists = queryClient.getQueriesData<WorkspaceCredential[]>({
233+
queryKey: workspaceCredentialKeys.lists(),
234+
})
235+
236+
queryClient.setQueriesData<WorkspaceCredential[]>(
237+
{ queryKey: workspaceCredentialKeys.lists() },
238+
(old) => {
239+
if (!old) return old
240+
return old.map((cred) =>
241+
cred.id === variables.credentialId
242+
? {
243+
...cred,
244+
...(variables.displayName !== undefined
245+
? { displayName: variables.displayName }
246+
: {}),
247+
...(variables.description !== undefined
248+
? { description: variables.description ?? null }
249+
: {}),
250+
}
251+
: cred
252+
)
253+
}
254+
)
255+
256+
return { previousLists }
257+
},
258+
onError: (_err, _variables, context) => {
259+
if (context?.previousLists) {
260+
for (const [queryKey, data] of context.previousLists) {
261+
queryClient.setQueryData(queryKey, data)
262+
}
263+
}
264+
},
226265
onSettled: (_data, _error, variables) => {
227266
queryClient.invalidateQueries({
228267
queryKey: workspaceCredentialKeys.detail(variables.credentialId),

0 commit comments

Comments
 (0)