mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
fix: working on subblock rendering
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { eq } from 'drizzle-orm'
|
||||
import type { NextRequest } from 'next/server'
|
||||
import type { NextRequest, NextResponse } from 'next/server'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { db } from '@/db'
|
||||
import { workflow } from '@/db/schema'
|
||||
@@ -11,6 +11,12 @@ const logger = createLogger('WorkflowDeployedStateAPI')
|
||||
export const dynamic = 'force-dynamic'
|
||||
export const runtime = 'nodejs'
|
||||
|
||||
// Helper function to add Cache-Control headers to NextResponse
|
||||
function addNoCacheHeaders(response: NextResponse): NextResponse {
|
||||
response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
|
||||
return response
|
||||
}
|
||||
|
||||
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||
const requestId = crypto.randomUUID().slice(0, 8)
|
||||
const { id } = await params
|
||||
@@ -21,7 +27,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||
|
||||
if (validation.error) {
|
||||
logger.warn(`[${requestId}] Failed to fetch deployed state: ${validation.error.message}`)
|
||||
return createErrorResponse(validation.error.message, validation.error.status)
|
||||
const response = createErrorResponse(validation.error.message, validation.error.status)
|
||||
return addNoCacheHeaders(response)
|
||||
}
|
||||
|
||||
// Fetch the workflow's deployed state
|
||||
@@ -36,7 +43,8 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||
|
||||
if (result.length === 0) {
|
||||
logger.warn(`[${requestId}] Workflow not found: ${id}`)
|
||||
return createErrorResponse('Workflow not found', 404)
|
||||
const response = createErrorResponse('Workflow not found', 404)
|
||||
return addNoCacheHeaders(response)
|
||||
}
|
||||
|
||||
const workflowData = result[0]
|
||||
@@ -44,18 +52,21 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||
// If the workflow is not deployed, return appropriate response
|
||||
if (!workflowData.isDeployed || !workflowData.deployedState) {
|
||||
logger.info(`[${requestId}] No deployed state available for workflow: ${id}`)
|
||||
return createSuccessResponse({
|
||||
const response = createSuccessResponse({
|
||||
deployedState: null,
|
||||
message: 'Workflow is not deployed or has no deployed state',
|
||||
})
|
||||
return addNoCacheHeaders(response)
|
||||
}
|
||||
|
||||
logger.info(`[${requestId}] Successfully retrieved deployed state for: ${id}`)
|
||||
return createSuccessResponse({
|
||||
const response = createSuccessResponse({
|
||||
deployedState: workflowData.deployedState,
|
||||
})
|
||||
return addNoCacheHeaders(response)
|
||||
} catch (error: any) {
|
||||
logger.error(`[${requestId}] Error fetching deployed state: ${id}`, error)
|
||||
return createErrorResponse(error.message || 'Failed to fetch deployed state', 500)
|
||||
const response = createErrorResponse(error.message || 'Failed to fetch deployed state', 500)
|
||||
return addNoCacheHeaders(response)
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ interface DeployModalProps {
|
||||
setNeedsRedeployment: (value: boolean) => void
|
||||
deployedState: any
|
||||
isLoadingDeployedState: boolean
|
||||
refetchDeployedState: () => Promise<void>
|
||||
}
|
||||
|
||||
interface ApiKey {
|
||||
@@ -73,6 +74,7 @@ export function DeployModal({
|
||||
setNeedsRedeployment,
|
||||
deployedState,
|
||||
isLoadingDeployedState,
|
||||
refetchDeployedState,
|
||||
}: DeployModalProps) {
|
||||
// Store hooks
|
||||
const { addNotification } = useNotificationStore()
|
||||
@@ -310,6 +312,10 @@ export function DeployModal({
|
||||
|
||||
setDeploymentInfo(newDeploymentInfo)
|
||||
|
||||
// Fetch the updated deployed state after deployment
|
||||
logger.info('Deployment successful, fetching initial deployed state')
|
||||
await refetchDeployedState()
|
||||
|
||||
// No notification on successful deploy
|
||||
} catch (error: any) {
|
||||
logger.error('Error deploying workflow:', { error })
|
||||
@@ -399,6 +405,10 @@ export function DeployModal({
|
||||
useWorkflowRegistry.getState().setWorkflowNeedsRedeployment(workflowId, false)
|
||||
}
|
||||
|
||||
// Fetch the updated deployed state after redeployment
|
||||
logger.info('Redeployment successful, fetching updated deployed state')
|
||||
await refetchDeployedState()
|
||||
|
||||
// Add a success notification
|
||||
addNotification('info', 'Workflow successfully redeployed', workflowId)
|
||||
} catch (error: any) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState } from 'react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent, CardHeader } from '@/components/ui/card'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { WorkflowPreview } from '@/app/w/components/workflow-preview/generic-workflow-preview'
|
||||
import { WorkflowPreview } from '@/app/w/components/workflow-preview/workflow-preview'
|
||||
|
||||
interface DeployedWorkflowCardProps {
|
||||
currentWorkflowState?: {
|
||||
@@ -27,6 +27,7 @@ export function DeployedWorkflowCard({
|
||||
}: DeployedWorkflowCardProps) {
|
||||
const [showingDeployed, setShowingDeployed] = useState(true)
|
||||
const workflowToShow = showingDeployed ? deployedWorkflowState : currentWorkflowState
|
||||
console.log('workflowToShow', workflowToShow)
|
||||
|
||||
return (
|
||||
<Card className={cn('relative overflow-hidden', className)}>
|
||||
|
||||
@@ -17,6 +17,7 @@ interface DeploymentControlsProps {
|
||||
setNeedsRedeployment: (value: boolean) => void
|
||||
deployedState: any
|
||||
isLoadingDeployedState: boolean
|
||||
refetchDeployedState: () => Promise<void>
|
||||
}
|
||||
|
||||
export function DeploymentControls({
|
||||
@@ -25,6 +26,7 @@ export function DeploymentControls({
|
||||
setNeedsRedeployment,
|
||||
deployedState,
|
||||
isLoadingDeployedState,
|
||||
refetchDeployedState,
|
||||
}: DeploymentControlsProps) {
|
||||
// Use workflow-specific deployment status
|
||||
const deploymentStatus = useWorkflowRegistry((state) =>
|
||||
@@ -106,6 +108,7 @@ export function DeploymentControls({
|
||||
setNeedsRedeployment={setNeedsRedeployment}
|
||||
deployedState={deployedState}
|
||||
isLoadingDeployedState={isLoadingDeployedState}
|
||||
refetchDeployedState={refetchDeployedState}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -198,6 +198,260 @@ export function ControlBar() {
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
// Listen for workflow changes and check if redeployment is needed
|
||||
useEffect(() => {
|
||||
if (!activeWorkflowId || !isDeployed) return
|
||||
|
||||
// Create a debounced function to check for changes
|
||||
let debounceTimer: NodeJS.Timeout | null = null
|
||||
let lastCheckTime = 0
|
||||
let pendingChanges = 0
|
||||
const DEBOUNCE_DELAY = 1000
|
||||
const THROTTLE_INTERVAL = 3000
|
||||
|
||||
// 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()
|
||||
|
||||
try {
|
||||
// Get the deployed state from the API
|
||||
const response = await fetch(`/api/workflows/${activeWorkflowId}/status`)
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
|
||||
// If the API says we need redeployment, update our state and the store
|
||||
if (data.needsRedeployment) {
|
||||
setNeedsRedeployment(true)
|
||||
// Also update the store state so other components can access this flag
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(true)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to check workflow change status:', { error })
|
||||
}
|
||||
}
|
||||
|
||||
// Debounced check function
|
||||
const debouncedCheck = () => {
|
||||
// Increment the pending changes counter
|
||||
pendingChanges++
|
||||
|
||||
// Clear any existing timer
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer)
|
||||
}
|
||||
|
||||
// If we recently checked, and it's within throttle interval, wait longer
|
||||
const timeElapsed = Date.now() - lastCheckTime
|
||||
if (timeElapsed < THROTTLE_INTERVAL && lastCheckTime > 0) {
|
||||
// Wait until the throttle interval has passed
|
||||
const adjustedDelay = Math.max(THROTTLE_INTERVAL - timeElapsed, DEBOUNCE_DELAY)
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
// Only check if we have pending changes
|
||||
if (pendingChanges > 0) {
|
||||
checkForChanges()
|
||||
}
|
||||
}, adjustedDelay)
|
||||
} else {
|
||||
// Standard debounce delay if we haven't checked recently
|
||||
debounceTimer = setTimeout(() => {
|
||||
// Only check if we have pending changes
|
||||
if (pendingChanges > 0) {
|
||||
checkForChanges()
|
||||
}
|
||||
}, DEBOUNCE_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe to workflow store changes
|
||||
const workflowUnsubscribe = useWorkflowStore.subscribe(debouncedCheck)
|
||||
|
||||
// Also subscribe to subblock store changes
|
||||
const subBlockUnsubscribe = useSubBlockStore.subscribe((state) => {
|
||||
// Only check for the active workflow
|
||||
if (!activeWorkflowId || !isDeployed || needsRedeployment) return
|
||||
|
||||
// Only trigger when there is an update to the current workflow's subblocks
|
||||
const workflowSubBlocks = state.workflowValues[activeWorkflowId]
|
||||
if (workflowSubBlocks && Object.keys(workflowSubBlocks).length > 0) {
|
||||
debouncedCheck()
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
if (debounceTimer) {
|
||||
clearTimeout(debounceTimer)
|
||||
}
|
||||
workflowUnsubscribe()
|
||||
subBlockUnsubscribe()
|
||||
}
|
||||
}, [activeWorkflowId, isDeployed, needsRedeployment])
|
||||
|
||||
// Check deployment and publication status on mount or when activeWorkflowId changes
|
||||
useEffect(() => {
|
||||
async function checkStatus() {
|
||||
if (!activeWorkflowId) return
|
||||
|
||||
// Skip API call in localStorage mode
|
||||
if (
|
||||
typeof window !== 'undefined' &&
|
||||
(localStorage.getItem('USE_LOCAL_STORAGE') === 'true' ||
|
||||
process.env.NEXT_PUBLIC_USE_LOCAL_STORAGE === 'true' ||
|
||||
process.env.NEXT_PUBLIC_DISABLE_DB_SYNC === 'true')
|
||||
) {
|
||||
// For localStorage mode, we already have the status in the workflow store
|
||||
// Nothing more to do as the useWorkflowStore already has this information
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/workflows/${activeWorkflowId}/status`)
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
// Update the store with the status from the API
|
||||
setDeploymentStatus(
|
||||
data.isDeployed,
|
||||
data.deployedAt ? new Date(data.deployedAt) : undefined
|
||||
)
|
||||
setNeedsRedeployment(data.needsRedeployment)
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(data.needsRedeployment)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to check workflow status:', { error })
|
||||
}
|
||||
}
|
||||
checkStatus()
|
||||
}, [activeWorkflowId, setDeploymentStatus])
|
||||
|
||||
// Add a function to explicitly fetch deployed state that can be called after redeployment
|
||||
const refetchDeployedState = async () => {
|
||||
if (!activeWorkflowId || !isDeployed) {
|
||||
setDeployedState(null)
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoadingDeployedState(true);
|
||||
logger.info(`[CENTRAL] Explicitly refetching deployed state for workflow: ${activeWorkflowId}`);
|
||||
|
||||
const response = await fetch(`/api/workflows/${activeWorkflowId}/deployed`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch deployed state: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.deployedState) {
|
||||
logger.info('Successfully refetched deployed state from DB after redeployment');
|
||||
// Create a deep clone to ensure no reference sharing with current state
|
||||
const deepClonedState = JSON.parse(JSON.stringify(data.deployedState));
|
||||
logger.info('deepClonedState', deepClonedState)
|
||||
setDeployedState(deepClonedState);
|
||||
} else {
|
||||
logger.warn('No deployed state found in the database after refetch');
|
||||
setDeployedState(null);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error refetching deployed state:', error);
|
||||
setDeployedState(null);
|
||||
} finally {
|
||||
setIsLoadingDeployedState(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch deployed state when the workflow ID changes or deployment status changes
|
||||
useEffect(() => {
|
||||
async function fetchDeployedState() {
|
||||
if (!activeWorkflowId || !isDeployed) {
|
||||
setDeployedState(null)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoadingDeployedState(true)
|
||||
logger.info(`[CENTRAL] Fetching deployed state for workflow: ${activeWorkflowId} (Control Bar - Single Source of Truth)`)
|
||||
|
||||
const response = await fetch(`/api/workflows/${activeWorkflowId}/deployed`)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch deployed state: ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.deployedState) {
|
||||
logger.info('Successfully fetched deployed state from DB - This is the only place that should fetch deployed state')
|
||||
// Create a deep clone to ensure no reference sharing with current state
|
||||
const deepClonedState = JSON.parse(JSON.stringify(data.deployedState))
|
||||
logger.info('deepClonedState', deepClonedState)
|
||||
setDeployedState(deepClonedState)
|
||||
} else {
|
||||
logger.warn('No deployed state found in the database')
|
||||
setDeployedState(null)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error fetching deployed state:', error)
|
||||
setDeployedState(null)
|
||||
} finally {
|
||||
setIsLoadingDeployedState(false)
|
||||
}
|
||||
}
|
||||
|
||||
fetchDeployedState()
|
||||
}, [activeWorkflowId, isDeployed])
|
||||
|
||||
// Listen for deployment status changes
|
||||
useEffect(() => {
|
||||
// When deployment status changes and isDeployed becomes true,
|
||||
// that means a deployment just occurred, so reset the needsRedeployment flag
|
||||
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)
|
||||
}
|
||||
}, [isDeployed, activeWorkflowId])
|
||||
|
||||
// Listen for deployment status changes
|
||||
useEffect(() => {
|
||||
// When deployment status changes and isDeployed becomes true,
|
||||
// that means a deployment just occurred, so reset the needsRedeployment flag
|
||||
if (isDeployed) {
|
||||
setNeedsRedeployment(false)
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(false)
|
||||
}
|
||||
}, [isDeployed])
|
||||
|
||||
// Add a listener for the needsRedeployment flag in the workflow store
|
||||
useEffect(() => {
|
||||
const unsubscribe = useWorkflowStore.subscribe((state) => {
|
||||
// Update local state when the store flag changes
|
||||
if (state.needsRedeployment !== undefined) {
|
||||
setNeedsRedeployment(state.needsRedeployment)
|
||||
}
|
||||
})
|
||||
|
||||
return () => unsubscribe()
|
||||
}, [])
|
||||
|
||||
// Add a manual method to update the deployment status and clear the needsRedeployment flag
|
||||
const updateDeploymentStatusAndClearFlag = (isDeployed: boolean, deployedAt?: Date) => {
|
||||
setDeploymentStatus(isDeployed, deployedAt)
|
||||
setNeedsRedeployment(false)
|
||||
useWorkflowStore.getState().setNeedsRedeploymentFlag(false)
|
||||
}
|
||||
|
||||
// Update existing API notifications when needsRedeployment changes
|
||||
useEffect(() => {
|
||||
if (!activeWorkflowId) return
|
||||
@@ -540,6 +794,7 @@ export function ControlBar() {
|
||||
setNeedsRedeployment={setNeedsRedeployment}
|
||||
deployedState={deployedState}
|
||||
isLoadingDeployedState={isLoadingDeployedState}
|
||||
refetchDeployedState={refetchDeployedState}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1001,63 +1256,6 @@ export function ControlBar() {
|
||||
</div>
|
||||
)
|
||||
|
||||
// Fetch deployed state when the workflow ID changes or deployment status changes
|
||||
useEffect(() => {
|
||||
async function fetchDeployedState() {
|
||||
if (!activeWorkflowId || !isDeployed) {
|
||||
setDeployedState(null)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoadingDeployedState(true)
|
||||
logger.info(`[CENTRAL] Fetching deployed state for workflow: ${activeWorkflowId} (Control Bar - Single Source of Truth)`)
|
||||
|
||||
const response = await fetch(`/api/workflows/${activeWorkflowId}/deployed`)
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch deployed state: ${response.status}`)
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.deployedState) {
|
||||
logger.info('Successfully fetched deployed state from DB - This is the only place that should fetch deployed state')
|
||||
// Create a deep clone to ensure no reference sharing with current state
|
||||
const deepClonedState = JSON.parse(JSON.stringify(data.deployedState))
|
||||
setDeployedState(deepClonedState)
|
||||
} else {
|
||||
logger.warn('No deployed state found in the database')
|
||||
setDeployedState(null)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error fetching deployed state:', error)
|
||||
setDeployedState(null)
|
||||
} finally {
|
||||
setIsLoadingDeployedState(false)
|
||||
}
|
||||
}
|
||||
|
||||
fetchDeployedState()
|
||||
}, [activeWorkflowId, isDeployed])
|
||||
|
||||
// Listen for deployment status changes
|
||||
useEffect(() => {
|
||||
// When deployment status changes and isDeployed becomes true,
|
||||
// that means a deployment just occurred, so reset the needsRedeployment flag
|
||||
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)
|
||||
}
|
||||
}, [isDeployed, activeWorkflowId])
|
||||
|
||||
return (
|
||||
<div className='flex h-16 w-full items-center justify-between border-b bg-background'>
|
||||
{/* Left Section - Workflow Info */}
|
||||
|
||||
@@ -42,7 +42,10 @@ export function OutputSelect({
|
||||
// Skip starter/start blocks
|
||||
if (block.type === 'starter') return
|
||||
|
||||
const blockName = block.name.replace(/\s+/g, '').toLowerCase()
|
||||
// Add defensive check to ensure block.name exists and is a string
|
||||
const blockName = block.name && typeof block.name === 'string'
|
||||
? block.name.replace(/\s+/g, '').toLowerCase()
|
||||
: `block-${block.id}`;
|
||||
|
||||
// Add response outputs
|
||||
if (block.outputs && typeof block.outputs === 'object') {
|
||||
@@ -60,7 +63,7 @@ export function OutputSelect({
|
||||
id: `${block.id}_${fullPath}`,
|
||||
label: `${blockName}.${fullPath}`,
|
||||
blockId: block.id,
|
||||
blockName: block.name,
|
||||
blockName: block.name || `Block ${block.id}`,
|
||||
blockType: block.type,
|
||||
path: fullPath,
|
||||
})
|
||||
@@ -93,7 +96,11 @@ export function OutputSelect({
|
||||
if (validOutputs.length === 1) {
|
||||
const output = workflowOutputs.find((o) => o.id === validOutputs[0])
|
||||
if (output) {
|
||||
return `${output.blockName.replace(/\s+/g, '').toLowerCase()}.${output.path}`
|
||||
// Add defensive check for output.blockName
|
||||
const blockNameText = output.blockName && typeof output.blockName === 'string'
|
||||
? output.blockName.replace(/\s+/g, '').toLowerCase()
|
||||
: `block-${output.blockId}`;
|
||||
return `${blockNameText}.${output.path}`
|
||||
}
|
||||
return placeholder
|
||||
}
|
||||
|
||||
@@ -39,8 +39,6 @@ export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
const { getValue } = useSubBlockStore()
|
||||
|
||||
const isFieldRequired = () => {
|
||||
const blockType = useWorkflowStore.getState().blocks[blockId]?.type
|
||||
if (!blockType) return false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useMemo } from 'react'
|
||||
import { useMemo, useEffect } from 'react'
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
ConnectionLineType,
|
||||
@@ -27,7 +27,6 @@ import { WorkflowEdge } from '@/app/w/[id]/components/workflow-edge/workflow-edg
|
||||
// import { createLoopNode } from '@/app/w/[id]/components/workflow-loop/workflow-loop'
|
||||
import { getBlock } from '@/blocks'
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
const logger = createLogger('WorkflowPreview')
|
||||
|
||||
@@ -68,7 +67,11 @@ const edgeTypes: EdgeTypes = {
|
||||
workflowEdge: WorkflowEdge,
|
||||
}
|
||||
|
||||
function WorkflowPreviewContent({
|
||||
// The subblocks should be getting passed from the state and not the subBlockStore.
|
||||
// Create optional parameter boolan isPreview to pass in the block state to know how to render
|
||||
// the subblocks
|
||||
|
||||
export function WorkflowPreview({
|
||||
workflowState,
|
||||
showSubBlocks = true,
|
||||
className,
|
||||
@@ -174,41 +177,35 @@ function WorkflowPreviewContent({
|
||||
logger.info('Rendering workflow state', { workflowState })
|
||||
}, [workflowState])
|
||||
|
||||
return (
|
||||
<div style={{ height, width }} className={className}>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
connectionLineType={ConnectionLineType.SmoothStep}
|
||||
fitView
|
||||
panOnScroll={false}
|
||||
panOnDrag={isPannable}
|
||||
zoomOnScroll={false}
|
||||
draggable={false}
|
||||
defaultViewport={{
|
||||
x: defaultPosition?.x ?? 0,
|
||||
y: defaultPosition?.y ?? 0,
|
||||
zoom: defaultZoom ?? 1,
|
||||
}}
|
||||
minZoom={0.1}
|
||||
maxZoom={2}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
elementsSelectable={false}
|
||||
nodesDraggable={false}
|
||||
nodesConnectable={false}
|
||||
>
|
||||
<Background />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function WorkflowPreview(props: WorkflowPreviewProps) {
|
||||
return (
|
||||
<ReactFlowProvider>
|
||||
<WorkflowPreviewContent {...props} />
|
||||
<div style={{ height, width }} className={className}>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
connectionLineType={ConnectionLineType.SmoothStep}
|
||||
fitView
|
||||
panOnScroll={false}
|
||||
panOnDrag={isPannable}
|
||||
zoomOnScroll={false}
|
||||
draggable={false}
|
||||
defaultViewport={{
|
||||
x: defaultPosition?.x ?? 0,
|
||||
y: defaultPosition?.y ?? 0,
|
||||
zoom: defaultZoom ?? 1,
|
||||
}}
|
||||
minZoom={0.1}
|
||||
maxZoom={2}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
elementsSelectable={false}
|
||||
nodesDraggable={false}
|
||||
nodesConnectable={false}
|
||||
>
|
||||
<Background />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
</ReactFlowProvider>
|
||||
)
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import { useEffect, useState } from 'react'
|
||||
import { Eye } from 'lucide-react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { Card, CardContent, CardFooter, CardHeader } from '@/components/ui/card'
|
||||
import { WorkflowPreview } from '@/app/w/components/workflow-preview/generic-workflow-preview'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import type { Workflow } from '../marketplace'
|
||||
import { WorkflowPreview } from '@/app/w/components/workflow-preview/workflow-preview'
|
||||
import { Workflow } from '../marketplace'
|
||||
|
||||
/**
|
||||
* WorkflowCardProps interface - defines the properties for the WorkflowCard component
|
||||
|
||||
Reference in New Issue
Block a user