mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-28 03:00:29 -04:00
fix: added greptile changes
This commit is contained in:
@@ -68,12 +68,12 @@ export function DeployedWorkflowCard({
|
||||
.filter(([_, block]) => block && block.type) // Filter out invalid blocks
|
||||
.map(([id, block]) => {
|
||||
// Deep clone the block to avoid any reference sharing
|
||||
const clonedBlock = JSON.parse(JSON.stringify(block));
|
||||
const clonedBlock = structuredClone(block);
|
||||
return [id, clonedBlock];
|
||||
})
|
||||
),
|
||||
edges: workflowToShow.edges ? JSON.parse(JSON.stringify(workflowToShow.edges)) : [],
|
||||
loops: workflowToShow.loops ? JSON.parse(JSON.stringify(workflowToShow.loops)) : {},
|
||||
edges: workflowToShow.edges ? structuredClone(workflowToShow.edges) : [],
|
||||
loops: workflowToShow.loops ? structuredClone(workflowToShow.loops) : {},
|
||||
_metadata: {
|
||||
...(workflowToShow._metadata || {}),
|
||||
workflowId: activeWorkflowId,
|
||||
@@ -87,7 +87,7 @@ export function DeployedWorkflowCard({
|
||||
|
||||
// Generate a unique key for the workflow preview
|
||||
const previewKey = useMemo(() => {
|
||||
return `${showingDeployed ? 'deployed' : 'current'}-preview-${activeWorkflowId}-${Date.now()}`;
|
||||
return `${showingDeployed ? 'deployed' : 'current'}-preview-${activeWorkflowId}}`;
|
||||
}, [showingDeployed, activeWorkflowId]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -53,30 +53,17 @@ export function DeployedWorkflowModal({
|
||||
deployedWorkflowState,
|
||||
}: DeployedWorkflowModalProps) {
|
||||
const [showRevertDialog, setShowRevertDialog] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const { revertToDeployedState } = useWorkflowStore()
|
||||
const activeWorkflowId = useWorkflowRegistry((state) => state.activeWorkflowId)
|
||||
|
||||
// Add instance ID to track component lifecycle
|
||||
const instanceId = useRef(Date.now());
|
||||
const modalOpenCount = useRef(0);
|
||||
|
||||
// Keep track of the original deployed state when modal opens
|
||||
const initialDeployedStateRef = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
modalOpenCount.current += 1;
|
||||
|
||||
// Store the initial deployed state when modal first opens
|
||||
if (!initialDeployedStateRef.current) {
|
||||
initialDeployedStateRef.current = deployedWorkflowState;
|
||||
}
|
||||
} else if (initialDeployedStateRef.current) {
|
||||
// Reset the initial state reference when modal closes
|
||||
initialDeployedStateRef.current = null;
|
||||
}
|
||||
}, [isOpen, deployedWorkflowState, activeWorkflowId]);
|
||||
}, [isOpen]);
|
||||
|
||||
// Get current workflow state to compare with deployed state
|
||||
const currentWorkflowState = useWorkflowStore((state) => ({
|
||||
@@ -96,7 +83,7 @@ export function DeployedWorkflowModal({
|
||||
.filter(([_, block]) => block && block.type)
|
||||
.map(([id, block]) => {
|
||||
// Deep clone the block to avoid any reference sharing
|
||||
return [id, JSON.parse(JSON.stringify(block))];
|
||||
return [id, structuredClone(block)];
|
||||
})
|
||||
),
|
||||
edges: currentWorkflowState.edges ? [...currentWorkflowState.edges] : [],
|
||||
@@ -154,7 +141,7 @@ export function DeployedWorkflowModal({
|
||||
.filter(([_, block]) => block && block.type)
|
||||
.map(([id, block]) => {
|
||||
// Deep clone the block to avoid any reference sharing
|
||||
return [id, JSON.parse(JSON.stringify(block))];
|
||||
return [id, structuredClone(block)];
|
||||
})
|
||||
),
|
||||
edges: deployedWorkflowState.edges ? [...deployedWorkflowState.edges] : [],
|
||||
@@ -189,17 +176,10 @@ export function DeployedWorkflowModal({
|
||||
<DialogTitle>Deployed Workflow</DialogTitle>
|
||||
</DialogHeader>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center items-center h-[500px]">
|
||||
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
) : (
|
||||
<DeployedWorkflowCard
|
||||
currentWorkflowState={sanitizedCurrentState}
|
||||
deployedWorkflowState={sanitizedDeployedState}
|
||||
/>
|
||||
)}
|
||||
<DeployedWorkflowCard
|
||||
currentWorkflowState={sanitizedCurrentState}
|
||||
deployedWorkflowState={sanitizedDeployedState}
|
||||
/>
|
||||
|
||||
<div className="flex justify-between mt-6">
|
||||
{needsRedeployment && (
|
||||
|
||||
@@ -1,25 +1,19 @@
|
||||
'use client'
|
||||
|
||||
<<<<<<< HEAD
|
||||
import { useEffect, useState } from 'react'
|
||||
=======
|
||||
import { useState, useEffect, useRef } from 'react'
|
||||
>>>>>>> 2d314bcc (fix: deployed state preview persists across workflows)
|
||||
import { Loader2, Rocket } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { WorkflowState } from '@/stores/workflows/workflow/types'
|
||||
import { DeployModal } from '../deploy-modal/deploy-modal'
|
||||
|
||||
const _logger = createLogger('DeploymentControls')
|
||||
|
||||
interface DeploymentControlsProps {
|
||||
activeWorkflowId: string | null
|
||||
needsRedeployment: boolean
|
||||
setNeedsRedeployment: (value: boolean) => void
|
||||
deployedState: any
|
||||
deployedState: WorkflowState | null
|
||||
isLoadingDeployedState: boolean
|
||||
refetchDeployedState: () => Promise<void>
|
||||
}
|
||||
@@ -47,65 +41,24 @@ export function DeploymentControls({
|
||||
const [isDeploying, _setIsDeploying] = useState(false)
|
||||
const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
|
||||
// Add a ref to track the last seen workflow ID and deployed state
|
||||
// Track the last seen workflow ID
|
||||
const lastWorkflowIdRef = useRef<string | null>(null)
|
||||
const lastDeployedStateRef = useRef<any>(null)
|
||||
|
||||
// Log when workflow ID changes
|
||||
// Update last seen workflow ID
|
||||
useEffect(() => {
|
||||
if (activeWorkflowId !== lastWorkflowIdRef.current) {
|
||||
logger.info('Workflow ID changed in DeploymentControls', {
|
||||
previousId: lastWorkflowIdRef.current,
|
||||
currentId: activeWorkflowId,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
lastWorkflowIdRef.current = activeWorkflowId;
|
||||
}
|
||||
}, [activeWorkflowId]);
|
||||
|
||||
// Log when deployed state changes
|
||||
useEffect(() => {
|
||||
if (deployedState && deployedState !== lastDeployedStateRef.current) {
|
||||
const blockIds = Object.keys(deployedState?.blocks || {});
|
||||
logger.info('Deployed state changed in DeploymentControls', {
|
||||
workflowId: activeWorkflowId,
|
||||
blockCount: blockIds.length,
|
||||
blockIds: JSON.stringify(blockIds.slice(0, 3)),
|
||||
isLoadingState: isLoadingDeployedState,
|
||||
timestamp: Date.now(),
|
||||
stateHash: JSON.stringify(deployedState).length
|
||||
});
|
||||
lastDeployedStateRef.current = deployedState;
|
||||
}
|
||||
}, [deployedState, activeWorkflowId, isLoadingDeployedState]);
|
||||
|
||||
// Add wrapper around refetchDeployedState to track timing
|
||||
const refetchWithLogging = async () => {
|
||||
// Refetch deployed state wrapper
|
||||
const refetchWithErrorHandling = async () => {
|
||||
if (!activeWorkflowId) return;
|
||||
|
||||
const fetchId = Date.now();
|
||||
logger.info('Starting deployedState refetch', {
|
||||
workflowId: activeWorkflowId,
|
||||
fetchId,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
try {
|
||||
await refetchDeployedState();
|
||||
|
||||
logger.info('Completed deployedState refetch', {
|
||||
workflowId: activeWorkflowId,
|
||||
fetchId,
|
||||
timestamp: Date.now(),
|
||||
duration: Date.now() - fetchId
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error in deployedState refetch', {
|
||||
workflowId: activeWorkflowId,
|
||||
fetchId,
|
||||
error,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
// Silent error handling
|
||||
}
|
||||
};
|
||||
|
||||
@@ -174,7 +127,7 @@ export function DeploymentControls({
|
||||
setNeedsRedeployment={setNeedsRedeployment}
|
||||
deployedState={deployedState}
|
||||
isLoadingDeployedState={isLoadingDeployedState}
|
||||
refetchDeployedState={refetchWithLogging}
|
||||
refetchDeployedState={refetchWithErrorHandling}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -218,11 +218,10 @@ export function ControlBar() {
|
||||
// Function to check if redeployment is needed
|
||||
const checkForChanges = async () => {
|
||||
// Skip if we're already showing needsRedeployment
|
||||
if (needsRedeployment) return
|
||||
|
||||
|
||||
// Reset the pending changes counter
|
||||
pendingChanges = 0
|
||||
lastCheckTime = Date.now()
|
||||
pendingChanges = 0;
|
||||
lastCheckTime = Date.now();
|
||||
|
||||
try {
|
||||
// Get the deployed state from the API
|
||||
@@ -235,6 +234,10 @@ export function ControlBar() {
|
||||
setNeedsRedeployment(true)
|
||||
// Also update the store state so other components can access this flag
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(true)
|
||||
} else {
|
||||
// Add this else branch to handle the case when changes are reverted
|
||||
setNeedsRedeployment(false)
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(false)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -397,11 +400,6 @@ export function ControlBar() {
|
||||
if (isDeployed) {
|
||||
setNeedsRedeployment(false)
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(false)
|
||||
|
||||
// When a workflow is newly deployed, we need to fetch the deployed state
|
||||
if (activeWorkflowId && deployedState === null) {
|
||||
// We'll fetch the deployed state in the other useEffect
|
||||
}
|
||||
} else {
|
||||
// If workflow is undeployed, clear the deployed state
|
||||
setDeployedState(null)
|
||||
|
||||
@@ -37,12 +37,21 @@ export function ShortInput({
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
const [showEnvVars, setShowEnvVars] = useState(false)
|
||||
const [showTags, setShowTags] = useState(false)
|
||||
const validatePropValue = (value: any): string => {
|
||||
if (value === undefined || value === null) return '';
|
||||
if (typeof value === 'string') return value;
|
||||
try {
|
||||
return String(value);
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
const [storeValue, setStoreValue] = useSubBlockValue(
|
||||
blockId,
|
||||
subBlockId,
|
||||
false, // No workflow update needed
|
||||
isPreview,
|
||||
propValue
|
||||
validatePropValue(propValue)
|
||||
)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [cursorPosition, setCursorPosition] = useState(0)
|
||||
|
||||
@@ -288,7 +288,11 @@ interface WebhookConfigProps {
|
||||
subBlockId?: string
|
||||
isConnecting: boolean
|
||||
isPreview?: boolean
|
||||
value?: any
|
||||
value?: {
|
||||
webhookProvider?: string
|
||||
webhookPath?: string
|
||||
providerConfig?: ProviderConfig
|
||||
}
|
||||
}
|
||||
|
||||
export function WebhookConfig({
|
||||
|
||||
@@ -237,7 +237,7 @@ export function useSubBlockValue<T = any>(
|
||||
// Otherwise use the store value or initial value
|
||||
valueRef.current = storeValue !== undefined ? storeValue : initialValue;
|
||||
}
|
||||
}, [storeValue, initialValue])
|
||||
}, [storeValue, initialValue, isPreview])
|
||||
|
||||
// Update the ref if the store value changes
|
||||
// This ensures we're always working with the latest value
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useMemo, useEffect } from 'react'
|
||||
import { useMemo } from 'react'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
@@ -78,6 +78,22 @@ export function WorkflowPreview({
|
||||
defaultPosition,
|
||||
defaultZoom,
|
||||
}: WorkflowPreviewProps) {
|
||||
// Track structure changes efficiently
|
||||
const blocksStructure = useMemo(() => ({
|
||||
count: Object.keys(workflowState.blocks || {}).length,
|
||||
ids: Object.keys(workflowState.blocks || {}).join(',')
|
||||
}), [workflowState.blocks]);
|
||||
|
||||
const loopsStructure = useMemo(() => ({
|
||||
count: Object.keys(workflowState.loops || {}).length,
|
||||
ids: Object.keys(workflowState.loops || {}).join(',')
|
||||
}), [workflowState.loops]);
|
||||
|
||||
const edgesStructure = useMemo(() => ({
|
||||
count: workflowState.edges.length,
|
||||
ids: workflowState.edges.map(e => e.id).join(',')
|
||||
}), [workflowState.edges]);
|
||||
|
||||
// Transform blocks and loops into ReactFlow nodes
|
||||
const nodes: Node[] = useMemo(() => {
|
||||
const nodeArray: Node[] = []
|
||||
@@ -167,8 +183,9 @@ export function WorkflowPreview({
|
||||
});
|
||||
})
|
||||
|
||||
|
||||
return nodeArray
|
||||
}, [JSON.stringify(workflowState.blocks), JSON.stringify(workflowState.loops), showSubBlocks])
|
||||
}, [blocksStructure, loopsStructure, showSubBlocks, workflowState.blocks, workflowState.loops])
|
||||
|
||||
// Transform edges
|
||||
const edges: Edge[] = useMemo(() => {
|
||||
@@ -180,7 +197,7 @@ export function WorkflowPreview({
|
||||
targetHandle: edge.targetHandle,
|
||||
type: 'workflowEdge',
|
||||
}))
|
||||
}, [JSON.stringify(workflowState.edges)])
|
||||
}, [edgesStructure, workflowState.edges])
|
||||
|
||||
return (
|
||||
<ReactFlowProvider>
|
||||
|
||||
Reference in New Issue
Block a user