Revert "fix(workspace url id bug): switch workspace bug (#564)" (#567)

This reverts commit 0049644224.
This commit is contained in:
Vikhyath Mondreti
2025-06-27 14:15:09 -07:00
committed by GitHub
parent 02cecd5745
commit e4523961ea
6 changed files with 55 additions and 93 deletions

View File

@@ -1,5 +1,5 @@
import crypto from 'crypto'
import { and, desc, eq, isNull } from 'drizzle-orm'
import { and, eq, isNull } from 'drizzle-orm'
import { NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console-logger'
@@ -155,22 +155,14 @@ export async function GET(request: Request) {
if (workspaceId) {
// Filter by workspace ID only, not user ID
// This allows sharing workflows across workspace members
// Order by createdAt desc to match frontend sorting by lastModified
workflows = await db
.select()
.from(workflow)
.where(eq(workflow.workspaceId, workspaceId))
.orderBy(desc(workflow.createdAt))
workflows = await db.select().from(workflow).where(eq(workflow.workspaceId, workspaceId))
} else {
// Filter by user ID only, including workflows without workspace IDs
// Order by createdAt desc to match frontend sorting by lastModified
workflows = await db
.select()
.from(workflow)
.where(eq(workflow.userId, userId))
.orderBy(desc(workflow.createdAt))
workflows = await db.select().from(workflow).where(eq(workflow.userId, userId))
}
const elapsed = Date.now() - startTime
// Return the workflows
return NextResponse.json({ data: workflows }, { status: 200 })
} catch (error: any) {

View File

@@ -333,45 +333,23 @@ export const WorkspaceHeader = React.memo<WorkspaceHeaderProps>(
}, [sessionData?.user?.id, fetchSubscriptionStatus, fetchWorkspaces])
const switchWorkspace = useCallback(
async (workspace: Workspace) => {
(workspace: Workspace) => {
// If already on this workspace, close dropdown and do nothing else
if (activeWorkspace?.id === workspace.id) {
setWorkspaceDropdownOpen(false)
return
}
// Close dropdown immediately for responsive feel
setActiveWorkspace(workspace)
setWorkspaceDropdownOpen(false)
try {
// Update UI state optimistically
setActiveWorkspace(workspace)
// Use full workspace switch which now handles localStorage automatically
switchToWorkspace(workspace.id)
// Switch workspace data first with the explicit workspace ID
// This ensures the data switch happens with the correct ID regardless of URL timing
await switchToWorkspace(workspace.id)
// Then update URL - this will trigger useParams updates in other components
router.push(`/workspace/${workspace.id}/w`)
} catch (error) {
// If workspace switch fails, revert the optimistic UI update
logger.error('Failed to switch workspace:', error)
// Revert to previous workspace if we can identify it
const currentWorkspaces = workspaces
const fallbackWorkspace = currentWorkspaces.find((w) => w.id === currentWorkspaceId)
if (fallbackWorkspace) {
setActiveWorkspace(fallbackWorkspace)
}
}
// Update URL to include workspace ID
router.push(`/workspace/${workspace.id}/w`)
},
[
activeWorkspace?.id,
switchToWorkspace,
router,
setWorkspaceDropdownOpen,
workspaces,
currentWorkspaceId,
]
[activeWorkspace?.id, switchToWorkspace, router, setWorkspaceDropdownOpen]
)
const handleCreateWorkspace = useCallback(
@@ -394,11 +372,11 @@ export const WorkspaceHeader = React.memo<WorkspaceHeaderProps>(
setWorkspaces((prev) => [...prev, newWorkspace])
setActiveWorkspace(newWorkspace)
// Switch workspace data first with the explicit workspace ID
// Use switchToWorkspace to properly load workflows for the new workspace
// This will clear existing workflows, set loading state, and fetch workflows from DB
switchToWorkspace(newWorkspace.id)
// Then update URL to include new workspace ID
// Update URL to include new workspace ID
router.push(`/workspace/${newWorkspace.id}/w`)
}
} catch (err) {
@@ -487,14 +465,10 @@ export const WorkspaceHeader = React.memo<WorkspaceHeaderProps>(
// If deleted workspace was active, switch to another workspace
if (activeWorkspace?.id === id && updatedWorkspaces.length > 0) {
const newWorkspace = updatedWorkspaces[0]
setActiveWorkspace(newWorkspace)
// Use the specialized method for handling workspace deletion with explicit workspace ID
useWorkflowRegistry.getState().handleWorkspaceDeletion(newWorkspace.id)
// Update URL to the new workspace
router.push(`/workspace/${newWorkspace.id}/w`)
// Use the specialized method for handling workspace deletion
const newWorkspaceId = updatedWorkspaces[0].id
useWorkflowRegistry.getState().handleWorkspaceDeletion(newWorkspaceId)
setActiveWorkspace(updatedWorkspaces[0])
}
setWorkspaceDropdownOpen(false)
@@ -504,7 +478,7 @@ export const WorkspaceHeader = React.memo<WorkspaceHeaderProps>(
setIsDeleting(false)
}
},
[workspaces, activeWorkspace?.id, router]
[workspaces, activeWorkspace?.id]
)
const openEditModal = useCallback(

View File

@@ -13,7 +13,7 @@ import {
useGlobalShortcuts,
} from '@/app/workspace/[workspaceId]/w/hooks/use-keyboard-shortcuts'
import { useSidebarStore } from '@/stores/sidebar/store'
import { isWorkspaceInTransition, useWorkflowRegistry } from '@/stores/workflows/registry/store'
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
import { useUserPermissionsContext } from '../providers/workspace-permissions-provider'
import { CreateMenu } from './components/create-menu/create-menu'
@@ -32,16 +32,13 @@ const IS_DEV = process.env.NODE_ENV === 'development'
export function Sidebar() {
useGlobalShortcuts()
const router = useRouter()
const params = useParams()
const workspaceId = params.workspaceId as string
const { workflows, createWorkflow, isLoading: workflowsLoading } = useWorkflowRegistry()
const { isPending: sessionLoading } = useSession()
const userPermissions = useUserPermissionsContext()
// Simple loading logic: wait for workflows and valid workspaceId, plus workspace transitions
const isLoading = workflowsLoading || sessionLoading || !workspaceId || isWorkspaceInTransition()
const isLoading = workflowsLoading || sessionLoading
const router = useRouter()
const params = useParams()
const workspaceId = params.workspaceId as string
const pathname = usePathname()
const [showSettings, setShowSettings] = useState(false)
@@ -60,25 +57,41 @@ export function Sidebar() {
}
}, [showSettings, showHelp, showInviteMembers, setAnyModalOpen])
// Filter workflows for current workspace (database already sorted)
// Separate regular workflows from temporary marketplace workflows
const { regularWorkflows, tempWorkflows } = useMemo(() => {
if (isLoading) return { regularWorkflows: [], tempWorkflows: [] }
const regular: WorkflowMetadata[] = []
const temp: WorkflowMetadata[] = []
Object.values(workflows).forEach((workflow) => {
if (workflow.workspaceId === workspaceId || !workflow.workspaceId) {
if (workflow.marketplaceData?.status === 'temp') {
temp.push(workflow)
} else {
regular.push(workflow)
if (!isLoading) {
Object.values(workflows).forEach((workflow) => {
if (workflow.workspaceId === workspaceId || !workflow.workspaceId) {
if (workflow.marketplaceData?.status === 'temp') {
temp.push(workflow)
} else {
regular.push(workflow)
}
}
})
// Sort by last modified date (newest first)
const sortByLastModified = (a: WorkflowMetadata, b: WorkflowMetadata) => {
const dateA =
a.lastModified instanceof Date
? a.lastModified.getTime()
: new Date(a.lastModified).getTime()
const dateB =
b.lastModified instanceof Date
? b.lastModified.getTime()
: new Date(b.lastModified).getTime()
return dateB - dateA
}
})
regular.sort(sortByLastModified)
temp.sort(sortByLastModified)
}
return { regularWorkflows: regular, tempWorkflows: temp }
}, [workflows, workspaceId, isLoading])
}, [workflows, isLoading, workspaceId])
// Create workflow handler
const handleCreateWorkflow = async (folderId?: string) => {

View File

@@ -7,27 +7,10 @@ import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
export default function WorkflowsPage() {
const router = useRouter()
const { workflows, isLoading, loadWorkflows } = useWorkflowRegistry()
const { workflows, isLoading } = useWorkflowRegistry()
const params = useParams()
const workspaceId = params.workspaceId as string
// Load workflows for this specific workspace when component mounts or workspaceId changes
// Only load if we don't already have workflows for this workspace (to prevent duplicate calls during workspace switches)
useEffect(() => {
if (workspaceId) {
// Check if we already have workflows for this workspace
const workflowIds = Object.keys(workflows)
const hasWorkflowsForWorkspace =
workflowIds.length > 0 &&
Object.values(workflows).some((w) => w.workspaceId === workspaceId)
// Only load if we don't have workflows for this workspace and we're not loading
if (!hasWorkflowsForWorkspace && !isLoading) {
loadWorkflows(workspaceId)
}
}
}, [workspaceId, loadWorkflows, isLoading, workflows])
const workspaceId = params.workspaceId
useEffect(() => {
// Wait for workflows to load
@@ -35,7 +18,7 @@ export default function WorkflowsPage() {
const workflowIds = Object.keys(workflows)
// If we have workflows, redirect to the first one (database already sorted by lastModified desc)
// If we have workflows, redirect to the first one
if (workflowIds.length > 0) {
router.replace(`/workspace/${workspaceId}/w/${workflowIds[0]}`)
return

View File

@@ -318,6 +318,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) {
})
socketInstance.on('workflow-state', (state) => {
logger.info('Received workflow state from server:', state)
// This will be used to sync initial state when joining a workflow
})

View File

@@ -151,7 +151,6 @@ async function fetchWorkflowsFromDB(workspaceId?: string): Promise<void> {
})
// Only set first workflow as active if no active workflow is set and we have workflows
// Database already returns workflows sorted by lastModified desc
const currentState = useWorkflowRegistry.getState()
if (!currentState.activeWorkflowId && Object.keys(registryWorkflows).length > 0) {
const firstWorkflowId = Object.keys(registryWorkflows)[0]