diff --git a/apps/sim/app/api/logs/[id]/route.ts b/apps/sim/app/api/logs/[id]/route.ts index 82e8deb09..466868c08 100644 --- a/apps/sim/app/api/logs/[id]/route.ts +++ b/apps/sim/app/api/logs/[id]/route.ts @@ -1,5 +1,10 @@ import { db } from '@sim/db' -import { permissions, workflow, workflowExecutionLogs } from '@sim/db/schema' +import { + permissions, + workflow, + workflowDeploymentVersion, + workflowExecutionLogs, +} from '@sim/db/schema' import { and, eq } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { getSession } from '@/lib/auth' @@ -29,6 +34,7 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{ workflowId: workflowExecutionLogs.workflowId, executionId: workflowExecutionLogs.executionId, stateSnapshotId: workflowExecutionLogs.stateSnapshotId, + deploymentVersionId: workflowExecutionLogs.deploymentVersionId, level: workflowExecutionLogs.level, trigger: workflowExecutionLogs.trigger, startedAt: workflowExecutionLogs.startedAt, @@ -46,9 +52,15 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{ workflowWorkspaceId: workflow.workspaceId, workflowCreatedAt: workflow.createdAt, workflowUpdatedAt: workflow.updatedAt, + deploymentVersion: workflowDeploymentVersion.version, + deploymentVersionName: workflowDeploymentVersion.name, }) .from(workflowExecutionLogs) .innerJoin(workflow, eq(workflowExecutionLogs.workflowId, workflow.id)) + .leftJoin( + workflowDeploymentVersion, + eq(workflowDeploymentVersion.id, workflowExecutionLogs.deploymentVersionId) + ) .innerJoin( permissions, and( @@ -81,6 +93,9 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{ id: log.id, workflowId: log.workflowId, executionId: log.executionId, + deploymentVersionId: log.deploymentVersionId, + deploymentVersion: log.deploymentVersion ?? null, + deploymentVersionName: log.deploymentVersionName ?? null, level: log.level, duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null, trigger: log.trigger, diff --git a/apps/sim/app/api/logs/route.ts b/apps/sim/app/api/logs/route.ts index 0020e1e6c..9651e9a28 100644 --- a/apps/sim/app/api/logs/route.ts +++ b/apps/sim/app/api/logs/route.ts @@ -1,5 +1,11 @@ import { db } from '@sim/db' -import { pausedExecutions, permissions, workflow, workflowExecutionLogs } from '@sim/db/schema' +import { + pausedExecutions, + permissions, + workflow, + workflowDeploymentVersion, + workflowExecutionLogs, +} from '@sim/db/schema' import { and, desc, eq, gte, inArray, isNotNull, isNull, lte, or, type SQL, sql } from 'drizzle-orm' import { type NextRequest, NextResponse } from 'next/server' import { z } from 'zod' @@ -51,6 +57,7 @@ export async function GET(request: NextRequest) { workflowId: workflowExecutionLogs.workflowId, executionId: workflowExecutionLogs.executionId, stateSnapshotId: workflowExecutionLogs.stateSnapshotId, + deploymentVersionId: workflowExecutionLogs.deploymentVersionId, level: workflowExecutionLogs.level, trigger: workflowExecutionLogs.trigger, startedAt: workflowExecutionLogs.startedAt, @@ -71,6 +78,8 @@ export async function GET(request: NextRequest) { pausedStatus: pausedExecutions.status, pausedTotalPauseCount: pausedExecutions.totalPauseCount, pausedResumedCount: pausedExecutions.resumedCount, + deploymentVersion: workflowDeploymentVersion.version, + deploymentVersionName: workflowDeploymentVersion.name, } : { // Basic mode - exclude large fields for better performance @@ -78,6 +87,7 @@ export async function GET(request: NextRequest) { workflowId: workflowExecutionLogs.workflowId, executionId: workflowExecutionLogs.executionId, stateSnapshotId: workflowExecutionLogs.stateSnapshotId, + deploymentVersionId: workflowExecutionLogs.deploymentVersionId, level: workflowExecutionLogs.level, trigger: workflowExecutionLogs.trigger, startedAt: workflowExecutionLogs.startedAt, @@ -98,6 +108,8 @@ export async function GET(request: NextRequest) { pausedStatus: pausedExecutions.status, pausedTotalPauseCount: pausedExecutions.totalPauseCount, pausedResumedCount: pausedExecutions.resumedCount, + deploymentVersion: workflowDeploymentVersion.version, + deploymentVersionName: sql`NULL`, // Only needed in full mode for details panel } const baseQuery = db @@ -107,6 +119,10 @@ export async function GET(request: NextRequest) { pausedExecutions, eq(pausedExecutions.executionId, workflowExecutionLogs.executionId) ) + .leftJoin( + workflowDeploymentVersion, + eq(workflowDeploymentVersion.id, workflowExecutionLogs.deploymentVersionId) + ) .innerJoin( workflow, and( @@ -397,6 +413,9 @@ export async function GET(request: NextRequest) { id: log.id, workflowId: log.workflowId, executionId: log.executionId, + deploymentVersionId: log.deploymentVersionId, + deploymentVersion: log.deploymentVersion ?? null, + deploymentVersionName: log.deploymentVersionName ?? null, level: log.level, duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null, trigger: log.trigger, diff --git a/apps/sim/app/api/v1/logs/route.ts b/apps/sim/app/api/v1/logs/route.ts index d4ebc972e..dc6352299 100644 --- a/apps/sim/app/api/v1/logs/route.ts +++ b/apps/sim/app/api/v1/logs/route.ts @@ -111,6 +111,7 @@ export async function GET(request: NextRequest) { id: workflowExecutionLogs.id, workflowId: workflowExecutionLogs.workflowId, executionId: workflowExecutionLogs.executionId, + deploymentVersionId: workflowExecutionLogs.deploymentVersionId, level: workflowExecutionLogs.level, trigger: workflowExecutionLogs.trigger, startedAt: workflowExecutionLogs.startedAt, @@ -161,6 +162,7 @@ export async function GET(request: NextRequest) { id: log.id, workflowId: log.workflowId, executionId: log.executionId, + deploymentVersionId: log.deploymentVersionId, level: log.level, trigger: log.trigger, startedAt: log.startedAt.toISOString(), diff --git a/apps/sim/app/api/workflows/[id]/execute/route.ts b/apps/sim/app/api/workflows/[id]/execute/route.ts index 52dce524a..a330dd624 100644 --- a/apps/sim/app/api/workflows/[id]/execute/route.ts +++ b/apps/sim/app/api/workflows/[id]/execute/route.ts @@ -430,6 +430,7 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id: edges: any[] loops: Record parallels: Record + deploymentVersionId?: string } | null = null let processedInput = input @@ -444,6 +445,10 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id: edges: workflowData.edges, loops: workflowData.loops || {}, parallels: workflowData.parallels || {}, + deploymentVersionId: + !shouldUseDraftState && 'deploymentVersionId' in workflowData + ? (workflowData.deploymentVersionId as string) + : undefined, } const serializedWorkflow = new Serializer().serializeWorkflow( diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx index f9c161485..757b0731f 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/knowledge.tsx @@ -199,7 +199,7 @@ export function Knowledge() { -
+
{isLoading ? ( ) : filteredAndSortedKnowledgeBases.length === 0 ? ( diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx index 5c9053cc3..cde20df02 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/dashboard/components/line-chart/line-chart.tsx @@ -30,8 +30,8 @@ export function LineChart({ }) { const containerRef = useRef(null) const uniqueId = useRef(`chart-${Math.random().toString(36).substring(2, 9)}`).current - const [containerWidth, setContainerWidth] = useState(420) - const width = containerWidth + const [containerWidth, setContainerWidth] = useState(null) + const width = containerWidth ?? 0 const height = 166 const padding = { top: 16, right: 28, bottom: 26, left: 26 } useEffect(() => { @@ -39,14 +39,14 @@ export function LineChart({ const element = containerRef.current const ro = new ResizeObserver((entries) => { const entry = entries[0] - if (entry?.contentRect) { + if (entry?.contentRect && entry.contentRect.width > 0) { const w = Math.max(280, Math.floor(entry.contentRect.width)) setContainerWidth(w) } }) ro.observe(element) const rect = element.getBoundingClientRect() - if (rect?.width) setContainerWidth(Math.max(280, Math.floor(rect.width))) + if (rect?.width && rect.width > 0) setContainerWidth(Math.max(280, Math.floor(rect.width))) return () => ro.disconnect() }, []) const chartWidth = width - padding.left - padding.right @@ -95,6 +95,16 @@ export function LineChart({ const hasExternalWrapper = !label || label === '' + if (containerWidth === null) { + return ( +
+ ) + } + if (data.length === 0) { return (
{/* Skeleton bars simulating chart */}
- {Array.from({ length: 24 }).map((_, i) => ( + {SKELETON_BAR_HEIGHTS.map((height, i) => ( ))} @@ -803,7 +811,6 @@ export default function Dashboard({
{globalDetails ? ( {globalDetails ? ( {globalDetails ? ( +
{/* Level */}
@@ -233,14 +233,30 @@ export function LogDetails({
{/* Duration */} -
+
Duration - + {log.duration || '—'}
+ + {/* Version */} + {log.deploymentVersion && ( +
+ + Version + +
+ + {log.deploymentVersionName || `v${log.deploymentVersion}`} + +
+
+ )}
{/* Workflow State */} diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx index e29715647..692849fa2 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/logs-toolbar/logs-toolbar.tsx @@ -343,17 +343,18 @@ export function LogsToolbar({ {/* View mode toggle */} -
+
onViewModeChange(isDashboardView ? 'logs' : 'dashboard')} + >