Skip to content

feat(canvas): auto-switch workspace when opening a flow URL from another member workspace#6582

Open
dkindlund wants to merge 5 commits into
FlowiseAI:mainfrom
dkindlund:pr/canvas-workspace-autoswitch
Open

feat(canvas): auto-switch workspace when opening a flow URL from another member workspace#6582
dkindlund wants to merge 5 commits into
FlowiseAI:mainfrom
dkindlund:pr/canvas-workspace-autoswitch

Conversation

@dkindlund

Copy link
Copy Markdown
Contributor

Closes #6581

What this does

In multi-user / enterprise mode, chatflows/agentflows are scoped to the user's active workspace, and the canvas load is scoped to that active workspace. So when a user opens a flow URL (/canvas/:id, /agentcanvas/:id, /v2/agentcanvas/:id) whose flow lives in a workspace they are a member of but which isn't active, the canvas dead-ends on:

Chatflow <id> not found in the database!

and they have to manually find and switch workspaces. Since chat_flow.id is a globally-unique UUID it maps to exactly one owning workspace, so the UI can resolve it and switch automatically — only when the user is a member.

Changes

Backend

  • services/chatflows/index.ts: new resolveChatflowWorkspace(chatflowId, userId) — looks the flow up by id (no workspace filter), then gates strictly on a direct workspace_user membership check, returning { workspaceId }. Every failure mode (bad UUID aside) returns the identical 404 "Chatflow <id> not found in the database!" as getChatflowById.
  • controllers/chatflows/index.ts: new getChatflowWorkspace controller (uses req.user?.id; API-key callers have no user → 404).
  • routes/chatflows/index.ts: new GET /chatflows/resolve-workspace/:id (two-segment path so it never collides with the ['/', '/:id'] matcher; same checkAnyPermission as the read route).

Frontend

  • api/chatflows.js: getChatflowWorkspace(id).
  • hooks/useFlowWorkspaceAutoSwitch.jsx (new): shared hook used by both canvases. On a 404, resolves the owning workspace and — only if it's in the user's assignedWorkspaces and isn't already active — calls the existing workspaceApi.switchWorkspace, dispatches workspaceSwitchSuccess, and re-fetches the flow. Attempts at most once per flow id; falls back to the normal error otherwise. Stays on the same canvas URL (no navigate('/'); navigate(0)).
  • views/canvas/index.jsx and views/agentflowsv2/Canvas.jsx: wire the hook into the existing getSpecificChatflow error branch.

Security

This preserves the existing "Protect Against Cross-Workspace Chatflow Disclosure" behavior:

  • All non-member / missing / no-user branches return the identical 404, so the endpoint never reveals that a flow exists in a workspace the caller can't access.
  • Membership is the only thing that reveals a workspace id; API-key callers are excluded.
  • The client additionally verifies the resolved workspace is in assignedWorkspaces before switching, so it can never switch into an unauthorized workspace.

How it was tested

Manually against a local multi-user instance:

  1. Member-but-inactive: flow in WS-A, user member of A, active in B → opening the flow URL auto-switches to A and the canvas loads, URL preserved. ✅
  2. Non-member: user not in A opens A's flow → identical 404, no switch, no leak. ✅
  3. Same-workspace: normal open unaffected. ✅
  4. Verified for both v1 (/canvas, /agentcanvas) and v2 (/v2/agentcanvas).

The backend resolver was also exercised directly: 404 repro, 200 member-resolve, identical-404 for non-member (no leak), 400 for a malformed UUID.

…her member workspace

In multi-user mode, chatflows/agentflows are scoped to the user's *active*
workspace, and the canvas load is scoped to that active workspace. So when a
user opens a flow URL (`/canvas/:id`, `/agentcanvas/:id`, `/v2/agentcanvas/:id`)
whose flow lives in a workspace they are a *member of* but which isn't their
active workspace, the canvas dead-ends on:

    Failed to retrieve Chatflow ... Chatflow <id> not found in the database!

and the user has to manually figure out which workspace owns it and switch.
Since `chat_flow.id` is a globally-unique UUID, it maps to exactly one owning
workspace, so the UI can resolve it and switch automatically.

Backend: add a membership-gated `GET /chatflows/resolve-workspace/:id` resolver
that returns `{ workspaceId }` only when the requesting user is a member of the
flow's workspace. Every other branch (missing flow, non-member, API-key caller
with no user) returns the *identical* 404 as `getChatflowById`, so this
preserves the existing "Protect Against Cross-Workspace Chatflow Disclosure"
hardening and never reveals that a flow exists in a workspace the caller cannot
access.

Frontend: on the canvas load 404, a shared `useFlowWorkspaceAutoSwitch` hook
resolves the owning workspace and — only if it's in the user's
`assignedWorkspaces` and isn't already active — switches to it and re-fetches
the flow, staying on the same canvas URL. Falls back to the normal error for a
genuine 404 / non-member. Guarded to attempt at most once per flow id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to automatically switch the active workspace when a user opens a chatflow URL belonging to a workspace they are a member of, but which is not currently active. It adds a secure server-side endpoint to resolve the workspace and a custom React hook useFlowWorkspaceAutoSwitch to handle the transition on the client side. The review feedback suggests defensive checks for workspaceId on the server, wrapping the auto-switch function in useCallback for performance, and using optional chaining on error responses in the UI to prevent potential crashes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/server/src/services/chatflows/index.ts Outdated
Comment thread packages/ui/src/hooks/useFlowWorkspaceAutoSwitch.jsx Outdated
Comment thread packages/ui/src/hooks/useFlowWorkspaceAutoSwitch.jsx Outdated
Comment thread packages/ui/src/views/agentflowsv2/Canvas.jsx
Comment thread packages/ui/src/views/canvas/index.jsx
- service: also treat a chatflow with a missing workspaceId as not-found
  before the membership lookup (fail-fast, avoids querying WorkspaceUser
  with a null workspaceId).
- useFlowWorkspaceAutoSwitch: memoize tryAutoSwitch with useCallback so it
  isn't recreated each render; defensively optional-chain w?.id and
  switchRes?.data.
- canvas/index.jsx, agentflowsv2/Canvas.jsx: optional-chain the fallback
  error message so a transport-level failure (no error.response) can't throw
  a TypeError; fall back to error.message / 'Unknown error'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkindlund

Copy link
Copy Markdown
Contributor Author

@gemini-code-assist, please re-review based on the latest commit.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a mechanism to automatically switch the active workspace in the UI when a user opens a chatflow URL belonging to another workspace they are a member of. This is achieved by adding a new /resolve-workspace/:id endpoint on the backend and a corresponding useFlowWorkspaceAutoSwitch hook on the frontend. The review feedback suggests a security improvement to ensure that the user's membership status is explicitly checked as active before resolving the workspace, preventing unauthorized access or disclosure for disabled or pending users.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/server/src/services/chatflows/index.ts
Comment thread packages/server/src/services/chatflows/index.ts Outdated
Gate the membership lookup in resolveChatflowWorkspace on
WorkspaceUserStatus.ACTIVE so a user who is only INVITED (invited but not
yet accepted) or DISABLEd cannot resolve a flow's workspace or auto-switch
into it. Without this, the default membership row (status INVITED) would
satisfy the check and leak/grant cross-workspace access via a direct API
call. Non-active members now get the same 404 as non-members.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkindlund

Copy link
Copy Markdown
Contributor Author

@gemini-code-assist, please re-review based on the latest commit.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an automatic workspace-switching mechanism in the UI when a user opens a chatflow URL belonging to another workspace they are a member of. This is supported by a new backend endpoint /resolve-workspace/:id that safely resolves the workspace ID while preventing cross-workspace information disclosure. Feedback highlights a critical issue in the custom hook useFlowWorkspaceAutoSwitch where a stale closure of currentUser can occur due to missing dependencies in the canvas components' useEffect hooks. Additionally, the hook prematurely marks a flow ID as attempted before verifying if the user is loaded. A ref-based solution is suggested to resolve these issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/ui/src/hooks/useFlowWorkspaceAutoSwitch.jsx Outdated
…try before user loads

Adopt the latest-ref pattern in useFlowWorkspaceAutoSwitch:

- Store currentUser in a ref kept current via useEffect, and read it inside
  tryAutoSwitch from the ref. tryAutoSwitch now only depends on [dispatch], so
  its identity is stable — callers that omit it from their useEffect deps no
  longer capture a stale callback that closes over an old/null user.
- Check that the user is loaded BEFORE adding the flow id to attemptedRef, so a
  call made before currentUser is hydrated doesn't permanently prevent a later,
  valid auto-switch attempt for that flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkindlund

Copy link
Copy Markdown
Contributor Author

@gemini-code-assist, please re-review based on the latest commit.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a workspace auto-switch feature that automatically switches the active workspace when a user opens a flow URL belonging to another workspace they are a member of, preventing a dead-end 404 error. This is implemented via a new server-side endpoint /resolve-workspace/:id that safely resolves the owning workspace without leaking information to non-members, and a custom React hook useFlowWorkspaceAutoSwitch integrated into the canvas views. Feedback suggests improving the hook's error handling by clearing the flow ID from the attempted set during transient (non-404) errors to allow subsequent retries.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/ui/src/hooks/useFlowWorkspaceAutoSwitch.jsx
In useFlowWorkspaceAutoSwitch, only a 404 from the resolver/switch is
definitive (not a member / missing flow) — keep it marked in attemptedRef so
we don't retry. For transient failures (network error, 5xx, etc.) delete the
flow id from attemptedRef so a later re-fetch can attempt the auto-switch
again instead of being permanently blocked until a full page reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@dkindlund

Copy link
Copy Markdown
Contributor Author

@gemini-code-assist, please re-review based on the latest commit.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a workspace auto-switching feature for chatflows. It adds a new backend endpoint /chatflows/resolve-workspace/:id and a corresponding service method resolveChatflowWorkspace to resolve the owning workspace of a chatflow, strictly gating access to active members of that workspace to prevent unauthorized information disclosure. On the frontend, a new React hook useFlowWorkspaceAutoSwitch is introduced and integrated into the canvas views. When a user attempts to load a chatflow that belongs to another workspace they are a member of, the UI automatically switches to that workspace and re-fetches the flow instead of displaying a 404 error. I have no additional feedback to provide as there are no review comments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multi-user: opening a flow URL from another (member) workspace fails with "Chatflow not found" instead of auto-switching

1 participant