diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/deploy-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/deploy-modal.tsx index 30238ca624..2cf5ac229c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/deploy-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/deploy-modal.tsx @@ -17,7 +17,7 @@ import { Button } from '@/components/ui/button' import { Card, CardContent } from '@/components/ui/card' import { CopyButton } from '@/components/ui/copy-button' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' -import { env } from '@/lib/env' +import { getEnv } from '@/lib/env' import { createLogger } from '@/lib/logs/console-logger' import { cn } from '@/lib/utils' import { ChatDeploy } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy' @@ -225,7 +225,7 @@ export function DeployModal({ } const data = await response.json() - const endpoint = `${env.NEXT_PUBLIC_APP_URL}/api/workflows/${workflowId}/execute` + const endpoint = `${getEnv('NEXT_PUBLIC_APP_URL')}/api/workflows/${workflowId}/execute` const inputFormatExample = getInputFormatExample() setDeploymentInfo({ @@ -288,7 +288,7 @@ export function DeployModal({ } // Update the local deployment info - const endpoint = `${env.NEXT_PUBLIC_APP_URL}/api/workflows/${workflowId}/execute` + const endpoint = `${getEnv('NEXT_PUBLIC_APP_URL')}/api/workflows/${workflowId}/execute` const inputFormatExample = getInputFormatExample() const newDeploymentInfo = { @@ -597,7 +597,7 @@ export function DeployModal({ { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/file-selector/file-selector-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/file-selector/file-selector-input.tsx index aae757d5e7..aa3a6ec837 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/file-selector/file-selector-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/components/file-selector/file-selector-input.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react' import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' -import { env } from '@/lib/env' +import { getEnv } from '@/lib/env' import type { SubBlockConfig } from '@/blocks/types' import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' @@ -169,8 +169,8 @@ export function FileSelectorInput({ } // For Google Drive - const clientId = env.NEXT_PUBLIC_GOOGLE_CLIENT_ID || '' - const apiKey = env.NEXT_PUBLIC_GOOGLE_API_KEY || '' + const clientId = getEnv('NEXT_PUBLIC_GOOGLE_CLIENT_ID') || '' + const apiKey = getEnv('NEXT_PUBLIC_GOOGLE_API_KEY') || '' // Render Google Calendar selector if (isGoogleCalendar) { diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/create-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/create-menu.tsx index 7e887cf5a6..5b09ddc7c6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/create-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/create-menu/create-menu.tsx @@ -5,10 +5,8 @@ import { logger } from '@sentry/nextjs' import { File, Folder, Plus, Upload } from 'lucide-react' import { useParams, useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' +import { generateFolderName } from '@/lib/naming' import { cn } from '@/lib/utils' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/w/components/providers/workspace-permissions-provider' import { useFolderStore } from '@/stores/folders/store' @@ -25,8 +23,6 @@ export function CreateMenu({ isCollapsed, isCreatingWorkflow = false, }: CreateMenuProps) { - const [showFolderDialog, setShowFolderDialog] = useState(false) - const [folderName, setFolderName] = useState('') const [isCreating, setIsCreating] = useState(false) const [isOpen, setIsOpen] = useState(false) const [pressTimer, setPressTimer] = useState(null) @@ -61,10 +57,37 @@ export function CreateMenu({ } }, [onCreateWorkflow, isCreatingWorkflow, router, workspaceId]) - const handleCreateFolder = useCallback(() => { + const handleCreateFolder = useCallback(async () => { setIsOpen(false) - setShowFolderDialog(true) - }, []) + + if (isCreating) { + logger.info('Folder creation already in progress, ignoring request') + return + } + + if (!workspaceId) { + logger.error('No workspaceId available for folder creation') + return + } + + try { + setIsCreating(true) + + // Generate folder name using fresh data from API + const folderName = await generateFolderName(workspaceId) + + await createFolder({ + name: folderName, + workspaceId: workspaceId, + }) + + logger.info(`Created folder: ${folderName}`) + } catch (error) { + logger.error('Failed to create folder:', { error }) + } finally { + setIsCreating(false) + } + }, [createFolder, workspaceId]) const handleImportWorkflow = useCallback(() => { setIsOpen(false) @@ -146,30 +169,6 @@ export function CreateMenu({ } }, [pressTimer]) - const handleFolderSubmit = async (e: React.FormEvent) => { - e.preventDefault() - if (!folderName.trim() || !workspaceId) return - - setIsCreating(true) - try { - await createFolder({ - name: folderName.trim(), - workspaceId: workspaceId, - }) - setFolderName('') - setShowFolderDialog(false) - } catch (error) { - logger.error('Failed to create folder:', { error }) - } finally { - setIsCreating(false) - } - } - - const handleCancel = () => { - setFolderName('') - setShowFolderDialog(false) - } - return ( <> @@ -221,11 +220,15 @@ export function CreateMenu({ {userPermissions.canEdit && ( @@ -246,36 +249,6 @@ export function CreateMenu({ disabled={!userPermissions.canEdit} onClose={() => setIsOpen(false)} /> - - {/* Folder creation dialog */} - - - - Create New Folder - -
-
- - setFolderName(e.target.value)} - placeholder='Enter folder name...' - autoFocus - required - /> -
-
- - -
-
-
-
) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-context-menu/folder-context-menu.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-context-menu/folder-context-menu.tsx index bc6432283b..85f061299c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-context-menu/folder-context-menu.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-context-menu/folder-context-menu.tsx @@ -4,17 +4,15 @@ import { useState } from 'react' import { File, Folder, MoreHorizontal, Pencil, Trash2 } from 'lucide-react' import { useParams } from 'next/navigation' import { Button } from '@/components/ui/button' -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' -import { Input } from '@/components/ui/input' -import { Label } from '@/components/ui/label' import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip' import { createLogger } from '@/lib/logs/console-logger' +import { generateSubfolderName } from '@/lib/naming' import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/w/components/providers/workspace-permissions-provider' import { useFolderStore } from '@/stores/folders/store' @@ -37,8 +35,6 @@ export function FolderContextMenu({ onStartEdit, level, }: FolderContextMenuProps) { - const [showSubfolderDialog, setShowSubfolderDialog] = useState(false) - const [subfolderName, setSubfolderName] = useState('') const [isCreating, setIsCreating] = useState(false) const params = useParams() const workspaceId = params.workspaceId as string @@ -46,14 +42,46 @@ export function FolderContextMenu({ // Get user permissions for the workspace const userPermissions = useUserPermissionsContext() - const { createFolder, deleteFolder } = useFolderStore() + const { createFolder, deleteFolder, setExpanded } = useFolderStore() const handleCreateWorkflow = () => { + // Ensure folder is expanded so user can see the new workflow + setExpanded(folderId, true) onCreateWorkflow(folderId) } - const handleCreateSubfolder = () => { - setShowSubfolderDialog(true) + const handleCreateSubfolder = async () => { + if (isCreating) { + logger.info('Subfolder creation already in progress, ignoring request') + return + } + + if (!workspaceId) { + logger.error('No workspaceId available for subfolder creation') + return + } + + try { + setIsCreating(true) + + // Ensure parent folder is expanded so user can see the new subfolder + setExpanded(folderId, true) + + // Generate subfolder name using fresh data from API + const subfolderName = await generateSubfolderName(workspaceId, folderId) + + await createFolder({ + name: subfolderName, + workspaceId: workspaceId, + parentId: folderId, + }) + + logger.info(`Created subfolder: ${subfolderName}`) + } catch (error) { + logger.error('Failed to create subfolder:', { error }) + } finally { + setIsCreating(false) + } } const handleRename = () => { @@ -76,31 +104,6 @@ export function FolderContextMenu({ } } - const handleSubfolderSubmit = async (e: React.FormEvent) => { - e.preventDefault() - if (!subfolderName.trim() || !workspaceId) return - - setIsCreating(true) - try { - await createFolder({ - name: subfolderName.trim(), - workspaceId: workspaceId, - parentId: folderId, - }) - setSubfolderName('') - setShowSubfolderDialog(false) - } catch (error) { - logger.error('Failed to create subfolder:', { error }) - } finally { - setIsCreating(false) - } - } - - const handleCancel = () => { - setSubfolderName('') - setShowSubfolderDialog(false) - } - return ( <> @@ -175,37 +178,6 @@ export function FolderContextMenu({ )} - - {/* Subfolder creation dialog */} - - e.stopPropagation()}> - - Create New Subfolder - -
-
- - setSubfolderName(e.target.value)} - placeholder='Enter folder name...' - maxLength={50} - autoFocus - required - /> -
-
- - -
-
-
-
) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/folder-item.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/folder-item.tsx index 0a6fe0ce61..f426148d13 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/folder-item.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/folder-item.tsx @@ -304,7 +304,7 @@ export function FolderItem({ onChange={(e) => setEditValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleInputBlur} - className='flex-1 border-0 bg-transparent p-0 text-muted-foreground text-sm outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0' + className='min-w-0 flex-1 border-0 bg-transparent p-0 text-muted-foreground text-sm outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0' maxLength={50} disabled={isRenaming} onClick={(e) => e.stopPropagation()} // Prevent folder toggle when clicking input @@ -314,7 +314,9 @@ export function FolderItem({ spellCheck='false' /> ) : ( - {folder.name} + + {folder.name} + )} {!isEditing && ( diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/workflow-item.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/workflow-item.tsx index e17a7eaffa..5945d69ddb 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/workflow-item.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/components/workflow-item.tsx @@ -225,7 +225,7 @@ export function WorkflowItem({ onChange={(e) => setEditValue(e.target.value)} onKeyDown={handleKeyDown} onBlur={handleInputBlur} - className={`flex-1 border-0 bg-transparent p-0 font-medium text-sm outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 ${ + className={`min-w-0 flex-1 border-0 bg-transparent p-0 font-medium text-sm outline-none focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 ${ active && !isDragOver ? 'text-foreground' : 'text-muted-foreground' }`} maxLength={100} @@ -237,7 +237,7 @@ export function WorkflowItem({ spellCheck='false' /> ) : ( - + {workflow.name} {isMarketplace && ' (Preview)'} diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/folder-tree.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/folder-tree.tsx index 2e723f040e..d92732b28a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/folder-tree.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/folder-tree/folder-tree.tsx @@ -567,7 +567,7 @@ export function FolderTree({ marketplaceWorkflows.length === 0 && folderTree.length === 0 && !isCollapsed && ( -
+
No workflows or folders in {workspaceId ? 'this workspace' : 'your account'}. Create one to get started.
diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-selector/workspace-selector.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-selector/workspace-selector.tsx index 3a5548f423..49b32a6cb6 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-selector/workspace-selector.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workspace-selector/workspace-selector.tsx @@ -16,6 +16,7 @@ import { import { Button } from '@/components/ui/button' import { ScrollArea } from '@/components/ui/scroll-area' import { Skeleton } from '@/components/ui/skeleton' +import { isDev } from '@/lib/environment' import { createLogger } from '@/lib/logs/console-logger' import { cn } from '@/lib/utils' import { useUserPermissionsContext } from '../../../providers/workspace-permissions-provider' @@ -251,20 +252,22 @@ export function WorkspaceSelector({ {/* Bottom Actions */}
- {/* Send Invite */} - + {/* Send Invite - Hide in development */} + {!isDev && ( + + )} {/* Create Workspace */}