mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
chore: updated prettier config and ran format, updated README
This commit is contained in:
@@ -1,22 +0,0 @@
|
||||
module.exports = {
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
tabWidth: 2,
|
||||
trailingComma: 'es5',
|
||||
printWidth: 100,
|
||||
bracketSpacing: true,
|
||||
arrowParens: 'always',
|
||||
endOfLine: 'lf',
|
||||
plugins: ['prettier-plugin-tailwindcss', '@trivago/prettier-plugin-sort-imports'],
|
||||
importOrder: [
|
||||
'^(react/(.*)$)|^(react$)',
|
||||
'^(next/(.*)$)|^(next$)',
|
||||
'<THIRD_PARTY_MODULES>',
|
||||
'^@/components/(.*)$',
|
||||
'^@/lib/(.*)$',
|
||||
'^@/stores/(.*)$',
|
||||
'^@/(.*)$',
|
||||
'^[./]',
|
||||
],
|
||||
importOrderSortSpecifiers: true,
|
||||
}
|
||||
@@ -2,14 +2,13 @@
|
||||
<img src="sim/public/sim.png" alt="Sim Studio Logo" width="500"/>
|
||||
</p>
|
||||
|
||||
# Sim Studio
|
||||
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
[](https://discord.gg/pQKwMTvNrg)
|
||||
[](https://x.com/simstudioai)
|
||||
[](https://github.com/simstudioai/sim/pulls)
|
||||
[](https://github.com/simstudioai/sim/issues)
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
||||
<a href="https://discord.gg/pQKwMTvNrg"><img src="https://img.shields.io/badge/Discord-Join%20Server-7289DA?logo=discord&logoColor=white" alt="Discord"></a>
|
||||
<a href="https://x.com/simstudioai"><img src="https://img.shields.io/twitter/follow/simstudio?style=social" alt="Twitter"></a>
|
||||
<a href="https://github.com/simstudioai/sim/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome"></a>
|
||||
<a href="https://github.com/simstudioai/sim/issues"><img src="https://img.shields.io/badge/support-contact%20author-purple.svg" alt="support"></a>
|
||||
</p>
|
||||
|
||||
**Sim Studio** is a powerful, user-friendly platform for building, testing, and optimizing agentic workflows.
|
||||
|
||||
|
||||
@@ -34,4 +34,4 @@ coverage
|
||||
**/public/sw.js
|
||||
**/public/workbox-*.js
|
||||
**/public/worker-*.js
|
||||
**/public/fallback-*.js
|
||||
**/public/fallback-*.js
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"endOfLine": "lf",
|
||||
"useTabs": false,
|
||||
"quoteProps": "as-needed",
|
||||
"jsxSingleQuote": false,
|
||||
"bracketSameLine": false,
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"vueIndentScriptAndStyle": false,
|
||||
"embeddedLanguageFormatting": "auto",
|
||||
"singleAttributePerLine": false,
|
||||
"plugins": ["prettier-plugin-tailwindcss", "@trivago/prettier-plugin-sort-imports"],
|
||||
"importOrder": [
|
||||
"^(react/(.*)$)|^(react$)",
|
||||
"^(next/(.*)$)|^(next$)",
|
||||
"<THIRD_PARTY_MODULES>",
|
||||
"^@/components/(.*)$",
|
||||
"^@/lib/(.*)$",
|
||||
"^@/stores/(.*)$",
|
||||
"^@/hooks/(.*)$",
|
||||
"^@/utils/(.*)$",
|
||||
"^@/types/(.*)$",
|
||||
"^@/styles/(.*)$",
|
||||
"^@/(.*)$",
|
||||
"^[./]"
|
||||
],
|
||||
"importOrderSortSpecifiers": true,
|
||||
"importOrderCaseInsensitive": true,
|
||||
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"]
|
||||
}
|
||||
@@ -33,7 +33,11 @@ export default function LoginPage() {
|
||||
const password = formData.get('password') as string
|
||||
|
||||
try {
|
||||
const result = await client.signIn.email({ email, password, callbackURL: '/w' })
|
||||
const result = await client.signIn.email({
|
||||
email,
|
||||
password,
|
||||
callbackURL: '/w',
|
||||
})
|
||||
|
||||
if (!result || result.error) {
|
||||
throw new Error(result?.error?.message || 'Authentication failed')
|
||||
|
||||
@@ -67,7 +67,9 @@ export async function GET(request: NextRequest) {
|
||||
displayName = decoded.name
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Error decoding ID token`, { accountId: acc.id })
|
||||
logger.warn(`[${requestId}] Error decoding ID token`, {
|
||||
accountId: acc.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,9 @@ export async function GET(request: NextRequest) {
|
||||
displayName = decoded.name
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Error decoding ID token`, { accountId: acc.id })
|
||||
logger.warn(`[${requestId}] Error decoding ID token`, {
|
||||
accountId: acc.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +93,9 @@ export async function GET(request: NextRequest) {
|
||||
displayName = userRecord[0].email
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`[${requestId}] Error fetching user email`, { userId: acc.userId })
|
||||
logger.warn(`[${requestId}] Error fetching user email`, {
|
||||
userId: acc.userId,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,9 @@ export async function GET(request: NextRequest) {
|
||||
fileId,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: error.error?.message || 'Failed to fetch file from Google Drive' },
|
||||
{
|
||||
error: error.error?.message || 'Failed to fetch file from Google Drive',
|
||||
},
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ export async function GET(request: NextRequest) {
|
||||
|
||||
// Check if the access token is valid
|
||||
if (!credential.accessToken) {
|
||||
logger.warn(`[${requestId}] No access token available for credential`, { credentialId })
|
||||
logger.warn(`[${requestId}] No access token available for credential`, {
|
||||
credentialId,
|
||||
})
|
||||
return NextResponse.json({ error: 'No access token available' }, { status: 400 })
|
||||
}
|
||||
|
||||
@@ -140,7 +142,9 @@ export async function GET(request: NextRequest) {
|
||||
error: error.error?.message || 'Failed to fetch files from Google Drive',
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: error.error?.message || 'Failed to fetch files from Google Drive' },
|
||||
{
|
||||
error: error.error?.message || 'Failed to fetch files from Google Drive',
|
||||
},
|
||||
{ status: response.status }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -180,7 +180,9 @@ export async function POST(request: Request) {
|
||||
|
||||
// Process tool calls if present
|
||||
if (message.tool_calls) {
|
||||
logger.debug(`[${requestId}] Tool calls:`, { toolCalls: message.tool_calls })
|
||||
logger.debug(`[${requestId}] Tool calls:`, {
|
||||
toolCalls: message.tool_calls,
|
||||
})
|
||||
const actions = message.tool_calls.map((call) => ({
|
||||
name: call.function.name,
|
||||
parameters: JSON.parse(call.function.arguments),
|
||||
|
||||
@@ -83,7 +83,9 @@ export async function GET(request: Request) {
|
||||
)
|
||||
}
|
||||
|
||||
const generalSettings = result[0].general as { isAutoConnectEnabled: boolean }
|
||||
const generalSettings = result[0].general as {
|
||||
isAutoConnectEnabled: boolean
|
||||
}
|
||||
return NextResponse.json(
|
||||
{
|
||||
data: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { SQL, and, eq, gte, lte, or, sql } from 'drizzle-orm'
|
||||
import { and, eq, gte, lte, or, SQL, sql } from 'drizzle-orm'
|
||||
import { z } from 'zod'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
@@ -166,7 +166,10 @@ export async function GET(request: NextRequest) {
|
||||
errors: validationError.errors,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid request parameters', details: validationError.errors },
|
||||
{
|
||||
error: 'Invalid request parameters',
|
||||
details: validationError.errors,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,14 +79,19 @@ export async function POST(req: NextRequest) {
|
||||
.select()
|
||||
.from(workflow)
|
||||
.where(eq(workflow.userId, session.user.id))
|
||||
|
||||
|
||||
// If user has existing workflows, but client sends empty, reject the sync
|
||||
if (existingWorkflows.length > 0) {
|
||||
logger.warn(`[${requestId}] Prevented data loss: Client attempted to sync empty workflows while DB has ${existingWorkflows.length} workflows`)
|
||||
return NextResponse.json({
|
||||
error: 'Sync rejected to prevent data loss',
|
||||
message: 'Client sent empty workflows, but user has existing workflows in database'
|
||||
}, { status: 409 })
|
||||
logger.warn(
|
||||
`[${requestId}] Prevented data loss: Client attempted to sync empty workflows while DB has ${existingWorkflows.length} workflows`
|
||||
)
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Sync rejected to prevent data loss',
|
||||
message: 'Client sent empty workflows, but user has existing workflows in database',
|
||||
},
|
||||
{ status: 409 }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import { Script, createContext } from 'vm'
|
||||
import { createContext, Script } from 'vm'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
|
||||
// Explicitly export allowed methods
|
||||
@@ -101,7 +101,9 @@ export async function POST(req: NextRequest) {
|
||||
})
|
||||
|
||||
const executionTime = Date.now() - startTime
|
||||
logger.info(`[${requestId}] Function executed successfully`, { executionTime })
|
||||
logger.info(`[${requestId}] Function executed successfully`, {
|
||||
executionTime,
|
||||
})
|
||||
|
||||
const response = {
|
||||
success: true,
|
||||
|
||||
@@ -104,7 +104,10 @@ export async function POST(request: NextRequest) {
|
||||
requestedWorkflowId: workflowId,
|
||||
})
|
||||
return NextResponse.json(
|
||||
{ error: 'Webhook path already exists. Please use a different path.', code: 'PATH_EXISTS' },
|
||||
{
|
||||
error: 'Webhook path already exists. Please use a different path.',
|
||||
code: 'PATH_EXISTS',
|
||||
},
|
||||
{ status: 409 }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -97,7 +97,9 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{
|
||||
return new NextResponse('OK', { status: 200 })
|
||||
} catch (error: any) {
|
||||
logger.error(`[${requestId}] Error processing webhook verification`, error)
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, { status: 500 })
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, {
|
||||
status: 500,
|
||||
})
|
||||
} finally {
|
||||
// Ensure Redis connection is properly closed in serverless environment
|
||||
await closeRedisConnection()
|
||||
@@ -214,7 +216,9 @@ export async function POST(
|
||||
await persistExecutionError(foundWorkflow.id, executionId, error, 'webhook')
|
||||
}
|
||||
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, { status: 500 })
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, {
|
||||
status: 500,
|
||||
})
|
||||
} finally {
|
||||
// Ensure Redis connection is properly closed in serverless environment
|
||||
await closeRedisConnection()
|
||||
@@ -519,6 +523,8 @@ async function processWebhook(
|
||||
await persistExecutionError(foundWorkflow.id, executionId, error, 'webhook')
|
||||
}
|
||||
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, { status: 500 })
|
||||
return new NextResponse(`Internal Server Error: ${error.message}`, {
|
||||
status: 500,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,11 @@ export async function DELETE(
|
||||
.where(eq(workflow.id, id))
|
||||
|
||||
logger.info(`[${requestId}] Workflow undeployed successfully: ${id}`)
|
||||
return createSuccessResponse({ isDeployed: false, deployedAt: null, apiKey: null })
|
||||
return createSuccessResponse({
|
||||
isDeployed: false,
|
||||
deployedAt: null,
|
||||
apiKey: null,
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error(`[${requestId}] Error undeploying workflow: ${id}`, error)
|
||||
return createErrorResponse(error.message || 'Failed to undeploy workflow', 500)
|
||||
|
||||
@@ -33,7 +33,9 @@ export async function POST(request: NextRequest, { params }: { params: Promise<{
|
||||
// Use persistExecutionLogs which handles tool call extraction
|
||||
await persistExecutionLogs(id, executionId, result, 'manual')
|
||||
|
||||
return createSuccessResponse({ message: 'Execution logs persisted successfully' })
|
||||
return createSuccessResponse({
|
||||
message: 'Execution logs persisted successfully',
|
||||
})
|
||||
}
|
||||
|
||||
// Fall back to the original log format if 'result' isn't provided
|
||||
|
||||
@@ -36,7 +36,10 @@ export const PineconeBlock: BlockConfig<PineconeResponse> = {
|
||||
options: [
|
||||
{ label: 'multilingual-e5-large', id: 'multilingual-e5-large' },
|
||||
{ label: 'llama-text-embed-v2', id: 'llama-text-embed-v2' },
|
||||
{ label: 'pinecone-sparse-english-v0', id: 'pinecone-sparse-english-v0' },
|
||||
{
|
||||
label: 'pinecone-sparse-english-v0',
|
||||
id: 'pinecone-sparse-english-v0',
|
||||
},
|
||||
],
|
||||
condition: { field: 'operation', value: 'generate' },
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const alertVariants = cva(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const badgeVariants = cva(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react'
|
||||
import { Slot } from '@radix-ui/react-slot'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const buttonVariants = cva(
|
||||
|
||||
@@ -12,6 +12,30 @@ import { cn } from '@/lib/utils'
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
// This file is not typed correctly from shadcn, so we're disabling the type checker
|
||||
// @ts-nocheck
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive> & {
|
||||
|
||||
@@ -30,7 +30,9 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & { hideCloseButton?: boolean }
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
||||
hideCloseButton?: boolean
|
||||
}
|
||||
>(({ className, children, hideCloseButton = false, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as LabelPrimitive from '@radix-ui/react-label'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const labelVariants = cva(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import * as React from 'react'
|
||||
import * as SheetPrimitive from '@radix-ui/react-dialog'
|
||||
import { type VariantProps, cva } from 'class-variance-authority'
|
||||
import { cva, type VariantProps } from 'class-variance-authority'
|
||||
import { X } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
|
||||
@@ -34,8 +34,12 @@ export const account = pgTable(
|
||||
accessToken: text('access_token'),
|
||||
refreshToken: text('refresh_token'),
|
||||
idToken: text('id_token'),
|
||||
accessTokenExpiresAt: timestamp('access_token_expires_at', { mode: 'string' }),
|
||||
refreshTokenExpiresAt: timestamp('refresh_token_expires_at', { mode: 'string' }),
|
||||
accessTokenExpiresAt: timestamp('access_token_expires_at', {
|
||||
mode: 'string',
|
||||
}),
|
||||
refreshTokenExpiresAt: timestamp('refresh_token_expires_at', {
|
||||
mode: 'string',
|
||||
}),
|
||||
scope: text(),
|
||||
password: text(),
|
||||
createdAt: timestamp('created_at', { mode: 'string' }).notNull(),
|
||||
|
||||
@@ -25,7 +25,9 @@ export class TestExecutor extends Executor {
|
||||
// Return a successful result
|
||||
return {
|
||||
success: true,
|
||||
output: { response: { result: 'Test execution completed' } } as NormalizedBlockOutput,
|
||||
output: {
|
||||
response: { result: 'Test execution completed' },
|
||||
} as NormalizedBlockOutput,
|
||||
logs: [],
|
||||
metadata: {
|
||||
duration: 100,
|
||||
|
||||
@@ -489,7 +489,11 @@ export class Executor {
|
||||
content: '',
|
||||
model: '',
|
||||
tokens: { prompt: 0, completion: 0, total: 0 },
|
||||
selectedPath: output?.selectedPath || { blockId: '', blockType: '', blockTitle: '' },
|
||||
selectedPath: output?.selectedPath || {
|
||||
blockId: '',
|
||||
blockType: '',
|
||||
blockTitle: '',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -513,7 +517,11 @@ export class Executor {
|
||||
return {
|
||||
response: {
|
||||
conditionResult: output?.conditionResult || false,
|
||||
selectedPath: output?.selectedPath || { blockId: '', blockType: '', blockTitle: '' },
|
||||
selectedPath: output?.selectedPath || {
|
||||
blockId: '',
|
||||
blockType: '',
|
||||
blockTitle: '',
|
||||
},
|
||||
selectedConditionId: output?.selectedConditionId || '',
|
||||
},
|
||||
}
|
||||
|
||||
+5
-1
@@ -14,7 +14,11 @@ const logger = createLogger('Auth')
|
||||
// In that case, we don't want to send emails and just log them
|
||||
const resend = process.env.RESEND_API_KEY
|
||||
? new Resend(process.env.RESEND_API_KEY)
|
||||
: { emails: { send: async (...args: any[]) => logger.info('Email sent:', args) } }
|
||||
: {
|
||||
emails: {
|
||||
send: async (...args: any[]) => logger.info('Email sent:', args),
|
||||
},
|
||||
}
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: drizzleAdapter(db, {
|
||||
|
||||
@@ -76,7 +76,9 @@ export async function persistExecutionLogs(
|
||||
|
||||
// Case 1: Direct toolCalls array
|
||||
if (Array.isArray(log.output.toolCalls)) {
|
||||
logger.debug('Found direct toolCalls array', { count: log.output.toolCalls.length })
|
||||
logger.debug('Found direct toolCalls array', {
|
||||
count: log.output.toolCalls.length,
|
||||
})
|
||||
|
||||
// Log raw timing data for debugging
|
||||
log.output.toolCalls.forEach((tc: any, idx: number) => {
|
||||
@@ -172,7 +174,9 @@ export async function persistExecutionLogs(
|
||||
? log.output.response.toolCalls
|
||||
: log.output.response.toolCalls.list || []
|
||||
|
||||
logger.debug('Found toolCalls in response', { count: toolCalls.length })
|
||||
logger.debug('Found toolCalls in response', {
|
||||
count: toolCalls.length,
|
||||
})
|
||||
|
||||
// Log raw timing data for debugging
|
||||
toolCalls.forEach((tc: any, idx: number) => {
|
||||
@@ -409,7 +413,9 @@ export async function persistExecutionLogs(
|
||||
},
|
||||
})
|
||||
} catch (error: any) {
|
||||
logger.error(`Error persisting execution logs: ${error.message}`, { error })
|
||||
logger.error(`Error persisting execution logs: ${error.message}`, {
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +446,9 @@ export async function persistExecutionError(
|
||||
createdAt: new Date(),
|
||||
})
|
||||
} catch (logError: any) {
|
||||
logger.error(`Error persisting execution error log: ${logError.message}`, { logError })
|
||||
logger.error(`Error persisting execution error log: ${logError.message}`, {
|
||||
logError,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -342,7 +342,10 @@ export async function refreshOAuthToken(
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text()
|
||||
logger.error('Token refresh failed:', { status: response.status, error: errorText })
|
||||
logger.error('Token refresh failed:', {
|
||||
status: response.status,
|
||||
error: errorText,
|
||||
})
|
||||
throw new Error(`Failed to refresh token: ${response.status} ${errorText}`)
|
||||
}
|
||||
|
||||
|
||||
@@ -337,7 +337,9 @@ export async function executeCode(
|
||||
try {
|
||||
await process.kill()
|
||||
} catch (killError) {
|
||||
logger.error('WebContainer executeCode - Failed to kill process:', { killError })
|
||||
logger.error('WebContainer executeCode - Failed to kill process:', {
|
||||
killError,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -419,7 +419,10 @@ ${fieldDescriptions}
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in Anthropic request:', { error, duration: totalDuration })
|
||||
logger.error('Error in Anthropic request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -344,7 +344,10 @@ export const cerebrasProvider: ProviderConfig = {
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in Cerebras request:', { error, duration: totalDuration })
|
||||
logger.error('Error in Cerebras request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -277,7 +277,10 @@ export const deepseekProvider: ProviderConfig = {
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in Deepseek request:', { error, duration: totalDuration })
|
||||
logger.error('Error in Deepseek request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -275,7 +275,10 @@ export const googleProvider: ProviderConfig = {
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in Google Gemini request:', { error, duration: totalDuration })
|
||||
logger.error('Error in Google Gemini request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -272,7 +272,10 @@ export const groqProvider: ProviderConfig = {
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in Groq request:', { error, duration: totalDuration })
|
||||
logger.error('Error in Groq request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -298,7 +298,10 @@ export const openaiProvider: ProviderConfig = {
|
||||
const providerEndTimeISO = new Date(providerEndTime).toISOString()
|
||||
const totalDuration = providerEndTime - providerStartTime
|
||||
|
||||
logger.error('Error in OpenAI request:', { error, duration: totalDuration })
|
||||
logger.error('Error in OpenAI request:', {
|
||||
error,
|
||||
duration: totalDuration,
|
||||
})
|
||||
|
||||
// Create a new error with timing information
|
||||
const enhancedError = new Error(error instanceof Error ? error.message : String(error))
|
||||
|
||||
@@ -137,7 +137,9 @@ export const useChatStore = create<ChatStore>()(
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Chat error:', { error })
|
||||
set({ error: error instanceof Error ? error.message : 'Unknown error' })
|
||||
set({
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
})
|
||||
} finally {
|
||||
set({ isProcessing: false })
|
||||
}
|
||||
|
||||
+11
-7
@@ -52,7 +52,7 @@ async function initializeApplication(): Promise<void> {
|
||||
// This is a fallback in case DB sync failed or there's no data in DB
|
||||
const registryState = useWorkflowRegistry.getState()
|
||||
const hasDbWorkflows = Object.keys(registryState.workflows).length > 0
|
||||
|
||||
|
||||
if (!hasDbWorkflows) {
|
||||
// No workflows loaded from DB, try localStorage as fallback
|
||||
const workflows = loadRegistry()
|
||||
@@ -65,11 +65,11 @@ async function initializeApplication(): Promise<void> {
|
||||
initializeWorkflowState(activeWorkflowId)
|
||||
}
|
||||
} else if (isNewLoginSession) {
|
||||
// Critical safeguard: For new login sessions with no DB workflows
|
||||
// Critical safeguard: For new login sessions with no DB workflows
|
||||
// and no localStorage, we disable sync temporarily to prevent data loss
|
||||
logger.info('New login session with no workflows - preventing initial sync')
|
||||
const syncManagers = getSyncManagers()
|
||||
syncManagers.forEach(manager => manager.stopIntervalSync())
|
||||
syncManagers.forEach((manager) => manager.stopIntervalSync())
|
||||
}
|
||||
} else {
|
||||
logger.info('Using workflows loaded from DB, ignoring localStorage')
|
||||
@@ -242,7 +242,11 @@ export const resetAllStores = () => {
|
||||
useWorkflowStore.getState().clear()
|
||||
useSubBlockStore.getState().clear()
|
||||
useNotificationStore.setState({ notifications: [] })
|
||||
useEnvironmentStore.setState({ variables: {}, isLoading: false, error: null })
|
||||
useEnvironmentStore.setState({
|
||||
variables: {},
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
useExecutionStore.getState().reset()
|
||||
useConsoleStore.setState({ entries: [], isOpen: false })
|
||||
useChatStore.setState({ messages: [], isProcessing: false, error: null })
|
||||
@@ -279,13 +283,13 @@ export async function reinitializeAfterLogin(): Promise<void> {
|
||||
try {
|
||||
// Reset sync managers to prevent any active syncs during reinitialization
|
||||
resetSyncManagers()
|
||||
|
||||
|
||||
// Clean existing state to avoid stale data
|
||||
resetAllStores()
|
||||
|
||||
|
||||
// Mark as a new login session
|
||||
sessionStorage.removeItem('app_initialized')
|
||||
|
||||
|
||||
// Reset initialization flags to force a fresh load
|
||||
isInitializing = false
|
||||
|
||||
|
||||
@@ -23,7 +23,9 @@ export const useGeneralStore = create<GeneralStore>()(
|
||||
isDebugModeEnabled: false,
|
||||
theme: 'system',
|
||||
toggleAutoConnect: () =>
|
||||
set((state) => ({ isAutoConnectEnabled: !state.isAutoConnectEnabled })),
|
||||
set((state) => ({
|
||||
isAutoConnectEnabled: !state.isAutoConnectEnabled,
|
||||
})),
|
||||
toggleDebugMode: () => set((state) => ({ isDebugModeEnabled: !state.isDebugModeEnabled })),
|
||||
setTheme: (theme: 'system' | 'light' | 'dark') => set({ theme }),
|
||||
}),
|
||||
|
||||
@@ -58,7 +58,10 @@ export async function performSync(config: SyncConfig): Promise<boolean> {
|
||||
if (isLocalStorageMode()) {
|
||||
// Still call onSyncSuccess to maintain expected behavior
|
||||
if (config.onSyncSuccess) {
|
||||
config.onSyncSuccess({ success: true, message: 'Skipped sync in localStorage mode' })
|
||||
config.onSyncSuccess({
|
||||
success: true,
|
||||
message: 'Skipped sync in localStorage mode',
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { SYNC_INTERVALS } from './constants'
|
||||
import {
|
||||
DEFAULT_SYNC_CONFIG,
|
||||
SyncConfig,
|
||||
SyncOperations,
|
||||
isLocalStorageMode,
|
||||
performSync,
|
||||
SyncConfig,
|
||||
SyncOperations,
|
||||
} from './sync-core'
|
||||
|
||||
const logger = createLogger('Sync')
|
||||
|
||||
@@ -338,7 +338,13 @@ export const useWorkflowRegistry = create<WorkflowRegistry>()(
|
||||
history: history || {
|
||||
past: [],
|
||||
present: {
|
||||
state: { blocks, edges, loops, isDeployed: isDeployed || false, deployedAt },
|
||||
state: {
|
||||
blocks,
|
||||
edges,
|
||||
loops,
|
||||
isDeployed: isDeployed || false,
|
||||
deployedAt,
|
||||
},
|
||||
timestamp: Date.now(),
|
||||
action: 'Initial state',
|
||||
subblockValues: {},
|
||||
|
||||
@@ -28,14 +28,14 @@ const scheduledWorkflows = new Set<string>()
|
||||
*/
|
||||
export function isActivelyLoadingFromDB(): boolean {
|
||||
if (!loadingFromDBToken) return false
|
||||
|
||||
|
||||
// Safety check: ensure loading doesn't block syncs indefinitely
|
||||
const elapsedTime = Date.now() - loadingFromDBStartTime
|
||||
if (elapsedTime > LOADING_TIMEOUT) {
|
||||
loadingFromDBToken = null
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -94,7 +94,9 @@ async function updateWorkflowSchedule(workflowId: string, state: any): Promise<v
|
||||
logger.info(`Schedule cancelled for workflow ${workflowId}:`, result)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error managing schedule for workflow ${workflowId}:`, { error })
|
||||
logger.error(`Error managing schedule for workflow ${workflowId}:`, {
|
||||
error,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,12 +240,12 @@ export async function fetchWorkflowsFromDB(): Promise<void> {
|
||||
setTimeout(() => {
|
||||
isLoadingFromDB = false
|
||||
loadingFromDBToken = null
|
||||
|
||||
|
||||
// Verify if registry has workflows as a final check
|
||||
const registryWorkflows = useWorkflowRegistry.getState().workflows
|
||||
const workflowCount = Object.keys(registryWorkflows).length
|
||||
logger.info(`DB loading complete. Workflows in registry: ${workflowCount}`)
|
||||
|
||||
|
||||
// Trigger one final sync to ensure consistency
|
||||
if (workflowCount > 0) {
|
||||
// Small delay for state to fully settle before allowing syncs
|
||||
@@ -275,10 +277,12 @@ export const workflowSync = createSingletonSyncManager('workflow-sync', () => ({
|
||||
// Safety check: if registry has workflows but we're sending empty data, something is wrong
|
||||
const registryWorkflows = useWorkflowRegistry.getState().workflows
|
||||
if (Object.keys(registryWorkflows).length > 0) {
|
||||
logger.warn('Potential data loss prevented: Registry has workflows but sync payload is empty')
|
||||
logger.warn(
|
||||
'Potential data loss prevented: Registry has workflows but sync payload is empty'
|
||||
)
|
||||
return { skipSync: true }
|
||||
}
|
||||
|
||||
|
||||
logger.info('Skipping workflow sync - no workflows to sync')
|
||||
return { skipSync: true }
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { create } from 'zustand'
|
||||
import { devtools } from 'zustand/middleware'
|
||||
import { getBlock } from '@/blocks'
|
||||
import { resolveOutputType } from '@/blocks/utils'
|
||||
import { WorkflowStoreWithHistory, pushHistory, withHistory } from '../middleware'
|
||||
import { pushHistory, withHistory, WorkflowStoreWithHistory } from '../middleware'
|
||||
import { saveWorkflowState } from '../persistence'
|
||||
import { useWorkflowRegistry } from '../registry/store'
|
||||
import { useSubBlockStore } from '../subblock/store'
|
||||
|
||||
@@ -125,7 +125,9 @@ export const createTool: ToolConfig<GoogleDocsToolParams, GoogleDocsCreateRespon
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Google Docs create - Error processing response:', { error })
|
||||
logger.error('Google Docs create - Error processing response:', {
|
||||
error,
|
||||
})
|
||||
throw error
|
||||
}
|
||||
},
|
||||
|
||||
+15
-4
@@ -351,7 +351,9 @@ export async function executeTool(
|
||||
},
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error in post-processing for tool ${toolId}:`, { error })
|
||||
logger.error(`Error in post-processing for tool ${toolId}:`, {
|
||||
error,
|
||||
})
|
||||
// Return original result if post-processing fails
|
||||
// Still include timing data
|
||||
const endTime = new Date()
|
||||
@@ -438,7 +440,10 @@ export async function executeTool(
|
||||
if (toolId.startsWith('custom_')) {
|
||||
const identifier = toolId.replace('custom_', '')
|
||||
const allTools = useCustomToolsStore.getState().getAllTools()
|
||||
const availableTools = allTools.map((t) => ({ id: t.id, title: t.title }))
|
||||
const availableTools = allTools.map((t) => ({
|
||||
id: t.id,
|
||||
title: t.title,
|
||||
}))
|
||||
|
||||
logger.error('Available custom tools:', availableTools)
|
||||
logger.error(`Looking for custom tool with identifier: ${identifier}`)
|
||||
@@ -570,7 +575,9 @@ async function handleInternalRequest(
|
||||
}
|
||||
}
|
||||
} catch (transformError) {
|
||||
logger.error(`Error transforming error for tool ${toolId}:`, { transformError })
|
||||
logger.error(`Error transforming error for tool ${toolId}:`, {
|
||||
transformError,
|
||||
})
|
||||
return {
|
||||
success: false,
|
||||
output: {},
|
||||
@@ -592,7 +599,11 @@ async function handleInternalRequest(
|
||||
*/
|
||||
function validateClientSideParams(
|
||||
params: Record<string, any>,
|
||||
schema: { type: string; properties: Record<string, any>; required?: string[] }
|
||||
schema: {
|
||||
type: string
|
||||
properties: Record<string, any>
|
||||
required?: string[]
|
||||
}
|
||||
) {
|
||||
if (!schema || schema.type !== 'object') {
|
||||
throw new Error('Invalid schema format')
|
||||
|
||||
@@ -16,7 +16,11 @@ export const embeddingsTool: ToolConfig<OpenAIEmbeddingsParams> = {
|
||||
|
||||
params: {
|
||||
apiKey: { type: 'string', required: true, description: 'OpenAI API key' },
|
||||
input: { type: 'string', required: true, description: 'Text to generate embeddings for' },
|
||||
input: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Text to generate embeddings for',
|
||||
},
|
||||
model: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
@@ -29,7 +33,11 @@ export const embeddingsTool: ToolConfig<OpenAIEmbeddingsParams> = {
|
||||
description: 'The format to return the embeddings in',
|
||||
default: 'float',
|
||||
},
|
||||
user: { type: 'string', required: false, description: 'A unique identifier for the end-user' },
|
||||
user: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'A unique identifier for the end-user',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
|
||||
@@ -26,7 +26,11 @@ export const fetchTool: ToolConfig<PineconeFetchParams, PineconeResponse> = {
|
||||
requiredForToolCall: true,
|
||||
description: 'Array of vector IDs to fetch',
|
||||
},
|
||||
namespace: { type: 'string', required: false, description: 'Namespace to fetch vectors from' },
|
||||
namespace: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Namespace to fetch vectors from',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
|
||||
@@ -20,12 +20,36 @@ export const searchTextTool: ToolConfig<PineconeSearchTextParams, PineconeRespon
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
namespace: { type: 'string', required: false, description: 'Namespace to search in' },
|
||||
searchQuery: { type: 'string', required: true, description: 'Text to search for' },
|
||||
topK: { type: 'string', required: false, description: 'Number of results to return' },
|
||||
fields: { type: 'array', required: false, description: 'Fields to return in the results' },
|
||||
filter: { type: 'object', required: false, description: 'Filter to apply to the search' },
|
||||
rerank: { type: 'object', required: false, description: 'Reranking parameters' },
|
||||
namespace: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Namespace to search in',
|
||||
},
|
||||
searchQuery: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Text to search for',
|
||||
},
|
||||
topK: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to return',
|
||||
},
|
||||
fields: {
|
||||
type: 'array',
|
||||
required: false,
|
||||
description: 'Fields to return in the results',
|
||||
},
|
||||
filter: {
|
||||
type: 'object',
|
||||
required: false,
|
||||
description: 'Filter to apply to the search',
|
||||
},
|
||||
rerank: {
|
||||
type: 'object',
|
||||
required: false,
|
||||
description: 'Reranking parameters',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
|
||||
@@ -20,10 +20,26 @@ export const searchVectorTool: ToolConfig<PineconeSearchVectorParams, PineconeRe
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
namespace: { type: 'string', required: false, description: 'Namespace to search in' },
|
||||
vector: { type: 'array', required: true, description: 'Vector to search for' },
|
||||
topK: { type: 'number', required: false, description: 'Number of results to return' },
|
||||
filter: { type: 'object', required: false, description: 'Filter to apply to the search' },
|
||||
namespace: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Namespace to search in',
|
||||
},
|
||||
vector: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
description: 'Vector to search for',
|
||||
},
|
||||
topK: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Number of results to return',
|
||||
},
|
||||
filter: {
|
||||
type: 'object',
|
||||
required: false,
|
||||
description: 'Filter to apply to the search',
|
||||
},
|
||||
includeValues: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
|
||||
@@ -20,7 +20,11 @@ export const upsertTextTool: ToolConfig<PineconeUpsertTextParams, PineconeRespon
|
||||
requiredForToolCall: true,
|
||||
description: 'Full Pinecone index host URL',
|
||||
},
|
||||
namespace: { type: 'string', required: true, description: 'Namespace to upsert records into' },
|
||||
namespace: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Namespace to upsert records into',
|
||||
},
|
||||
records: {
|
||||
type: 'array',
|
||||
required: true,
|
||||
|
||||
@@ -82,7 +82,10 @@ export const visionTool: ToolConfig<VisionParams, VisionResponse> = {
|
||||
role: 'user',
|
||||
content: [
|
||||
{ type: 'text', text: prompt },
|
||||
{ type: 'image', source: { type: 'url', url: params.imageUrl } },
|
||||
{
|
||||
type: 'image',
|
||||
source: { type: 'url', url: params.imageUrl },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -4,8 +4,8 @@ import { highlight, languages } from 'prismjs'
|
||||
import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/themes/prism.css'
|
||||
import Editor from 'react-simple-code-editor'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useSubBlockValue } from '../hooks/use-sub-block-value'
|
||||
|
||||
+10
-4
@@ -7,8 +7,8 @@ import 'prismjs/themes/prism.css'
|
||||
import Editor from 'react-simple-code-editor'
|
||||
import { Handle, Position, useUpdateNodeInternals } from 'reactflow'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -43,7 +43,9 @@ export function ConditionInput({ blockId, subBlockId, isConnecting }: ConditionI
|
||||
const [cursorPosition, setCursorPosition] = useState(0)
|
||||
const [activeSourceBlockId, setActiveSourceBlockId] = useState<string | null>(null)
|
||||
const editorRef = useRef<HTMLDivElement>(null)
|
||||
const [visualLineHeights, setVisualLineHeights] = useState<{ [key: string]: number[] }>({})
|
||||
const [visualLineHeights, setVisualLineHeights] = useState<{
|
||||
[key: string]: number[]
|
||||
}>({})
|
||||
const updateNodeInternals = useUpdateNodeInternals()
|
||||
const removeEdge = useWorkflowStore((state) => state.removeEdge)
|
||||
const edges = useWorkflowStore((state) => state.edges)
|
||||
@@ -602,7 +604,11 @@ export function ConditionInput({ blockId, subBlockId, isConnecting }: ConditionI
|
||||
setConditionalBlocks((blocks) =>
|
||||
blocks.map((b) =>
|
||||
b.id === block.id
|
||||
? { ...b, showTags: false, activeSourceBlockId: null }
|
||||
? {
|
||||
...b,
|
||||
showTags: false,
|
||||
activeSourceBlockId: null,
|
||||
}
|
||||
: b
|
||||
)
|
||||
)
|
||||
|
||||
+2
-2
@@ -13,10 +13,10 @@ import {
|
||||
import { client } from '@/lib/auth-client'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import {
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
getProviderIdFromServiceId,
|
||||
getServiceIdFromScopes,
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
parseProvider,
|
||||
} from '@/lib/oauth'
|
||||
import { saveToStorage } from '@/stores/workflows/persistence'
|
||||
|
||||
+2
-2
@@ -15,10 +15,10 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import {
|
||||
Credential,
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
getProviderIdFromServiceId,
|
||||
getServiceIdFromScopes,
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
parseProvider,
|
||||
} from '@/lib/oauth'
|
||||
import { saveToStorage } from '@/stores/workflows/persistence'
|
||||
|
||||
+5
-3
@@ -16,11 +16,11 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import {
|
||||
Credential,
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
getProviderIdFromServiceId,
|
||||
getServiceByProviderAndId,
|
||||
getServiceIdFromScopes,
|
||||
OAUTH_PROVIDERS,
|
||||
OAuthProvider,
|
||||
parseProvider,
|
||||
} from '@/lib/oauth'
|
||||
import { saveToStorage } from '@/stores/workflows/persistence'
|
||||
@@ -153,7 +153,9 @@ export function GoogleDrivePicker({
|
||||
return data.file
|
||||
}
|
||||
} else {
|
||||
logger.error('Error fetching file by ID:', { error: await response.text() })
|
||||
logger.error('Error fetching file by ID:', {
|
||||
error: await response.text(),
|
||||
})
|
||||
}
|
||||
return null
|
||||
} catch (error) {
|
||||
|
||||
+6
-2
@@ -137,7 +137,9 @@ export function FolderSelector({
|
||||
return data.label
|
||||
}
|
||||
} else {
|
||||
logger.error('Error fetching folder by ID:', { error: await response.text() })
|
||||
logger.error('Error fetching folder by ID:', {
|
||||
error: await response.text(),
|
||||
})
|
||||
}
|
||||
return null
|
||||
} catch (error) {
|
||||
@@ -187,7 +189,9 @@ export function FolderSelector({
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.error('Error fetching folders:', { error: await response.text() })
|
||||
logger.error('Error fetching folders:', {
|
||||
error: await response.text(),
|
||||
})
|
||||
setFolders([])
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { useRef, useState } from 'react'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { formatDisplayText } from '@/components/ui/formatted-text'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { formatDisplayText } from '@/components/ui/formatted-text'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { SubBlockConfig } from '@/blocks/types'
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { Trash2 } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { formatDisplayText } from '@/components/ui/formatted-text'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useSubBlockValue } from '../hooks/use-sub-block-value'
|
||||
|
||||
|
||||
+2
-2
@@ -9,9 +9,9 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown'
|
||||
import { checkEnvVarTrigger, EnvVarDropdown } from '@/components/ui/env-var-dropdown'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown'
|
||||
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
|
||||
import { createLogger } from '@/lib/logs/console-logger'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useCustomToolsStore } from '@/stores/custom-tools/store'
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import React, {
|
||||
ReactNode,
|
||||
createContext,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
|
||||
+4
-1
@@ -374,7 +374,10 @@ export function ToolInput({ blockId, subBlockId }: ToolInputProps) {
|
||||
])
|
||||
} else {
|
||||
setValue([
|
||||
...selectedTools.map((tool) => ({ ...tool, isExpanded: false })),
|
||||
...selectedTools.map((tool) => ({
|
||||
...tool,
|
||||
isExpanded: false,
|
||||
})),
|
||||
newTool,
|
||||
])
|
||||
}
|
||||
|
||||
+7
-2
@@ -54,7 +54,10 @@ export function WebhookModal({
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
const [isTesting, setIsTesting] = useState(false)
|
||||
const [isLoadingToken, setIsLoadingToken] = useState(false)
|
||||
const [testResult, setTestResult] = useState<{ success: boolean; message?: string } | null>(null)
|
||||
const [testResult, setTestResult] = useState<{
|
||||
success: boolean
|
||||
message?: string
|
||||
} | null>(null)
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
|
||||
const isConfigured = Boolean(webhookId)
|
||||
|
||||
@@ -221,7 +224,9 @@ export function WebhookModal({
|
||||
|
||||
// Get provider icon
|
||||
const getProviderIcon = () => {
|
||||
return provider.icon({ className: 'h-5 w-5 text-green-500 dark:text-green-400' })
|
||||
return provider.icon({
|
||||
className: 'h-5 w-5 text-green-500 dark:text-green-400',
|
||||
})
|
||||
}
|
||||
|
||||
// Get provider-specific title
|
||||
|
||||
+3
-1
@@ -247,7 +247,9 @@ export function WebhookConfig({ blockId, subBlockId, isConnecting }: WebhookConf
|
||||
}
|
||||
|
||||
const provider = WEBHOOK_PROVIDERS[webhookProvider || 'generic']
|
||||
return provider.icon({ className: 'h-4 w-4 mr-2 text-green-500 dark:text-green-400' })
|
||||
return provider.icon({
|
||||
className: 'h-4 w-4 mr-2 text-green-500 dark:text-green-400',
|
||||
})
|
||||
}
|
||||
|
||||
// Check if the webhook is connected for the selected provider
|
||||
|
||||
@@ -134,7 +134,9 @@ function WorkflowContent() {
|
||||
|
||||
const blockConfig = getBlock(block.type)
|
||||
if (!blockConfig) {
|
||||
logger.error(`No configuration found for block type: ${block.type}`, { block })
|
||||
logger.error(`No configuration found for block type: ${block.type}`, {
|
||||
block,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -127,7 +127,10 @@ export function Account({ onOpenChange }: AccountProps) {
|
||||
<div className="relative flex h-10 w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg bg-muted animate-pulse">
|
||||
<div
|
||||
className="absolute inset-0 bg-gradient-to-r from-transparent via-white/20 to-transparent animate-[shimmer_1.5s_infinite]"
|
||||
style={{ transform: 'translateX(-100%)', animation: 'shimmer 1.5s infinite' }}
|
||||
style={{
|
||||
transform: 'translateX(-100%)',
|
||||
animation: 'shimmer 1.5s infinite',
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
+8
-2
@@ -35,8 +35,14 @@ const nextConfig: NextConfig = {
|
||||
source: '/api/:path*',
|
||||
headers: [
|
||||
{ key: 'Access-Control-Allow-Credentials', value: 'true' },
|
||||
{ key: 'Access-Control-Allow-Origin', value: 'https://localhost:3001' },
|
||||
{ key: 'Access-Control-Allow-Methods', value: 'GET,POST,OPTIONS,PUT,DELETE' },
|
||||
{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: 'https://localhost:3001',
|
||||
},
|
||||
{
|
||||
key: 'Access-Control-Allow-Methods',
|
||||
value: 'GET,POST,OPTIONS,PUT,DELETE',
|
||||
},
|
||||
{
|
||||
key: 'Access-Control-Allow-Headers',
|
||||
value:
|
||||
|
||||
@@ -2,8 +2,16 @@
|
||||
"name": "Sim Studio",
|
||||
"short_name": "Sim Studio",
|
||||
"icons": [
|
||||
{ "src": "/favicon/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
|
||||
{ "src": "/favicon/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
|
||||
{
|
||||
"src": "/favicon/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/favicon/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
|
||||
+20
-5
@@ -29,21 +29,36 @@ export default defineConfig({
|
||||
find: '@/stores/execution/store',
|
||||
replacement: path.resolve(__dirname, 'app/stores/execution/store.ts'),
|
||||
},
|
||||
{ find: '@/blocks/types', replacement: path.resolve(__dirname, 'app/blocks/types.ts') },
|
||||
{
|
||||
find: '@/blocks/types',
|
||||
replacement: path.resolve(__dirname, 'app/blocks/types.ts'),
|
||||
},
|
||||
{
|
||||
find: '@/serializer/types',
|
||||
replacement: path.resolve(__dirname, 'app/serializer/types.ts'),
|
||||
},
|
||||
{ find: '@/lib', replacement: path.resolve(__dirname, 'app/lib') },
|
||||
{ find: '@/stores', replacement: path.resolve(__dirname, 'app/stores') },
|
||||
{ find: '@/components', replacement: path.resolve(__dirname, 'app/components') },
|
||||
{
|
||||
find: '@/components',
|
||||
replacement: path.resolve(__dirname, 'app/components'),
|
||||
},
|
||||
{ find: '@/app', replacement: path.resolve(__dirname, 'app') },
|
||||
{ find: '@/api', replacement: path.resolve(__dirname, 'app/api') },
|
||||
{ find: '@/executor', replacement: path.resolve(__dirname, 'app/executor') },
|
||||
{ find: '@/providers', replacement: path.resolve(__dirname, 'app/providers') },
|
||||
{
|
||||
find: '@/executor',
|
||||
replacement: path.resolve(__dirname, 'app/executor'),
|
||||
},
|
||||
{
|
||||
find: '@/providers',
|
||||
replacement: path.resolve(__dirname, 'app/providers'),
|
||||
},
|
||||
{ find: '@/tools', replacement: path.resolve(__dirname, 'app/tools') },
|
||||
{ find: '@/blocks', replacement: path.resolve(__dirname, 'app/blocks') },
|
||||
{ find: '@/serializer', replacement: path.resolve(__dirname, 'app/serializer') },
|
||||
{
|
||||
find: '@/serializer',
|
||||
replacement: path.resolve(__dirname, 'app/serializer'),
|
||||
},
|
||||
{ find: '@', replacement: path.resolve(__dirname) },
|
||||
],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user