Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/sim/hooks/use-oauth-return.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ import { getDesktopBridge } from '@/lib/desktop'
import { oauthConnectionsKeys } from '@/hooks/queries/oauth/oauth-connections'
import { workspaceCredentialKeys } from '@/hooks/queries/utils/credential-keys'
import { requireWorkspaceCredentialListResponse } from '@/hooks/queries/utils/fetch-workspace-credentials'
import { SETTINGS_RETURN_URL_KEY } from '@/hooks/use-settings-navigation'

const OAUTH_CREDENTIAL_UPDATED_EVENT = 'oauth-credentials-updated'
const SETTINGS_RETURN_URL_KEY = 'settings-return-url'
const CONTEXT_MAX_AGE_MS = 15 * 60 * 1000

export interface OAuthResultMessage {
Expand Down
42 changes: 41 additions & 1 deletion apps/sim/hooks/use-settings-navigation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ vi.mock('@/lib/auth/auth-client', () => ({
useSession: vi.fn(() => ({ data: null, isPending: false })),
}))

import { resolveSettingsHref } from '@/hooks/use-settings-navigation'
import { resolveSettingsHref, resolveSettingsReturnUrl } from '@/hooks/use-settings-navigation'

const HOST_CONTEXT: WorkspaceHostContext = {
workspace: {
Expand Down Expand Up @@ -107,3 +107,43 @@ describe('resolveSettingsHref unified settings navigation', () => {
).toBe('/workspace/workspace-b/settings/billing')
})
})

describe('resolveSettingsReturnUrl', () => {
const fallback = '/workspace/workspace-b'

it('returns the stored url when it belongs to the current workspace', () => {
expect(
resolveSettingsReturnUrl({
storedUrl: '/workspace/workspace-b/w/workflow-a',
workspaceId: 'workspace-b',
fallback,
})
).toBe('/workspace/workspace-b/w/workflow-a')
})

it('discards a stored url captured in a workspace the user has since left', () => {
expect(
resolveSettingsReturnUrl({
storedUrl: '/workspace/workspace-a/w/workflow-a',
workspaceId: 'workspace-b',
fallback,
})
).toBe(fallback)
})

it('keeps workspace-agnostic stored urls', () => {
expect(
resolveSettingsReturnUrl({
storedUrl: '/account/settings/billing',
workspaceId: 'workspace-b',
fallback,
})
).toBe('/account/settings/billing')
})

it('falls back when nothing was stored', () => {
expect(
resolveSettingsReturnUrl({ storedUrl: null, workspaceId: 'workspace-b', fallback })
).toBe(fallback)
})
})
48 changes: 38 additions & 10 deletions apps/sim/hooks/use-settings-navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { canManageWorkspaceBilling } from '@/lib/billing/workspace-permissions'
import { useOptionalWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
import type { SettingsSection } from '@/app/workspace/[workspaceId]/settings/navigation'

const SETTINGS_RETURN_URL_KEY = 'settings-return-url'
export const SETTINGS_RETURN_URL_KEY = 'settings-return-url'

interface SettingsNavigationOptions {
section?: SettingsSection
Expand Down Expand Up @@ -57,6 +57,31 @@ export function resolveSettingsHref({
return query ? `${pathname}?${query}` : pathname
}

interface ResolveSettingsReturnUrlParams {
storedUrl: string | null
workspaceId?: string
fallback: string
}

/**
* Resolves the stored settings return url, discarding it when it points at a
* different workspace than the one currently open. Switching workspaces from
* settings keeps the user on the new workspace, so a return url captured in the
* old one would silently navigate them back out of it.
*/
export function resolveSettingsReturnUrl({
storedUrl,
workspaceId,
fallback,
}: ResolveSettingsReturnUrlParams): string {
if (!storedUrl) return fallback
const [, root, storedWorkspaceId] = storedUrl.split('/')
if (root === 'workspace' && storedWorkspaceId && storedWorkspaceId !== workspaceId) {
return fallback
}
return storedUrl
}

export function useSettingsNavigation(): UseSettingsNavigationReturn {
const router = useRouter()
const params = useParams<{ workspaceId?: string }>()
Expand All @@ -77,15 +102,18 @@ export function useSettingsNavigation(): UseSettingsNavigationReturn {
[hostContext, session?.user?.id, workspaceId]
)

const popSettingsReturnUrl = useCallback((fallback: string): string => {
try {
const url = sessionStorage.getItem(SETTINGS_RETURN_URL_KEY)
sessionStorage.removeItem(SETTINGS_RETURN_URL_KEY)
return url ?? fallback
} catch {
return fallback
}
}, [])
const popSettingsReturnUrl = useCallback(
(fallback: string): string => {
try {
const storedUrl = sessionStorage.getItem(SETTINGS_RETURN_URL_KEY)
sessionStorage.removeItem(SETTINGS_RETURN_URL_KEY)
return resolveSettingsReturnUrl({ storedUrl, workspaceId, fallback })
} catch {
return fallback
}
},
[workspaceId]
)

const navigateToSettings = useCallback(
(options?: SettingsNavigationOptions) => {
Expand Down
Loading