Skip to content

Commit 839a6f3

Browse files
committed
fix(workspaces): count outstanding pin toggles off the mutation cache
`hooks/queries/workspace.ts` has no 'use client' directive because server code imports `workspaceKeys` during SSR, so the `useRef` counter added in 3dc924d broke the production build — caught by CI, not by typecheck or tests. `isMutating` answers the same question without a hook: `onSettled` runs before the mutation leaves `pending`, so it counts itself, and anything above one means a later toggle is still queued behind the scope.
1 parent 3dc924d commit 839a6f3

4 files changed

Lines changed: 119 additions & 111 deletions

File tree

apps/sim/hooks/queries/workspace.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { useRef } from 'react'
21
import type { QueryClient } from '@tanstack/react-query'
32
import { keepPreviousData, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
43
import { ApiClientError } from '@/lib/api/client/errors'
@@ -122,6 +121,12 @@ export function usePinnedWorkspaceIds(enabled = true) {
122121
})
123122
}
124123

124+
/**
125+
* Identifies pin toggles in the mutation cache so `onSettled` can tell whether it is
126+
* the last one. Doubles as the `scope` id, which is what serializes them.
127+
*/
128+
const WORKSPACE_PIN_MUTATION_KEY = ['workspace', 'toggle-pin'] as const
129+
125130
/** Applies one toggle to a pin list. Idempotent, so replaying it cannot double-apply. */
126131
function applyPinToggle(pinnedWorkspaceIds: string[], workspaceId: string, pinned: boolean) {
127132
const without = pinnedWorkspaceIds.filter((id) => id !== workspaceId)
@@ -144,10 +149,9 @@ function applyPinToggle(pinnedWorkspaceIds: string[], workspaceId: string, pinne
144149
export function useToggleWorkspacePin() {
145150
const queryClient = useQueryClient()
146151
const queryKey = workspaceKeys.list('active')
147-
/** Toggles the user has made that have not settled yet; see `onSettled`. */
148-
const outstandingRef = useRef(0)
149152

150153
return useMutation({
154+
mutationKey: WORKSPACE_PIN_MUTATION_KEY,
151155
scope: { id: 'workspace-pin' },
152156
mutationFn: async ({ workspaceId, pinned }: { workspaceId: string; pinned: boolean }) => {
153157
try {
@@ -167,7 +171,6 @@ export function useToggleWorkspacePin() {
167171
}
168172
},
169173
onMutate: async ({ workspaceId, pinned }) => {
170-
outstandingRef.current += 1
171174
await queryClient.cancelQueries({ queryKey })
172175
queryClient.setQueryData<WorkspacesResponse>(queryKey, (old) =>
173176
old
@@ -197,10 +200,16 @@ export function useToggleWorkspacePin() {
197200
* so an earlier toggle settles while a later one is still waiting its turn —
198201
* refetching there would render the server's intermediate state and bounce the
199202
* row out of the pinned group and back before the last write even leaves.
203+
*
204+
* Counted off the mutation cache rather than a ref because this module is
205+
* server-importable (`workspaceKeys` is read during SSR), so it cannot use hooks.
200206
*/
201207
onSettled: () => {
202-
outstandingRef.current -= 1
203-
if (outstandingRef.current > 0) return
208+
/**
209+
* `onSettled` runs before the mutation leaves `pending`, so it counts itself —
210+
* anything above one means a later toggle is still queued behind the scope.
211+
*/
212+
if (queryClient.isMutating({ mutationKey: WORKSPACE_PIN_MUTATION_KEY }) > 1) return
204213
queryClient.invalidateQueries({ queryKey: workspaceKeys.lists() })
205214
},
206215
})

apps/sim/lib/execution/sandbox/bundles/docx.cjs

Lines changed: 21 additions & 21 deletions
Large diffs are not rendered by default.

apps/sim/lib/execution/sandbox/bundles/pdf-lib.cjs

Lines changed: 21 additions & 21 deletions
Large diffs are not rendered by default.

apps/sim/lib/execution/sandbox/bundles/pptxgenjs.cjs

Lines changed: 62 additions & 63 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)