diff --git a/apps/sim/app/_styles/globals.css b/apps/sim/app/_styles/globals.css index 0c80aef072a..254534f2891 100644 --- a/apps/sim/app/_styles/globals.css +++ b/apps/sim/app/_styles/globals.css @@ -10,7 +10,7 @@ * @see stores/constants.ts for the source of truth */ :root { - --sidebar-width: 248px; /* SIDEBAR_WIDTH.DEFAULT */ + --sidebar-width: 0px; /* 0 outside workspace; blocking script always sets actual value on workspace pages */ --panel-width: 320px; /* PANEL_WIDTH.DEFAULT */ --toolbar-triggers-height: 300px; /* TOOLBAR_TRIGGERS_HEIGHT.DEFAULT */ --editor-connections-height: 172px; /* EDITOR_CONNECTIONS_HEIGHT.DEFAULT */ diff --git a/apps/sim/app/api/copilot/checkpoints/revert/route.test.ts b/apps/sim/app/api/copilot/checkpoints/revert/route.test.ts index fe3246181d4..7fd68b4925e 100644 --- a/apps/sim/app/api/copilot/checkpoints/revert/route.test.ts +++ b/apps/sim/app/api/copilot/checkpoints/revert/route.test.ts @@ -304,7 +304,6 @@ describe('Copilot Checkpoints Revert API Route', () => { loops: {}, parallels: {}, isDeployed: true, - deploymentStatuses: { production: 'deployed' }, }, } @@ -349,7 +348,6 @@ describe('Copilot Checkpoints Revert API Route', () => { loops: {}, parallels: {}, isDeployed: true, - deploymentStatuses: { production: 'deployed' }, lastSaved: 1640995200000, }, }, @@ -370,7 +368,6 @@ describe('Copilot Checkpoints Revert API Route', () => { loops: {}, parallels: {}, isDeployed: true, - deploymentStatuses: { production: 'deployed' }, lastSaved: 1640995200000, }), } @@ -473,7 +470,6 @@ describe('Copilot Checkpoints Revert API Route', () => { edges: undefined, loops: null, parallels: undefined, - deploymentStatuses: null, }, } @@ -508,7 +504,6 @@ describe('Copilot Checkpoints Revert API Route', () => { loops: {}, parallels: {}, isDeployed: false, - deploymentStatuses: {}, lastSaved: 1640995200000, }) }) @@ -768,10 +763,6 @@ describe('Copilot Checkpoints Revert API Route', () => { parallel1: { branches: ['branch1', 'branch2'] }, }, isDeployed: true, - deploymentStatuses: { - production: 'deployed', - staging: 'pending', - }, deployedAt: '2024-01-01T10:00:00.000Z', }, } @@ -816,10 +807,6 @@ describe('Copilot Checkpoints Revert API Route', () => { parallel1: { branches: ['branch1', 'branch2'] }, }, isDeployed: true, - deploymentStatuses: { - production: 'deployed', - staging: 'pending', - }, deployedAt: '2024-01-01T10:00:00.000Z', lastSaved: 1640995200000, }) diff --git a/apps/sim/app/api/copilot/checkpoints/revert/route.ts b/apps/sim/app/api/copilot/checkpoints/revert/route.ts index 2edf7d2dec7..dd73477f5ec 100644 --- a/apps/sim/app/api/copilot/checkpoints/revert/route.ts +++ b/apps/sim/app/api/copilot/checkpoints/revert/route.ts @@ -82,7 +82,6 @@ export async function POST(request: NextRequest) { loops: checkpointState?.loops || {}, parallels: checkpointState?.parallels || {}, isDeployed: checkpointState?.isDeployed || false, - deploymentStatuses: checkpointState?.deploymentStatuses || {}, lastSaved: Date.now(), ...(checkpointState?.deployedAt && checkpointState.deployedAt !== null && diff --git a/apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts b/apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts index 618a1de8f94..a209db29eb4 100644 --- a/apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts +++ b/apps/sim/app/api/workflows/[id]/deployments/[version]/revert/route.ts @@ -79,7 +79,6 @@ export async function POST( loops: deployedState.loops || {}, parallels: deployedState.parallels || {}, lastSaved: Date.now(), - deploymentStatuses: deployedState.deploymentStatuses || {}, }) if (!saveResult.success) { diff --git a/apps/sim/app/api/workflows/[id]/route.ts b/apps/sim/app/api/workflows/[id]/route.ts index 95a6ee43dc7..3d74fe527fa 100644 --- a/apps/sim/app/api/workflows/[id]/route.ts +++ b/apps/sim/app/api/workflows/[id]/route.ts @@ -89,7 +89,6 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ const finalWorkflowData = { ...workflowData, state: { - deploymentStatuses: {}, blocks: normalizedData.blocks, edges: normalizedData.edges, loops: normalizedData.loops, @@ -115,7 +114,6 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ const emptyWorkflowData = { ...workflowData, state: { - deploymentStatuses: {}, blocks: {}, edges: [], loops: {}, diff --git a/apps/sim/app/api/workflows/[id]/variables/route.ts b/apps/sim/app/api/workflows/[id]/variables/route.ts index 7b19a0320a9..1b4cd8ab3b9 100644 --- a/apps/sim/app/api/workflows/[id]/variables/route.ts +++ b/apps/sim/app/api/workflows/[id]/variables/route.ts @@ -8,7 +8,7 @@ import { AuditAction, AuditResourceType, recordAudit } from '@/lib/audit/log' import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid' import { generateRequestId } from '@/lib/core/utils/request' import { authorizeWorkflowByWorkspacePermission } from '@/lib/workflows/utils' -import type { Variable } from '@/stores/panel/variables/types' +import type { Variable } from '@/stores/variables/types' const logger = createLogger('WorkflowVariablesAPI') diff --git a/apps/sim/app/layout.tsx b/apps/sim/app/layout.tsx index 05fd18a7c0b..5863c4405d3 100644 --- a/apps/sim/app/layout.tsx +++ b/apps/sim/app/layout.tsx @@ -90,6 +90,7 @@ export default function RootLayout({ children }: { children: React.ReactNode }) } // Sidebar width + var defaultSidebarWidth = '248px'; try { var stored = localStorage.getItem('sidebar-state'); if (stored) { @@ -108,11 +109,15 @@ export default function RootLayout({ children }: { children: React.ReactNode }) document.documentElement.style.setProperty('--sidebar-width', width + 'px'); } else if (width > maxSidebarWidth) { document.documentElement.style.setProperty('--sidebar-width', maxSidebarWidth + 'px'); + } else { + document.documentElement.style.setProperty('--sidebar-width', defaultSidebarWidth); } } + } else { + document.documentElement.style.setProperty('--sidebar-width', defaultSidebarWidth); } } catch (e) { - // Fallback handled by CSS defaults + document.documentElement.style.setProperty('--sidebar-width', defaultSidebarWidth); } // Panel width and active tab diff --git a/apps/sim/app/templates/components/template-card.tsx b/apps/sim/app/templates/components/template-card.tsx index 15fb0cec4cc..7a2f3d2e105 100644 --- a/apps/sim/app/templates/components/template-card.tsx +++ b/apps/sim/app/templates/components/template-card.tsx @@ -108,8 +108,6 @@ function normalizeWorkflowState(input?: any): WorkflowState | null { lastUpdate: input.lastUpdate, metadata: input.metadata, variables: input.variables, - deploymentStatuses: input.deploymentStatuses, - needsRedeployment: input.needsRedeployment, dragStartPosition: input.dragStartPosition ?? null, } diff --git a/apps/sim/app/workspace/[workspaceId]/components/oauth-modal.tsx b/apps/sim/app/workspace/[workspaceId]/components/oauth-modal.tsx index 5f4e89edd09..7720c84fa3a 100644 --- a/apps/sim/app/workspace/[workspaceId]/components/oauth-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/components/oauth-modal.tsx @@ -16,7 +16,7 @@ import { } from '@/components/emcn' import { client, useSession } from '@/lib/auth/auth-client' import type { OAuthReturnContext } from '@/lib/credentials/client-state' -import { writeOAuthReturnContext } from '@/lib/credentials/client-state' +import { ADD_CONNECTOR_SEARCH_PARAM, writeOAuthReturnContext } from '@/lib/credentials/client-state' import { getCanonicalScopesForProvider, getProviderIdFromServiceId, @@ -59,8 +59,8 @@ type OAuthModalConnectProps = OAuthModalBaseProps & { workspaceId: string credentialCount: number } & ( - | { workflowId: string; knowledgeBaseId?: never } - | { workflowId?: never; knowledgeBaseId: string } + | { workflowId: string; knowledgeBaseId?: never; connectorType?: never } + | { workflowId?: never; knowledgeBaseId: string; connectorType?: string } ) interface OAuthModalReauthorizeProps extends OAuthModalBaseProps { @@ -81,6 +81,7 @@ export function OAuthModal(props: OAuthModalProps) { const workspaceId = isConnect ? props.workspaceId : '' const workflowId = isConnect ? props.workflowId : undefined const knowledgeBaseId = isConnect ? props.knowledgeBaseId : undefined + const connectorType = isConnect ? props.connectorType : undefined const toolName = !isConnect ? props.toolName : '' const requiredScopes = !isConnect ? (props.requiredScopes ?? EMPTY_SCOPES) : EMPTY_SCOPES const newScopes = !isConnect ? (props.newScopes ?? EMPTY_SCOPES) : EMPTY_SCOPES @@ -172,7 +173,7 @@ export function OAuthModal(props: OAuthModalProps) { } const returnContext: OAuthReturnContext = knowledgeBaseId - ? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId } + ? { ...baseContext, origin: 'kb-connectors' as const, knowledgeBaseId, connectorType } : { ...baseContext, origin: 'workflow' as const, workflowId: workflowId! } writeOAuthReturnContext(returnContext) @@ -205,7 +206,11 @@ export function OAuthModal(props: OAuthModalProps) { return } - await client.oauth2.link({ providerId, callbackURL: window.location.href }) + const callbackURL = new URL(window.location.href) + if (connectorType) { + callbackURL.searchParams.set(ADD_CONNECTOR_SEARCH_PARAM, connectorType) + } + await client.oauth2.link({ providerId, callbackURL: callbackURL.toString() }) handleClose() } catch (err) { logger.error('Failed to initiate OAuth connection', { error: err }) diff --git a/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx b/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx deleted file mode 100644 index c64c3a39e27..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/files/[fileId]/view/loading.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Loader2 } from 'lucide-react' - -export default function FileViewLoading() { - return ( -
- -
- ) -} diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index 5fa965d9abe..88866a77000 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -1407,17 +1407,6 @@ export function useChat( const output = tc.result?.output as Record | undefined const deployedWorkflowId = (output?.workflowId as string) ?? undefined if (deployedWorkflowId && typeof output?.isDeployed === 'boolean') { - const isDeployed = output.isDeployed as boolean - const serverDeployedAt = output.deployedAt - ? new Date(output.deployedAt as string) - : undefined - useWorkflowRegistry - .getState() - .setDeploymentStatus( - deployedWorkflowId, - isDeployed, - isDeployed ? (serverDeployedAt ?? new Date()) : undefined - ) queryClient.invalidateQueries({ queryKey: deploymentKeys.info(deployedWorkflowId), }) diff --git a/apps/sim/app/workspace/[workspaceId]/home/loading.tsx b/apps/sim/app/workspace/[workspaceId]/home/loading.tsx deleted file mode 100644 index 98b656ef94e..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/home/loading.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Skeleton } from '@/components/emcn' - -const SKELETON_LINE_COUNT = 4 - -export default function HomeLoading() { - return ( -
-
-
- {Array.from({ length: SKELETON_LINE_COUNT }).map((_, i) => ( - - ))} -
-
-
-
- -
-
-
- ) -} diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx index eb5823f9100..e81701bac4d 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx @@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { createLogger } from '@sim/logger' import { format } from 'date-fns' import { AlertCircle, Loader2, Pencil, Plus, Tag, X } from 'lucide-react' -import { useParams, useRouter } from 'next/navigation' +import { useParams, usePathname, useRouter, useSearchParams } from 'next/navigation' import { usePostHog } from 'posthog-js/react' import { Badge, @@ -25,6 +25,7 @@ import { import { Database, DatabaseX } from '@/components/emcn/icons' import { SearchHighlight } from '@/components/ui/search-highlight' import { cn } from '@/lib/core/utils/cn' +import { ADD_CONNECTOR_SEARCH_PARAM } from '@/lib/credentials/client-state' import { ALL_TAG_SLOTS, type AllTagSlot, getFieldTypeForSlot } from '@/lib/knowledge/constants' import type { DocumentSortField, SortOrder } from '@/lib/knowledge/documents/types' import { type FilterFieldType, getOperatorsForFieldType } from '@/lib/knowledge/filters/types' @@ -192,6 +193,10 @@ export function KnowledgeBase({ }: KnowledgeBaseProps) { const params = useParams() const workspaceId = propWorkspaceId || (params.workspaceId as string) + const router = useRouter() + const searchParams = useSearchParams() + const pathname = usePathname() + const addConnectorParam = searchParams.get(ADD_CONNECTOR_SEARCH_PARAM) const posthog = usePostHog() useEffect(() => { @@ -278,7 +283,29 @@ export function KnowledgeBase({ const [contextMenuDocument, setContextMenuDocument] = useState(null) const [showRenameModal, setShowRenameModal] = useState(false) const [documentToRename, setDocumentToRename] = useState(null) - const [showAddConnectorModal, setShowAddConnectorModal] = useState(false) + const showAddConnectorModal = addConnectorParam != null + const searchParamsRef = useRef(searchParams) + searchParamsRef.current = searchParams + const updateAddConnectorParam = useCallback( + (value: string | null) => { + const current = searchParamsRef.current + const currentValue = current.get(ADD_CONNECTOR_SEARCH_PARAM) + if (value === currentValue || (value === null && currentValue === null)) return + const next = new URLSearchParams(current.toString()) + if (value === null) { + next.delete(ADD_CONNECTOR_SEARCH_PARAM) + } else { + next.set(ADD_CONNECTOR_SEARCH_PARAM, value) + } + const qs = next.toString() + router.replace(qs ? `${pathname}?${qs}` : pathname, { scroll: false }) + }, + [pathname, router] + ) + const setShowAddConnectorModal = useCallback( + (open: boolean) => updateAddConnectorParam(open ? '' : null), + [updateAddConnectorParam] + ) const { isOpen: isContextMenuOpen, @@ -340,8 +367,6 @@ export function KnowledgeBase({ prevHadSyncingRef.current = hasSyncingConnectors }, [hasSyncingConnectors, refreshKnowledgeBase, refreshDocuments]) - const router = useRouter() - const knowledgeBaseName = knowledgeBase?.name || passedKnowledgeBaseName || 'Knowledge Base' const error = knowledgeBaseError || documentsError @@ -1254,7 +1279,13 @@ export function KnowledgeBase({ /> {showAddConnectorModal && ( - + )} {documentToRename && ( diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx index 223091360bc..ce218132643 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx @@ -44,14 +44,22 @@ const CONNECTOR_ENTRIES = Object.entries(CONNECTOR_REGISTRY) interface AddConnectorModalProps { open: boolean onOpenChange: (open: boolean) => void + onConnectorTypeChange?: (connectorType: string | null) => void knowledgeBaseId: string + initialConnectorType?: string | null } type Step = 'select-type' | 'configure' -export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddConnectorModalProps) { - const [step, setStep] = useState('select-type') - const [selectedType, setSelectedType] = useState(null) +export function AddConnectorModal({ + open, + onOpenChange, + onConnectorTypeChange, + knowledgeBaseId, + initialConnectorType, +}: AddConnectorModalProps) { + const [step, setStep] = useState(() => (initialConnectorType ? 'configure' : 'select-type')) + const [selectedType, setSelectedType] = useState(initialConnectorType ?? null) const [sourceConfig, setSourceConfig] = useState>({}) const [syncInterval, setSyncInterval] = useState(1440) const [selectedCredentialId, setSelectedCredentialId] = useState(null) @@ -151,6 +159,7 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo setError(null) setSearchTerm('') setStep('configure') + onConnectorTypeChange?.(type) } const handleFieldChange = useCallback( @@ -286,7 +295,10 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo @@ -565,6 +577,7 @@ export function AddConnectorModal({ open, onOpenChange, knowledgeBaseId }: AddCo workspaceId={workspaceId} knowledgeBaseId={knowledgeBaseId} credentialCount={credentials.length} + connectorType={selectedType ?? undefined} /> )} diff --git a/apps/sim/app/workspace/[workspaceId]/task/[taskId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/task/[taskId]/loading.tsx deleted file mode 100644 index acc047d3a4b..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/task/[taskId]/loading.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Loader2 } from 'lucide-react' - -export default function TaskLoading() { - return ( -
-
-
- -
-
-
- ) -} diff --git a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx index 8671a709271..a93cb915c69 100644 --- a/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx +++ b/apps/sim/app/workspace/[workspaceId]/templates/components/template-card.tsx @@ -111,8 +111,6 @@ function normalizeWorkflowState(input?: any): WorkflowState | null { lastUpdate: input.lastUpdate, metadata: input.metadata, variables: input.variables, - deploymentStatuses: input.deploymentStatuses, - needsRedeployment: input.needsRedeployment, dragStartPosition: input.dragStartPosition ?? null, } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx index f6ce4e95c2b..4133728b666 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx @@ -40,7 +40,6 @@ import { useWorkflowMap } from '@/hooks/queries/workflows' import { useWorkspaceSettings } from '@/hooks/queries/workspace' import { usePermissionConfig } from '@/hooks/use-permission-config' import { useSettingsNavigation } from '@/hooks/use-settings-navigation' -import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { mergeSubblockState } from '@/stores/workflows/utils' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import type { WorkflowState } from '@/stores/workflows/workflow/types' @@ -90,10 +89,7 @@ export function DeployModal({ const params = useParams() const workspaceId = params?.workspaceId as string const { navigateToSettings } = useSettingsNavigation() - const deploymentStatus = useWorkflowRegistry((state) => - state.getWorkflowDeploymentStatus(workflowId) - ) - const isDeployed = deploymentStatus?.isDeployed ?? isDeployedProp + const isDeployed = isDeployedProp const { data: workflowMap = {} } = useWorkflowMap(workspaceId) const workflowMetadata = workflowId ? workflowMap[workflowId] : undefined const workflowWorkspaceId = workflowMetadata?.workspaceId ?? null @@ -381,8 +377,6 @@ export function DeployModal({ invalidateDeploymentQueries(queryClient, workflowId) - useWorkflowRegistry.getState().setWorkflowNeedsRedeployment(workflowId, false) - if (chatSuccessTimeoutRef.current) { clearTimeout(chatSuccessTimeoutRef.current) } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx index 78081e6eeac..24a0975325c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx @@ -9,7 +9,7 @@ import { useDeployment, } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks' import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow' -import { useDeployedWorkflowState } from '@/hooks/queries/deployments' +import { useDeployedWorkflowState, useDeploymentInfo } from '@/hooks/queries/deployments' import type { WorkspaceUserPermissions } from '@/hooks/use-user-permissions' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' @@ -25,10 +25,10 @@ export function Deploy({ activeWorkflowId, userPermissions, className }: DeployP const isRegistryLoading = hydrationPhase === 'idle' || hydrationPhase === 'state-loading' const { hasBlocks } = useCurrentWorkflow() - const deploymentStatus = useWorkflowRegistry((state) => - state.getWorkflowDeploymentStatus(activeWorkflowId) - ) - const isDeployed = deploymentStatus?.isDeployed || false + const { data: deploymentInfo } = useDeploymentInfo(activeWorkflowId, { + enabled: !isRegistryLoading, + }) + const isDeployed = deploymentInfo?.isDeployed ?? false const isDeployedStateEnabled = Boolean(activeWorkflowId) && isDeployed && !isRegistryLoading const { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-change-detection.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-change-detection.ts index 7187bf7fc95..41b394b8a77 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-change-detection.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-change-detection.ts @@ -1,7 +1,7 @@ import { useMemo } from 'react' import { hasWorkflowChanged } from '@/lib/workflows/comparison' import { mergeSubblockStateWithValues } from '@/lib/workflows/subblocks' -import { useVariablesStore } from '@/stores/panel/variables/store' +import { useVariablesStore } from '@/stores/variables/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import type { WorkflowState } from '@/stores/workflows/workflow/types' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx index 68256664a9c..620d38c2e83 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx @@ -31,8 +31,8 @@ import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/ import { getBlock } from '@/blocks' import type { BlockConfig } from '@/blocks/types' import { normalizeName } from '@/executor/constants' -import type { Variable } from '@/stores/panel' -import { useVariablesStore } from '@/stores/panel' +import { useVariablesStore } from '@/stores/variables/store' +import type { Variable } from '@/stores/variables/types' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx index 3cb55879312..c71a48f77bc 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/variables-input/variables-input.tsx @@ -19,8 +19,8 @@ import { } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown' import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value' import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes' -import type { Variable } from '@/stores/panel' -import { useVariablesStore } from '@/stores/panel' +import { useVariablesStore } from '@/stores/variables/store' +import type { Variable } from '@/stores/variables/types' interface VariableAssignment { id: string diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-selector-setup.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-selector-setup.ts index 3986164f0fd..555496c899a 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-selector-setup.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-selector-setup.ts @@ -5,8 +5,8 @@ import { useParams } from 'next/navigation' import { SELECTOR_CONTEXT_FIELDS } from '@/lib/workflows/subblocks/context' import type { SubBlockConfig } from '@/blocks/types' import { extractEnvVarName, isEnvVarReference, isReference } from '@/executor/constants' +import { usePersonalEnvironment } from '@/hooks/queries/environment' import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types' -import { useEnvironmentStore } from '@/stores/settings/environment' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { useDependsOnGate } from './use-depends-on-gate' import { useSubBlockValue } from './use-sub-block-value' @@ -32,7 +32,7 @@ export function useSelectorSetup( const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) const workflowId = (params?.workflowId as string) || activeWorkflowId || '' - const envVariables = useEnvironmentStore((s) => s.variables) + const { data: envVariables = {} } = usePersonalEnvironment() const { finalDisabled, dependencyValues, canonicalIndex } = useDependsOnGate( blockId, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx index 0f349d1b85f..4c5ecbbc570 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/panel.tsx @@ -63,7 +63,8 @@ import { useSettingsNavigation } from '@/hooks/use-settings-navigation' import { useChatStore } from '@/stores/chat/store' import { useNotificationStore } from '@/stores/notifications/store' import type { ChatContext, PanelTab } from '@/stores/panel' -import { usePanelStore, useVariablesStore as usePanelVariablesStore } from '@/stores/panel' +import { usePanelStore } from '@/stores/panel' +import { useVariablesModalStore } from '@/stores/variables/modal' import { useVariablesStore } from '@/stores/variables/store' import { useWorkflowDiffStore } from '@/stores/workflow-diff/store' import { captureBaselineSnapshot } from '@/stores/workflow-diff/utils' @@ -205,7 +206,7 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel setIsChatOpen: state.setIsChatOpen, })) ) - const { isOpen: isVariablesOpen, setIsOpen: setVariablesOpen } = useVariablesStore( + const { isOpen: isVariablesOpen, setIsOpen: setVariablesOpen } = useVariablesModalStore( useShallow((state) => ({ isOpen: state.isOpen, setIsOpen: state.setIsOpen, @@ -410,6 +411,17 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel setHasHydrated(true) }, [setHasHydrated]) + useEffect(() => { + const handler = (e: Event) => { + const message = (e as CustomEvent<{ message: string }>).detail?.message + if (!message) return + setActiveTab('copilot') + copilotSendMessage(message) + } + window.addEventListener('mothership-send-message', handler) + return () => window.removeEventListener('mothership-send-message', handler) + }, [setActiveTab, copilotSendMessage]) + /** * Handles tab click events */ @@ -482,7 +494,7 @@ export const Panel = memo(function Panel({ workspaceId: propWorkspaceId }: Panel throw new Error('No workflow state found') } - const workflowVariables = usePanelVariablesStore + const workflowVariables = useVariablesStore .getState() .getVariablesByWorkflowId(activeWorkflowId) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx index 7c182e285c6..a5fb1615c45 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/variables/variables.tsx @@ -27,15 +27,15 @@ import { usePreventZoom, } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks' import { useCollaborativeWorkflow } from '@/hooks/use-collaborative-workflow' -import { useVariablesStore as usePanelVariablesStore } from '@/stores/panel' import { getVariablesPosition, MAX_VARIABLES_HEIGHT, MAX_VARIABLES_WIDTH, MIN_VARIABLES_HEIGHT, MIN_VARIABLES_WIDTH, - useVariablesStore, -} from '@/stores/variables/store' + useVariablesModalStore, +} from '@/stores/variables/modal' +import { useVariablesStore } from '@/stores/variables/store' import type { Variable } from '@/stores/variables/types' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' @@ -96,7 +96,7 @@ export function Variables() { const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) const { isOpen, position, width, height, setIsOpen, setPosition, setDimensions } = - useVariablesStore( + useVariablesModalStore( useShallow((s) => ({ isOpen: s.isOpen, position: s.position, @@ -108,7 +108,7 @@ export function Variables() { })) ) - const variables = usePanelVariablesStore((s) => s.variables) + const variables = useVariablesStore((s) => s.variables) const { collaborativeUpdateVariable, collaborativeAddVariable, collaborativeDeleteVariable } = useCollaborativeWorkflow() diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx index b7b04f38bb2..bb676157396 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx @@ -48,7 +48,7 @@ import { useSkills } from '@/hooks/queries/skills' import { useTablesList } from '@/hooks/queries/tables' import { useWorkflowMap } from '@/hooks/queries/workflows' import { useSelectorDisplayName } from '@/hooks/use-selector-display-name' -import { useVariablesStore } from '@/stores/panel' +import { useVariablesStore } from '@/stores/variables/store' import { useSubBlockStore } from '@/stores/workflows/subblock/store' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import { wouldCreateCycle } from '@/stores/workflows/workflow/utils' diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow.ts index a74573b07b0..85143170e5c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-current-workflow.ts @@ -2,7 +2,6 @@ import { useMemo } from 'react' import type { Edge } from 'reactflow' import { useShallow } from 'zustand/react/shallow' import { useWorkflowDiffStore } from '@/stores/workflow-diff/store' -import type { DeploymentStatus } from '@/stores/workflows/registry/types' import { useWorkflowStore } from '@/stores/workflows/workflow/store' import type { BlockState, Loop, Parallel, WorkflowState } from '@/stores/workflows/workflow/types' @@ -16,8 +15,6 @@ export interface CurrentWorkflow { loops: Record parallels: Record lastSaved?: number - deploymentStatuses?: Record - needsRedeployment?: boolean // Mode information isDiffMode: boolean @@ -48,8 +45,6 @@ export function useCurrentWorkflow(): CurrentWorkflow { loops: state.loops, parallels: state.parallels, lastSaved: state.lastSaved, - deploymentStatuses: state.deploymentStatuses, - needsRedeployment: state.needsRedeployment, })) ) @@ -78,8 +73,6 @@ export function useCurrentWorkflow(): CurrentWorkflow { loops: activeWorkflow.loops || {}, parallels: activeWorkflow.parallels || {}, lastSaved: activeWorkflow.lastSaved, - deploymentStatuses: activeWorkflow.deploymentStatuses, - needsRedeployment: activeWorkflow.needsRedeployment, // Mode information - update to reflect ready state isDiffMode: hasActiveDiff && isShowingDiff, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 2e8e4b8ce4a..8b9ca1fa0a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -36,8 +36,6 @@ import { useExecutionStream } from '@/hooks/use-execution-stream' import { WorkflowValidationError } from '@/serializer' import { useCurrentWorkflowExecution, useExecutionStore } from '@/stores/execution' import { useNotificationStore } from '@/stores/notifications' -import { useVariablesStore } from '@/stores/panel' -import { useEnvironmentStore } from '@/stores/settings/environment' import { clearExecutionPointer, consolePersistence, @@ -45,6 +43,7 @@ import { saveExecutionPointer, useTerminalConsoleStore, } from '@/stores/terminal' +import { useVariablesStore } from '@/stores/variables/store' import { useWorkflowDiffStore } from '@/stores/workflow-diff' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { mergeSubblockState } from '@/stores/workflows/utils' @@ -120,7 +119,6 @@ export function useWorkflowExecution() { })) ) const hasHydrated = useTerminalConsoleStore((s) => s._hasHydrated) - const getAllVariables = useEnvironmentStore((s) => s.getAllVariables) const { getVariablesByWorkflowId, variables } = useVariablesStore( useShallow((s) => ({ getVariablesByWorkflowId: s.getVariablesByWorkflowId, @@ -744,7 +742,6 @@ export function useWorkflowExecution() { activeWorkflowId, currentWorkflow, toggleConsole, - getAllVariables, getVariablesByWorkflowId, setIsExecuting, setIsDebugging, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx deleted file mode 100644 index 6a65da73c7e..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/loading.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Loader2 } from 'lucide-react' - -export default function WorkflowLoading() { - return ( -
-
- -
-
- ) -} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils.ts index 3b4d5a73ee5..69a15ec7d67 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/utils/auto-layout-utils.ts @@ -124,8 +124,7 @@ export async function applyAutoLayoutAndUpdateStore( try { useWorkflowStore.getState().updateLastSaved() - const { deploymentStatuses, needsRedeployment, dragStartPosition, ...stateToSave } = - newWorkflowState + const { dragStartPosition, ...stateToSave } = newWorkflowState const cleanedWorkflowState = { ...stateToSave, diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx index 57fd7a41706..0a8c196c60c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/workflow.tsx @@ -85,7 +85,7 @@ import { useSearchModalStore } from '@/stores/modals/search/store' import { useNotificationStore } from '@/stores/notifications' import { usePanelEditorStore } from '@/stores/panel' import { useUndoRedoStore } from '@/stores/undo-redo' -import { useVariablesStore } from '@/stores/variables/store' +import { useVariablesModalStore } from '@/stores/variables/modal' import { useWorkflowDiffStore } from '@/stores/workflow-diff/store' import { useWorkflowRegistry } from '@/stores/workflows/registry/store' import { getUniqueBlockName, prepareBlockState } from '@/stores/workflows/utils' @@ -265,7 +265,7 @@ const WorkflowContent = React.memo( const { fitViewToBounds, getViewportCenter } = useCanvasViewport(reactFlowInstance, { embedded, }) - const { emitCursorUpdate } = useSocket() + const { emitCursorUpdate, joinWorkflow, leaveWorkflow } = useSocket() useDynamicHandleRefresh() const workspaceId = propWorkspaceId || (params.workspaceId as string) @@ -273,6 +273,14 @@ const WorkflowContent = React.memo( const addNotification = useNotificationStore((state) => state.addNotification) + useEffect(() => { + if (!embedded || !workflowIdParam) return + joinWorkflow(workflowIdParam) + return () => { + leaveWorkflow() + } + }, [embedded, workflowIdParam, joinWorkflow, leaveWorkflow]) + useOAuthReturnForWorkflow(workflowIdParam) const { @@ -337,7 +345,7 @@ const WorkflowContent = React.memo( autoConnectRef.current = isAutoConnectEnabled // Panel open states for context menu - const isVariablesOpen = useVariablesStore((state) => state.isOpen) + const isVariablesOpen = useVariablesModalStore((state) => state.isOpen) const isChatOpen = useChatStore((state) => state.isChatOpen) const snapGrid: [number, number] = useMemo( @@ -1374,7 +1382,7 @@ const WorkflowContent = React.memo( }, [router, workspaceId, workflowIdParam]) const handleContextToggleVariables = useCallback(() => { - const { isOpen, setIsOpen } = useVariablesStore.getState() + const { isOpen, setIsOpen } = useVariablesModalStore.getState() setIsOpen(!isOpen) }, []) @@ -2144,12 +2152,9 @@ const WorkflowContent = React.memo( const handleCanvasPointerMove = useCallback( (event: React.PointerEvent) => { - const target = event.currentTarget as HTMLElement - const bounds = target.getBoundingClientRect() - const position = screenToFlowPosition({ - x: event.clientX - bounds.left, - y: event.clientY - bounds.top, + x: event.clientX, + y: event.clientY, }) emitCursorUpdate(position) diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx index f2c78c680c3..f6c0f9c5b5f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/preview/components/preview-workflow/components/block/block.tsx @@ -13,7 +13,7 @@ import { DELETED_WORKFLOW_LABEL } from '@/app/workspace/[workspaceId]/logs/utils import { getDisplayValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block' import { getBlock } from '@/blocks' import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types' -import { useVariablesStore } from '@/stores/panel/variables/store' +import { useVariablesStore } from '@/stores/variables/store' import type { WorkflowMetadata } from '@/stores/workflows/registry/types' /** Execution status for blocks in preview mode */ diff --git a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx index 23c34bfdea4..51a9533e79d 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/search-modal/search-modal.tsx @@ -343,7 +343,11 @@ export function SearchModal({ '-translate-x-1/2 fixed top-[15%] z-50 w-[500px] rounded-xl border-[4px] border-black/[0.06] bg-[var(--bg)] shadow-[0_24px_80px_-16px_rgba(0,0,0,0.15)] dark:border-white/[0.06] dark:shadow-[0_24px_80px_-16px_rgba(0,0,0,0.4)]', open ? 'visible opacity-100' : 'invisible opacity-0' )} - style={{ left: 'calc(var(--sidebar-width) / 2 + 50%)' }} + style={{ + left: isOnWorkflowPage + ? 'calc(50% + (var(--sidebar-width) - var(--panel-width)) / 2)' + : 'calc(var(--sidebar-width) / 2 + 50%)', + }} >
diff --git a/apps/sim/app/workspace/[workspaceId]/w/loading.tsx b/apps/sim/app/workspace/[workspaceId]/w/loading.tsx deleted file mode 100644 index 9bb97126c6a..00000000000 --- a/apps/sim/app/workspace/[workspaceId]/w/loading.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { Loader2 } from 'lucide-react' - -export default function WorkflowsLoading() { - return ( -
-
- -
-
- ) -} diff --git a/apps/sim/app/workspace/providers/socket-provider.tsx b/apps/sim/app/workspace/providers/socket-provider.tsx index 6a27bd3a664..91a415df132 100644 --- a/apps/sim/app/workspace/providers/socket-provider.tsx +++ b/apps/sim/app/workspace/providers/socket-provider.tsx @@ -90,6 +90,7 @@ interface SocketContextType { onSelectionUpdate: (handler: (data: any) => void) => void onWorkflowDeleted: (handler: (data: any) => void) => void onWorkflowReverted: (handler: (data: any) => void) => void + onWorkflowUpdated: (handler: (data: any) => void) => void onOperationConfirmed: (handler: (data: any) => void) => void onOperationFailed: (handler: (data: any) => void) => void } @@ -118,6 +119,7 @@ const SocketContext = createContext({ onSelectionUpdate: () => {}, onWorkflowDeleted: () => {}, onWorkflowReverted: () => {}, + onWorkflowUpdated: () => {}, onOperationConfirmed: () => {}, onOperationFailed: () => {}, }) @@ -155,6 +157,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) { selectionUpdate?: (data: any) => void workflowDeleted?: (data: any) => void workflowReverted?: (data: any) => void + workflowUpdated?: (data: any) => void operationConfirmed?: (data: any) => void operationFailed?: (data: any) => void }>({}) @@ -334,7 +337,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) { socketInstance.on('join-workflow-success', ({ workflowId, presenceUsers }) => { isRejoiningRef.current = false // Ignore stale success responses from previous navigation - if (workflowId !== urlWorkflowIdRef.current) { + if (urlWorkflowIdRef.current && workflowId !== urlWorkflowIdRef.current) { logger.debug(`Ignoring stale join-workflow-success for ${workflowId}`) return } @@ -382,6 +385,11 @@ export function SocketProvider({ children, user }: SocketProviderProps) { eventHandlers.current.workflowReverted?.(data) }) + socketInstance.on('workflow-updated', (data) => { + logger.info(`Workflow ${data.workflowId} has been updated externally`) + eventHandlers.current.workflowUpdated?.(data) + }) + const rehydrateWorkflowStores = async (workflowId: string, workflowState: any) => { const [ { useOperationQueueStore }, @@ -424,7 +432,6 @@ export function SocketProvider({ children, user }: SocketProviderProps) { loops: workflowState.loops || {}, parallels: workflowState.parallels || {}, lastSaved: workflowState.lastSaved || Date.now(), - deploymentStatuses: workflowState.deploymentStatuses || {}, }) useSubBlockStore.setState((state: any) => ({ @@ -804,6 +811,10 @@ export function SocketProvider({ children, user }: SocketProviderProps) { eventHandlers.current.workflowReverted = handler }, []) + const onWorkflowUpdated = useCallback((handler: (data: any) => void) => { + eventHandlers.current.workflowUpdated = handler + }, []) + const onOperationConfirmed = useCallback((handler: (data: any) => void) => { eventHandlers.current.operationConfirmed = handler }, []) @@ -837,6 +848,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) { onSelectionUpdate, onWorkflowDeleted, onWorkflowReverted, + onWorkflowUpdated, onOperationConfirmed, onOperationFailed, }), @@ -864,6 +876,7 @@ export function SocketProvider({ children, user }: SocketProviderProps) { onSelectionUpdate, onWorkflowDeleted, onWorkflowReverted, + onWorkflowUpdated, onOperationConfirmed, onOperationFailed, ] diff --git a/apps/sim/components/emcn/components/modal/modal.tsx b/apps/sim/components/emcn/components/modal/modal.tsx index 2932bb2d5c9..f9afb95b6d6 100644 --- a/apps/sim/components/emcn/components/modal/modal.tsx +++ b/apps/sim/components/emcn/components/modal/modal.tsx @@ -40,6 +40,7 @@ import * as React from 'react' import * as DialogPrimitive from '@radix-ui/react-dialog' import * as TabsPrimitive from '@radix-ui/react-tabs' import { X } from 'lucide-react' +import { usePathname } from 'next/navigation' import { cn } from '@/lib/core/utils/cn' import { Button } from '../button/button' @@ -50,13 +51,6 @@ import { Button } from '../button/button' const ANIMATION_CLASSES = 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:animate-out data-[state=open]:animate-in motion-reduce:animate-none' -/** - * Modal content animation classes. - * We keep only the slide animations (no zoom) to stabilize positioning while avoiding scale effects. - */ -const CONTENT_ANIMATION_CLASSES = - 'data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[50%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[50%] motion-reduce:animate-none' - /** * Root modal component. Manages open state. */ @@ -145,6 +139,8 @@ const ModalContent = React.forwardRef< ModalContentProps >(({ className, children, showClose = true, size = 'md', style, ...props }, ref) => { const [isInteractionReady, setIsInteractionReady] = React.useState(false) + const pathname = usePathname() + const isWorkflowPage = pathname?.includes('/w/') ?? false React.useEffect(() => { const timer = setTimeout(() => setIsInteractionReady(true), 100) @@ -157,14 +153,15 @@ const ModalContent = React.forwardRef<