Skip to content

Commit ac72565

Browse files
icecrasher321aadamgoughAdam GoughAdam GoughVikhyath Mondreti
authored andcommitted
v0.2.2: fix (#588)
* fix(loop-foreach): forEach loop iterations (#581) * fix: working on fixing foreach loop max * fix: removed default of 5 iterations * fix: bun run lint * fix: greptile comments (#581) * fix: removed safety max (#581) --------- Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net> Co-authored-by: Adam Gough <adamgough@Adams-MacBook-Pro.local> * improvement(sockets conn): sockets connection refresh warning (#580) * working conn status * improvement(sockets conn): sockets connection refresh warning * fix styling --------- Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-Air.attlocal.net> Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-MacBook-Air.local> * fix(variable resolution): use variable references to not have escaping issues (#587) * fix(variable-resolution): don't inject stringified json, use var refs * fix lint * remove unused var --------- Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@vikhyaths-air.lan> --------- Co-authored-by: Adam Gough <77861281+aadamgough@users.noreply.github.com> Co-authored-by: Adam Gough <adamgough@Mac.attlocal.net> Co-authored-by: Adam Gough <adamgough@Adams-MacBook-Pro.local> Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-Air.attlocal.net> Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@Vikhyaths-MacBook-Air.local> Co-authored-by: Vikhyath Mondreti <vikhyathmondreti@vikhyaths-air.lan>
1 parent 1fc3378 commit ac72565

File tree

4 files changed

+88
-50
lines changed

4 files changed

+88
-50
lines changed

apps/sim/app/api/function/execute/route.ts

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createLogger } from '@/lib/logs/console-logger'
44

55
export const dynamic = 'force-dynamic'
66
export const runtime = 'nodejs'
7+
export const maxDuration = 60
78

89
const logger = createLogger('FunctionExecuteAPI')
910

@@ -14,71 +15,45 @@ const logger = createLogger('FunctionExecuteAPI')
1415
* @param envVars - Environment variables from the workflow
1516
* @returns Resolved code
1617
*/
17-
/**
18-
* Safely serialize a value to JSON string with proper escaping
19-
* This prevents JavaScript syntax errors when the serialized data is injected into code
20-
*/
21-
function safeJSONStringify(value: any): string {
22-
try {
23-
// Use JSON.stringify with proper escaping
24-
// The key is to let JSON.stringify handle the escaping properly
25-
return JSON.stringify(value)
26-
} catch (error) {
27-
// If JSON.stringify fails (e.g., circular references), return a safe fallback
28-
try {
29-
// Try to create a safe representation by removing circular references
30-
const seen = new WeakSet()
31-
const cleanValue = JSON.parse(
32-
JSON.stringify(value, (key, val) => {
33-
if (typeof val === 'object' && val !== null) {
34-
if (seen.has(val)) {
35-
return '[Circular Reference]'
36-
}
37-
seen.add(val)
38-
}
39-
return val
40-
})
41-
)
42-
return JSON.stringify(cleanValue)
43-
} catch {
44-
// If that also fails, return a safe string representation
45-
return JSON.stringify(String(value))
46-
}
47-
}
48-
}
4918

5019
function resolveCodeVariables(
5120
code: string,
5221
params: Record<string, any>,
5322
envVars: Record<string, string> = {}
54-
): string {
23+
): { resolvedCode: string; contextVariables: Record<string, any> } {
5524
let resolvedCode = code
25+
const contextVariables: Record<string, any> = {}
5626

5727
// Resolve environment variables with {{var_name}} syntax
5828
const envVarMatches = resolvedCode.match(/\{\{([^}]+)\}\}/g) || []
5929
for (const match of envVarMatches) {
6030
const varName = match.slice(2, -2).trim()
6131
// Priority: 1. Environment variables from workflow, 2. Params
6232
const varValue = envVars[varName] || params[varName] || ''
63-
// Use safe JSON stringify to prevent syntax errors
64-
resolvedCode = resolvedCode.replace(
65-
new RegExp(escapeRegExp(match), 'g'),
66-
safeJSONStringify(varValue)
67-
)
33+
34+
// Instead of injecting large JSON directly, create a variable reference
35+
const safeVarName = `__var_${varName.replace(/[^a-zA-Z0-9_]/g, '_')}`
36+
contextVariables[safeVarName] = varValue
37+
38+
// Replace the template with a variable reference
39+
resolvedCode = resolvedCode.replace(new RegExp(escapeRegExp(match), 'g'), safeVarName)
6840
}
6941

7042
// Resolve tags with <tag_name> syntax
7143
const tagMatches = resolvedCode.match(/<([a-zA-Z_][a-zA-Z0-9_]*)>/g) || []
7244
for (const match of tagMatches) {
7345
const tagName = match.slice(1, -1).trim()
7446
const tagValue = params[tagName] || ''
75-
resolvedCode = resolvedCode.replace(
76-
new RegExp(escapeRegExp(match), 'g'),
77-
safeJSONStringify(tagValue)
78-
)
47+
48+
// Instead of injecting large JSON directly, create a variable reference
49+
const safeVarName = `__tag_${tagName.replace(/[^a-zA-Z0-9_]/g, '_')}`
50+
contextVariables[safeVarName] = tagValue
51+
52+
// Replace the template with a variable reference
53+
resolvedCode = resolvedCode.replace(new RegExp(escapeRegExp(match), 'g'), safeVarName)
7954
}
8055

81-
return resolvedCode
56+
return { resolvedCode, contextVariables }
8257
}
8358

8459
/**
@@ -118,7 +93,7 @@ export async function POST(req: NextRequest) {
11893
})
11994

12095
// Resolve variables in the code with workflow environment variables
121-
const resolvedCode = resolveCodeVariables(code, executionParams, envVars)
96+
const { resolvedCode, contextVariables } = resolveCodeVariables(code, executionParams, envVars)
12297

12398
const executionMethod = 'vm' // Default execution method
12499

@@ -280,6 +255,7 @@ export async function POST(req: NextRequest) {
280255
const context = createContext({
281256
params: executionParams,
282257
environmentVariables: envVars,
258+
...contextVariables, // Add resolved variables directly to context
283259
fetch: globalThis.fetch || require('node-fetch').default,
284260
console: {
285261
log: (...args: any[]) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
'use client'
2+
3+
import { useEffect, useState } from 'react'
4+
5+
interface ConnectionStatusProps {
6+
isConnected: boolean
7+
}
8+
9+
export function ConnectionStatus({ isConnected }: ConnectionStatusProps) {
10+
const [showOfflineNotice, setShowOfflineNotice] = useState(false)
11+
12+
useEffect(() => {
13+
let timeoutId: NodeJS.Timeout
14+
15+
if (!isConnected) {
16+
// Show offline notice after 6 seconds of being disconnected
17+
timeoutId = setTimeout(() => {
18+
setShowOfflineNotice(true)
19+
}, 6000) // 6 seconds
20+
} else {
21+
// Hide notice immediately when reconnected
22+
setShowOfflineNotice(false)
23+
}
24+
25+
return () => {
26+
if (timeoutId) {
27+
clearTimeout(timeoutId)
28+
}
29+
}
30+
}, [isConnected])
31+
32+
// Don't render anything if connected or if we haven't been disconnected long enough
33+
if (!showOfflineNotice) {
34+
return null
35+
}
36+
37+
return (
38+
<div className='flex items-center gap-1.5'>
39+
<div className='flex items-center gap-1.5 text-red-600'>
40+
<div className='relative flex items-center justify-center'>
41+
<div className='absolute h-3 w-3 animate-ping rounded-full bg-red-500/20' />
42+
<div className='relative h-2 w-2 rounded-full bg-red-500' />
43+
</div>
44+
<div className='flex flex-col'>
45+
<span className='font-medium text-xs leading-tight'>Connection lost</span>
46+
<span className='text-xs leading-tight opacity-90'>
47+
Changes not saved - please refresh
48+
</span>
49+
</div>
50+
</div>
51+
</div>
52+
)
53+
}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/user-avatar-stack/user-avatar-stack.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useMemo } from 'react'
44
import { usePresence } from '../../../../hooks/use-presence'
5+
import { ConnectionStatus } from './components/connection-status/connection-status'
56
import { UserAvatar } from './components/user-avatar/user-avatar'
67

78
interface User {
@@ -25,7 +26,7 @@ export function UserAvatarStack({
2526
className = '',
2627
}: UserAvatarStackProps) {
2728
// Use presence data if no users are provided via props
28-
const { users: presenceUsers } = usePresence()
29+
const { users: presenceUsers, isConnected } = usePresence()
2930
const users = propUsers || presenceUsers
3031

3132
// Memoize the processed users to avoid unnecessary re-renders
@@ -43,10 +44,14 @@ export function UserAvatarStack({
4344
}
4445
}, [users, maxVisible])
4546

47+
// Show connection status component regardless of user count
48+
// This will handle the offline notice when disconnected for 15 seconds
49+
const connectionStatusElement = <ConnectionStatus isConnected={isConnected} />
50+
4651
// Only show presence when there are multiple users (>1)
47-
// Don't render anything if there are no users or only 1 user
52+
// But always show connection status
4853
if (users.length <= 1) {
49-
return null
54+
return connectionStatusElement
5055
}
5156

5257
// Determine spacing based on size
@@ -58,6 +63,9 @@ export function UserAvatarStack({
5863

5964
return (
6065
<div className={`flex items-center ${spacingClass} ${className}`}>
66+
{/* Connection status - always present */}
67+
{connectionStatusElement}
68+
6169
{/* Render visible user avatars */}
6270
{visibleUsers.map((user, index) => (
6371
<UserAvatar

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/control-bar.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,6 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
683683
</p>
684684
)}
685685
</div>
686-
<UserAvatarStack className='ml-3' />
687686
</div>
688687
)
689688
}
@@ -1275,8 +1274,10 @@ export function ControlBar({ hasValidationErrors = false }: ControlBarProps) {
12751274
{/* Left Section - Workflow Info */}
12761275
<div className='pl-4'>{renderWorkflowName()}</div>
12771276

1278-
{/* Middle Section - Reserved for future use */}
1279-
<div className='flex-1' />
1277+
{/* Middle Section - Connection Status */}
1278+
<div className='flex flex-1 justify-center'>
1279+
<UserAvatarStack />
1280+
</div>
12801281

12811282
{/* Right Section - Actions */}
12821283
<div className='flex items-center gap-1 pr-4'>

0 commit comments

Comments
 (0)