Skip to content

Commit 4aee01e

Browse files
committed
fix(settings): isolate identity lifecycle state
1 parent 66c3bc0 commit 4aee01e

36 files changed

Lines changed: 512 additions & 122 deletions

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/agent-group/tool-permission-card.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { createLogger } from '@sim/logger'
1616
import { useQueryClient } from '@tanstack/react-query'
1717
import { requestJson } from '@/lib/api/client/request'
1818
import { copilotToolPermissionContract } from '@/lib/api/contracts/copilot'
19-
import { generalSettingsKeys } from '@/hooks/queries/general-settings-data'
19+
import { generalSettingsKeys } from '@/hooks/queries/current-user-data'
2020
import { useToolPermissionStore } from '@/stores/tool-permission/store'
2121

2222
const logger = createLogger('ToolPermissionCard')

apps/sim/app/workspace/[workspaceId]/prefetch.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ import { getWorkspaceHostContextForViewer } from '@/lib/workspaces/host-context'
1010
import { listWorkspacesForViewer } from '@/lib/workspaces/list'
1111
import { getWorkspacePermissionsForAuthorizedViewer } from '@/lib/workspaces/permissions/utils'
1212
import { prefetchResourceFolders } from '@/app/workspace/[workspaceId]/lib/prefetch-resource-folders'
13+
import {
14+
mapUserProfileResponse,
15+
USER_PROFILE_STALE_TIME,
16+
userProfileKeys,
17+
} from '@/hooks/queries/current-user-data'
1318
import {
1419
MOTHERSHIP_CHAT_LIST_STALE_TIME,
1520
mapChat,
1621
mothershipChatKeys,
1722
} from '@/hooks/queries/mothership-chats'
18-
import {
19-
mapUserProfileResponse,
20-
USER_PROFILE_STALE_TIME,
21-
userProfileKeys,
22-
} from '@/hooks/queries/user-profile-data'
2323
import { workflowKeys } from '@/hooks/queries/utils/workflow-keys'
2424
import { mapWorkflow, WORKFLOW_LIST_STALE_TIME } from '@/hooks/queries/utils/workflow-list-query'
2525
import { normalizeWorkspacesResponse } from '@/hooks/queries/utils/workspace-list-query'

apps/sim/app/workspace/[workspaceId]/settings/[section]/prefetch.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ vi.mock('@/lib/api/server/routes', () => ({
2626
}))
2727

2828
import { SECTION_PREFETCHERS } from '@/app/workspace/[workspaceId]/settings/[section]/prefetch'
29-
import { generalSettingsKeys } from '@/hooks/queries/general-settings-data'
29+
import { generalSettingsKeys } from '@/hooks/queries/current-user-data'
3030
import { credentialGroupKeys } from '@/hooks/queries/utils/credential-group-queries'
3131

3232
describe('general settings prefetch', () => {

apps/sim/app/workspace/[workspaceId]/settings/components/general/general.tsx

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,13 +188,18 @@ export function General() {
188188
}
189189

190190
const handleSignOut = async () => {
191+
const logoutUrl = '/login?fromLogout=true'
192+
let canNavigateInApp = false
193+
191194
try {
192-
await Promise.all([signOut(), clearUserData()])
193-
router.push('/login?fromLogout=true')
195+
const [, inMemoryResetSucceeded] = await Promise.all([signOut(), clearUserData()])
196+
canNavigateInApp = inMemoryResetSucceeded
194197
} catch (error) {
195198
logger.error('Error signing out:', { error })
196-
router.push('/login?fromLogout=true')
197199
}
200+
201+
if (canNavigateInApp) router.push(logoutUrl)
202+
else window.location.assign(logoutUrl)
198203
}
199204

200205
const handleResetPasswordConfirm = async () => {

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.test.tsx

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const {
1414
mockFetch,
1515
mockHandleExecutionCancelledConsole,
1616
mockHandleExecutionErrorConsole,
17+
mockPersistenceExecutionEnded,
18+
mockPersistenceExecutionStarted,
1719
mockRequestJson,
1820
mockResolveStartCandidates,
1921
mockSelectBestTrigger,
@@ -89,6 +91,8 @@ const {
8991
mockFetch: vi.fn(),
9092
mockHandleExecutionCancelledConsole: vi.fn(),
9193
mockHandleExecutionErrorConsole: vi.fn(),
94+
mockPersistenceExecutionEnded: vi.fn(),
95+
mockPersistenceExecutionStarted: vi.fn(() => ({})),
9296
mockRequestJson: vi.fn(),
9397
mockResolveStartCandidates: vi.fn(),
9498
mockSelectBestTrigger: vi.fn(),
@@ -237,8 +241,8 @@ vi.mock('@/stores/execution', () => ({
237241
vi.mock('@/stores/terminal', () => ({
238242
clearExecutionPointer: vi.fn(),
239243
consolePersistence: {
240-
executionStarted: vi.fn(),
241-
executionEnded: vi.fn(),
244+
executionStarted: mockPersistenceExecutionStarted,
245+
executionEnded: mockPersistenceExecutionEnded,
242246
persist: vi.fn(),
243247
},
244248
loadExecutionPointer: vi.fn(),
@@ -402,6 +406,9 @@ describe('useWorkflowExecution cancellation', () => {
402406
describe('useWorkflowExecution attachment uploads', () => {
403407
beforeEach(() => {
404408
vi.clearAllMocks()
409+
executionStoreState.getWorkflowExecution.mockReturnValue(
410+
executionStoreState.workflowExecutions.get('workflow-1')!
411+
)
405412
executionStoreState.getCurrentExecutionId.mockReturnValue(null)
406413
mockResolveStartCandidates.mockReturnValue([])
407414
mockSelectBestTrigger.mockReturnValue([])
@@ -538,6 +545,46 @@ describe('useWorkflowExecution attachment uploads', () => {
538545
unmount()
539546
})
540547

548+
it('does not let an overlapping run without lifecycle ownership end the active run', async () => {
549+
const persistenceExecution = {}
550+
let resolveActiveRun: (() => void) | undefined
551+
mockPersistenceExecutionStarted.mockReturnValueOnce(persistenceExecution)
552+
mockExecute.mockImplementationOnce(
553+
() =>
554+
new Promise<void>((resolve) => {
555+
resolveActiveRun = resolve
556+
})
557+
)
558+
const { result, unmount } = renderWorkflowExecutionHook()
559+
560+
let activeRun: unknown
561+
await act(async () => {
562+
activeRun = await result().handleRunWorkflow({ input: 'active run' })
563+
})
564+
565+
executionStoreState.getWorkflowExecution.mockReturnValue({
566+
...executionStoreState.getWorkflowExecution(),
567+
isExecuting: true,
568+
})
569+
570+
await act(async () => {
571+
await result().handleRunWorkflow()
572+
})
573+
574+
expect(mockPersistenceExecutionStarted).toHaveBeenCalledTimes(1)
575+
expect(mockPersistenceExecutionEnded).not.toHaveBeenCalled()
576+
577+
await act(async () => {
578+
resolveActiveRun?.()
579+
await drainStream(activeRun)
580+
})
581+
582+
expect(mockPersistenceExecutionEnded).toHaveBeenCalledOnce()
583+
expect(mockPersistenceExecutionEnded).toHaveBeenCalledWith(persistenceExecution)
584+
585+
unmount()
586+
})
587+
541588
it('uses only projected live thinking without changing normal settle behavior', async () => {
542589
mockExecute.mockImplementationOnce(async (options) => {
543590
options.onExecutionId?.('execution-1')

0 commit comments

Comments
 (0)