-
-
Notifications
You must be signed in to change notification settings - Fork 24.7k
feat(canvas): auto-switch workspace when opening a flow URL from another member workspace #6582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dkindlund
wants to merge
5
commits into
FlowiseAI:main
Choose a base branch
from
dkindlund:pr/canvas-workspace-autoswitch
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+173
−2
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
62470cf
feat(canvas): auto-switch workspace when opening a flow URL from anot…
dkindlund a556597
refactor(canvas): address review feedback on workspace auto-switch
dkindlund f68fb59
fix(security): require ACTIVE membership to resolve a flow's workspace
dkindlund 2deac0a
fix(canvas): make auto-switch hook stale-closure-safe; don't block re…
dkindlund dc7c86e
fix(canvas): retry auto-switch after transient failures
dkindlund File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| import { useCallback, useEffect, useRef } from 'react' | ||
| import { useDispatch, useSelector } from 'react-redux' | ||
|
|
||
| import chatflowsApi from '@/api/chatflows' | ||
| import workspaceApi from '@/api/workspace' | ||
| import { workspaceSwitchSuccess } from '@/store/reducers/authSlice' | ||
|
|
||
| // When a flow canvas fails to load with a 404 because the flow lives in a workspace the user belongs to but | ||
| // isn't their ACTIVE workspace, resolve the flow's owning workspace (membership-gated server-side) and switch | ||
| // to it, then let the caller re-fetch — instead of dead-ending on "Chatflow <id> not found in the database!". | ||
| // | ||
| // Returns an async `tryAutoSwitch(chatflowId, error, onSwitched)`: | ||
| // - returns true => it switched workspaces and invoked onSwitched() (caller should suppress its error) | ||
| // - returns false => not applicable / not a member; caller should fall back to its normal error handling | ||
| // | ||
| // Security: the resolver only returns a workspaceId when the user is a member, and we additionally verify the | ||
| // id is in the user's assignedWorkspaces before switching — so we never switch into an unauthorized workspace. | ||
| export const useFlowWorkspaceAutoSwitch = () => { | ||
| const dispatch = useDispatch() | ||
| const currentUser = useSelector((state) => state.auth.user) | ||
| // Keep the latest user in a ref so tryAutoSwitch can read it without being listed as a useCallback dep. | ||
| // This keeps the callback identity stable (callers omit it from their useEffect deps) while still reading | ||
| // the freshest user — avoiding a stale closure if the user loads/changes after the callback was created. | ||
| const currentUserRef = useRef(currentUser) | ||
| useEffect(() => { | ||
| currentUserRef.current = currentUser | ||
| }, [currentUser]) | ||
|
|
||
| const attemptedRef = useRef(new Set()) | ||
|
|
||
| const tryAutoSwitch = useCallback( | ||
| async (chatflowId, error, onSwitched) => { | ||
| const status = error?.response?.status | ||
| if (status !== 404 || !chatflowId) return false | ||
|
|
||
| // Bail before marking attempted if the user isn't loaded yet, so a later (loaded) call can retry. | ||
| const user = currentUserRef.current | ||
| if (!user) return false | ||
|
|
||
| // Only attempt once per flow id to avoid any retry loop if something goes sideways. | ||
| if (attemptedRef.current.has(chatflowId)) return false | ||
| attemptedRef.current.add(chatflowId) | ||
|
|
||
| try { | ||
| const res = await chatflowsApi.getChatflowWorkspace(chatflowId) | ||
| const workspaceId = res?.data?.workspaceId | ||
| if (!workspaceId) return false | ||
| if (workspaceId === user.activeWorkspaceId) return false | ||
| const assigned = user.assignedWorkspaces || [] | ||
| if (!assigned.some((w) => w?.id === workspaceId)) return false | ||
|
|
||
| const switchRes = await workspaceApi.switchWorkspace(workspaceId) | ||
| dispatch(workspaceSwitchSuccess(switchRes?.data)) | ||
| if (typeof onSwitched === 'function') onSwitched() | ||
| return true | ||
| } catch (e) { | ||
| // A 404 is definitive (not a member / missing flow) — leave it marked so we don't retry. | ||
| // For transient failures (network error, 5xx, etc.) clear the mark so a later re-fetch can retry. | ||
| if (e?.response?.status !== 404) { | ||
| attemptedRef.current.delete(chatflowId) | ||
| } | ||
| // Fall back to the caller's normal error handling. | ||
| return false | ||
| } | ||
|
dkindlund marked this conversation as resolved.
|
||
| }, | ||
| [dispatch] | ||
| ) | ||
|
|
||
| return tryAutoSwitch | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.