mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-09 15:07:55 -05:00
feat(deployment-version): capture deployment version in log (#2304)
* feat(deployment-version): capture deployment version in log * improvement: terminal store, logs version, toolbar --------- Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
This commit is contained in:
@@ -1,5 +1,10 @@
|
|||||||
import { db } from '@sim/db'
|
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 { and, eq } from 'drizzle-orm'
|
||||||
import { type NextRequest, NextResponse } from 'next/server'
|
import { type NextRequest, NextResponse } from 'next/server'
|
||||||
import { getSession } from '@/lib/auth'
|
import { getSession } from '@/lib/auth'
|
||||||
@@ -29,6 +34,7 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{
|
|||||||
workflowId: workflowExecutionLogs.workflowId,
|
workflowId: workflowExecutionLogs.workflowId,
|
||||||
executionId: workflowExecutionLogs.executionId,
|
executionId: workflowExecutionLogs.executionId,
|
||||||
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
||||||
|
deploymentVersionId: workflowExecutionLogs.deploymentVersionId,
|
||||||
level: workflowExecutionLogs.level,
|
level: workflowExecutionLogs.level,
|
||||||
trigger: workflowExecutionLogs.trigger,
|
trigger: workflowExecutionLogs.trigger,
|
||||||
startedAt: workflowExecutionLogs.startedAt,
|
startedAt: workflowExecutionLogs.startedAt,
|
||||||
@@ -46,9 +52,15 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{
|
|||||||
workflowWorkspaceId: workflow.workspaceId,
|
workflowWorkspaceId: workflow.workspaceId,
|
||||||
workflowCreatedAt: workflow.createdAt,
|
workflowCreatedAt: workflow.createdAt,
|
||||||
workflowUpdatedAt: workflow.updatedAt,
|
workflowUpdatedAt: workflow.updatedAt,
|
||||||
|
deploymentVersion: workflowDeploymentVersion.version,
|
||||||
|
deploymentVersionName: workflowDeploymentVersion.name,
|
||||||
})
|
})
|
||||||
.from(workflowExecutionLogs)
|
.from(workflowExecutionLogs)
|
||||||
.innerJoin(workflow, eq(workflowExecutionLogs.workflowId, workflow.id))
|
.innerJoin(workflow, eq(workflowExecutionLogs.workflowId, workflow.id))
|
||||||
|
.leftJoin(
|
||||||
|
workflowDeploymentVersion,
|
||||||
|
eq(workflowDeploymentVersion.id, workflowExecutionLogs.deploymentVersionId)
|
||||||
|
)
|
||||||
.innerJoin(
|
.innerJoin(
|
||||||
permissions,
|
permissions,
|
||||||
and(
|
and(
|
||||||
@@ -81,6 +93,9 @@ export async function GET(_request: NextRequest, { params }: { params: Promise<{
|
|||||||
id: log.id,
|
id: log.id,
|
||||||
workflowId: log.workflowId,
|
workflowId: log.workflowId,
|
||||||
executionId: log.executionId,
|
executionId: log.executionId,
|
||||||
|
deploymentVersionId: log.deploymentVersionId,
|
||||||
|
deploymentVersion: log.deploymentVersion ?? null,
|
||||||
|
deploymentVersionName: log.deploymentVersionName ?? null,
|
||||||
level: log.level,
|
level: log.level,
|
||||||
duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null,
|
duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null,
|
||||||
trigger: log.trigger,
|
trigger: log.trigger,
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
import { db } from '@sim/db'
|
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 { and, desc, eq, gte, inArray, isNotNull, isNull, lte, or, type SQL, sql } from 'drizzle-orm'
|
||||||
import { type NextRequest, NextResponse } from 'next/server'
|
import { type NextRequest, NextResponse } from 'next/server'
|
||||||
import { z } from 'zod'
|
import { z } from 'zod'
|
||||||
@@ -51,6 +57,7 @@ export async function GET(request: NextRequest) {
|
|||||||
workflowId: workflowExecutionLogs.workflowId,
|
workflowId: workflowExecutionLogs.workflowId,
|
||||||
executionId: workflowExecutionLogs.executionId,
|
executionId: workflowExecutionLogs.executionId,
|
||||||
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
||||||
|
deploymentVersionId: workflowExecutionLogs.deploymentVersionId,
|
||||||
level: workflowExecutionLogs.level,
|
level: workflowExecutionLogs.level,
|
||||||
trigger: workflowExecutionLogs.trigger,
|
trigger: workflowExecutionLogs.trigger,
|
||||||
startedAt: workflowExecutionLogs.startedAt,
|
startedAt: workflowExecutionLogs.startedAt,
|
||||||
@@ -71,6 +78,8 @@ export async function GET(request: NextRequest) {
|
|||||||
pausedStatus: pausedExecutions.status,
|
pausedStatus: pausedExecutions.status,
|
||||||
pausedTotalPauseCount: pausedExecutions.totalPauseCount,
|
pausedTotalPauseCount: pausedExecutions.totalPauseCount,
|
||||||
pausedResumedCount: pausedExecutions.resumedCount,
|
pausedResumedCount: pausedExecutions.resumedCount,
|
||||||
|
deploymentVersion: workflowDeploymentVersion.version,
|
||||||
|
deploymentVersionName: workflowDeploymentVersion.name,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
// Basic mode - exclude large fields for better performance
|
// Basic mode - exclude large fields for better performance
|
||||||
@@ -78,6 +87,7 @@ export async function GET(request: NextRequest) {
|
|||||||
workflowId: workflowExecutionLogs.workflowId,
|
workflowId: workflowExecutionLogs.workflowId,
|
||||||
executionId: workflowExecutionLogs.executionId,
|
executionId: workflowExecutionLogs.executionId,
|
||||||
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
stateSnapshotId: workflowExecutionLogs.stateSnapshotId,
|
||||||
|
deploymentVersionId: workflowExecutionLogs.deploymentVersionId,
|
||||||
level: workflowExecutionLogs.level,
|
level: workflowExecutionLogs.level,
|
||||||
trigger: workflowExecutionLogs.trigger,
|
trigger: workflowExecutionLogs.trigger,
|
||||||
startedAt: workflowExecutionLogs.startedAt,
|
startedAt: workflowExecutionLogs.startedAt,
|
||||||
@@ -98,6 +108,8 @@ export async function GET(request: NextRequest) {
|
|||||||
pausedStatus: pausedExecutions.status,
|
pausedStatus: pausedExecutions.status,
|
||||||
pausedTotalPauseCount: pausedExecutions.totalPauseCount,
|
pausedTotalPauseCount: pausedExecutions.totalPauseCount,
|
||||||
pausedResumedCount: pausedExecutions.resumedCount,
|
pausedResumedCount: pausedExecutions.resumedCount,
|
||||||
|
deploymentVersion: workflowDeploymentVersion.version,
|
||||||
|
deploymentVersionName: sql<null>`NULL`, // Only needed in full mode for details panel
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseQuery = db
|
const baseQuery = db
|
||||||
@@ -107,6 +119,10 @@ export async function GET(request: NextRequest) {
|
|||||||
pausedExecutions,
|
pausedExecutions,
|
||||||
eq(pausedExecutions.executionId, workflowExecutionLogs.executionId)
|
eq(pausedExecutions.executionId, workflowExecutionLogs.executionId)
|
||||||
)
|
)
|
||||||
|
.leftJoin(
|
||||||
|
workflowDeploymentVersion,
|
||||||
|
eq(workflowDeploymentVersion.id, workflowExecutionLogs.deploymentVersionId)
|
||||||
|
)
|
||||||
.innerJoin(
|
.innerJoin(
|
||||||
workflow,
|
workflow,
|
||||||
and(
|
and(
|
||||||
@@ -397,6 +413,9 @@ export async function GET(request: NextRequest) {
|
|||||||
id: log.id,
|
id: log.id,
|
||||||
workflowId: log.workflowId,
|
workflowId: log.workflowId,
|
||||||
executionId: log.executionId,
|
executionId: log.executionId,
|
||||||
|
deploymentVersionId: log.deploymentVersionId,
|
||||||
|
deploymentVersion: log.deploymentVersion ?? null,
|
||||||
|
deploymentVersionName: log.deploymentVersionName ?? null,
|
||||||
level: log.level,
|
level: log.level,
|
||||||
duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null,
|
duration: log.totalDurationMs ? `${log.totalDurationMs}ms` : null,
|
||||||
trigger: log.trigger,
|
trigger: log.trigger,
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export async function GET(request: NextRequest) {
|
|||||||
id: workflowExecutionLogs.id,
|
id: workflowExecutionLogs.id,
|
||||||
workflowId: workflowExecutionLogs.workflowId,
|
workflowId: workflowExecutionLogs.workflowId,
|
||||||
executionId: workflowExecutionLogs.executionId,
|
executionId: workflowExecutionLogs.executionId,
|
||||||
|
deploymentVersionId: workflowExecutionLogs.deploymentVersionId,
|
||||||
level: workflowExecutionLogs.level,
|
level: workflowExecutionLogs.level,
|
||||||
trigger: workflowExecutionLogs.trigger,
|
trigger: workflowExecutionLogs.trigger,
|
||||||
startedAt: workflowExecutionLogs.startedAt,
|
startedAt: workflowExecutionLogs.startedAt,
|
||||||
@@ -161,6 +162,7 @@ export async function GET(request: NextRequest) {
|
|||||||
id: log.id,
|
id: log.id,
|
||||||
workflowId: log.workflowId,
|
workflowId: log.workflowId,
|
||||||
executionId: log.executionId,
|
executionId: log.executionId,
|
||||||
|
deploymentVersionId: log.deploymentVersionId,
|
||||||
level: log.level,
|
level: log.level,
|
||||||
trigger: log.trigger,
|
trigger: log.trigger,
|
||||||
startedAt: log.startedAt.toISOString(),
|
startedAt: log.startedAt.toISOString(),
|
||||||
|
|||||||
@@ -430,6 +430,7 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
edges: any[]
|
edges: any[]
|
||||||
loops: Record<string, any>
|
loops: Record<string, any>
|
||||||
parallels: Record<string, any>
|
parallels: Record<string, any>
|
||||||
|
deploymentVersionId?: string
|
||||||
} | null = null
|
} | null = null
|
||||||
|
|
||||||
let processedInput = input
|
let processedInput = input
|
||||||
@@ -444,6 +445,10 @@ export async function POST(req: NextRequest, { params }: { params: Promise<{ id:
|
|||||||
edges: workflowData.edges,
|
edges: workflowData.edges,
|
||||||
loops: workflowData.loops || {},
|
loops: workflowData.loops || {},
|
||||||
parallels: workflowData.parallels || {},
|
parallels: workflowData.parallels || {},
|
||||||
|
deploymentVersionId:
|
||||||
|
!shouldUseDraftState && 'deploymentVersionId' in workflowData
|
||||||
|
? (workflowData.deploymentVersionId as string)
|
||||||
|
: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
const serializedWorkflow = new Serializer().serializeWorkflow(
|
const serializedWorkflow = new Serializer().serializeWorkflow(
|
||||||
|
|||||||
@@ -199,7 +199,7 @@ export function Knowledge() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-[24px] grid grid-cols-1 gap-x-[20px] gap-y-[40px] md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'>
|
<div className='mt-[24px] grid grid-cols-1 gap-[20px] md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<BaseCardSkeletonGrid count={8} />
|
<BaseCardSkeletonGrid count={8} />
|
||||||
) : filteredAndSortedKnowledgeBases.length === 0 ? (
|
) : filteredAndSortedKnowledgeBases.length === 0 ? (
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export function LineChart({
|
|||||||
}) {
|
}) {
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null)
|
const containerRef = useRef<HTMLDivElement | null>(null)
|
||||||
const uniqueId = useRef(`chart-${Math.random().toString(36).substring(2, 9)}`).current
|
const uniqueId = useRef(`chart-${Math.random().toString(36).substring(2, 9)}`).current
|
||||||
const [containerWidth, setContainerWidth] = useState<number>(420)
|
const [containerWidth, setContainerWidth] = useState<number | null>(null)
|
||||||
const width = containerWidth
|
const width = containerWidth ?? 0
|
||||||
const height = 166
|
const height = 166
|
||||||
const padding = { top: 16, right: 28, bottom: 26, left: 26 }
|
const padding = { top: 16, right: 28, bottom: 26, left: 26 }
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -39,14 +39,14 @@ export function LineChart({
|
|||||||
const element = containerRef.current
|
const element = containerRef.current
|
||||||
const ro = new ResizeObserver((entries) => {
|
const ro = new ResizeObserver((entries) => {
|
||||||
const entry = entries[0]
|
const entry = entries[0]
|
||||||
if (entry?.contentRect) {
|
if (entry?.contentRect && entry.contentRect.width > 0) {
|
||||||
const w = Math.max(280, Math.floor(entry.contentRect.width))
|
const w = Math.max(280, Math.floor(entry.contentRect.width))
|
||||||
setContainerWidth(w)
|
setContainerWidth(w)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
ro.observe(element)
|
ro.observe(element)
|
||||||
const rect = element.getBoundingClientRect()
|
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()
|
return () => ro.disconnect()
|
||||||
}, [])
|
}, [])
|
||||||
const chartWidth = width - padding.left - padding.right
|
const chartWidth = width - padding.left - padding.right
|
||||||
@@ -95,6 +95,16 @@ export function LineChart({
|
|||||||
|
|
||||||
const hasExternalWrapper = !label || label === ''
|
const hasExternalWrapper = !label || label === ''
|
||||||
|
|
||||||
|
if (containerWidth === null) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={containerRef}
|
||||||
|
className={cn('w-full', !hasExternalWrapper && 'rounded-lg border bg-card p-4')}
|
||||||
|
style={{ height }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -40,6 +40,14 @@ interface WorkflowExecution {
|
|||||||
const DEFAULT_SEGMENTS = 72
|
const DEFAULT_SEGMENTS = 72
|
||||||
const MIN_SEGMENT_PX = 10
|
const MIN_SEGMENT_PX = 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Predetermined heights for skeleton bars to avoid hydration mismatch.
|
||||||
|
* Using static values instead of Math.random() ensures server/client consistency.
|
||||||
|
*/
|
||||||
|
const SKELETON_BAR_HEIGHTS = [
|
||||||
|
45, 72, 38, 85, 52, 68, 30, 90, 55, 42, 78, 35, 88, 48, 65, 28, 82, 58, 40, 75, 32, 95, 50, 70,
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skeleton loader for a single graph card
|
* Skeleton loader for a single graph card
|
||||||
*/
|
*/
|
||||||
@@ -56,12 +64,12 @@ function GraphCardSkeleton({ title }: { title: string }) {
|
|||||||
<div className='flex h-[166px] flex-col justify-end gap-[4px]'>
|
<div className='flex h-[166px] flex-col justify-end gap-[4px]'>
|
||||||
{/* Skeleton bars simulating chart */}
|
{/* Skeleton bars simulating chart */}
|
||||||
<div className='flex items-end gap-[2px]'>
|
<div className='flex items-end gap-[2px]'>
|
||||||
{Array.from({ length: 24 }).map((_, i) => (
|
{SKELETON_BAR_HEIGHTS.map((height, i) => (
|
||||||
<Skeleton
|
<Skeleton
|
||||||
key={i}
|
key={i}
|
||||||
className='flex-1'
|
className='flex-1'
|
||||||
style={{
|
style={{
|
||||||
height: `${Math.random() * 80 + 20}%`,
|
height: `${height}%`,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -803,7 +811,6 @@ export default function Dashboard({
|
|||||||
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
||||||
{globalDetails ? (
|
{globalDetails ? (
|
||||||
<LineChart
|
<LineChart
|
||||||
key={`runs-${expandedWorkflowId || 'all'}-${Object.keys(selectedSegments).length}-${filteredExecutions.length}`}
|
|
||||||
data={globalDetails.executionCounts}
|
data={globalDetails.executionCounts}
|
||||||
label=''
|
label=''
|
||||||
color='var(--brand-tertiary)'
|
color='var(--brand-tertiary)'
|
||||||
@@ -832,7 +839,6 @@ export default function Dashboard({
|
|||||||
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
||||||
{globalDetails ? (
|
{globalDetails ? (
|
||||||
<LineChart
|
<LineChart
|
||||||
key={`errors-${expandedWorkflowId || 'all'}-${Object.keys(selectedSegments).length}-${filteredExecutions.length}`}
|
|
||||||
data={globalDetails.failureCounts}
|
data={globalDetails.failureCounts}
|
||||||
label=''
|
label=''
|
||||||
color='var(--text-error)'
|
color='var(--text-error)'
|
||||||
@@ -861,7 +867,6 @@ export default function Dashboard({
|
|||||||
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
<div className='flex-1 overflow-y-auto rounded-t-[6px] bg-[var(--surface-1)] px-[14px] py-[10px]'>
|
||||||
{globalDetails ? (
|
{globalDetails ? (
|
||||||
<LineChart
|
<LineChart
|
||||||
key={`latency-${expandedWorkflowId || 'all'}-${Object.keys(selectedSegments).length}-${filteredExecutions.length}`}
|
|
||||||
data={globalDetails.latencies}
|
data={globalDetails.latencies}
|
||||||
label=''
|
label=''
|
||||||
color='var(--c-F59E0B)'
|
color='var(--c-F59E0B)'
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ export function LogDetails({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Details Section */}
|
{/* Details Section */}
|
||||||
<div className='flex flex-col'>
|
<div className='flex min-w-0 flex-col overflow-hidden'>
|
||||||
{/* Level */}
|
{/* Level */}
|
||||||
<div className='flex h-[48px] items-center justify-between border-[var(--border)] border-b p-[8px]'>
|
<div className='flex h-[48px] items-center justify-between border-[var(--border)] border-b p-[8px]'>
|
||||||
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
||||||
@@ -233,14 +233,30 @@ export function LogDetails({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Duration */}
|
{/* Duration */}
|
||||||
<div className='flex h-[48px] items-center justify-between p-[8px]'>
|
<div
|
||||||
|
className={`flex h-[48px] items-center justify-between border-b p-[8px] ${log.deploymentVersion ? 'border-[var(--border)]' : 'border-transparent'}`}
|
||||||
|
>
|
||||||
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>
|
||||||
Duration
|
Duration
|
||||||
</span>
|
</span>
|
||||||
<span className='font-medium text-[14px] text-[var(--text-secondary)]'>
|
<span className='font-medium text-[13px] text-[var(--text-secondary)]'>
|
||||||
{log.duration || '—'}
|
{log.duration || '—'}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Version */}
|
||||||
|
{log.deploymentVersion && (
|
||||||
|
<div className='flex h-[48px] items-center gap-[8px] p-[8px]'>
|
||||||
|
<span className='flex-shrink-0 font-medium text-[12px] text-[var(--text-tertiary)]'>
|
||||||
|
Version
|
||||||
|
</span>
|
||||||
|
<div className='flex w-0 flex-1 justify-end'>
|
||||||
|
<span className='max-w-full truncate rounded-[6px] bg-[#14291B] px-[9px] py-[2px] font-medium text-[#86EFAC] text-[12px]'>
|
||||||
|
{log.deploymentVersionName || `v${log.deploymentVersion}`}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Workflow State */}
|
{/* Workflow State */}
|
||||||
|
|||||||
@@ -343,17 +343,18 @@ export function LogsToolbar({
|
|||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{/* View mode toggle */}
|
{/* View mode toggle */}
|
||||||
<div className='flex h-[32px] items-center rounded-[6px] border border-[var(--border)] bg-[var(--surface-elevated)] p-[2px]'>
|
<div
|
||||||
|
className='flex h-[32px] cursor-pointer items-center rounded-[6px] border border-[var(--border)] bg-[var(--surface-elevated)] p-[2px]'
|
||||||
|
onClick={() => onViewModeChange(isDashboardView ? 'logs' : 'dashboard')}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
variant={!isDashboardView ? 'active' : 'ghost'}
|
variant={!isDashboardView ? 'active' : 'ghost'}
|
||||||
onClick={() => onViewModeChange('logs')}
|
|
||||||
className='h-[26px] rounded-[4px] px-[10px]'
|
className='h-[26px] rounded-[4px] px-[10px]'
|
||||||
>
|
>
|
||||||
Logs
|
Logs
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant={isDashboardView ? 'active' : 'ghost'}
|
variant={isDashboardView ? 'active' : 'ghost'}
|
||||||
onClick={() => onViewModeChange('dashboard')}
|
|
||||||
className='h-[26px] rounded-[4px] px-[10px]'
|
className='h-[26px] rounded-[4px] px-[10px]'
|
||||||
>
|
>
|
||||||
Dashboard
|
Dashboard
|
||||||
|
|||||||
@@ -609,7 +609,7 @@ export default function Logs() {
|
|||||||
|
|
||||||
{/* Log Details - rendered inside table container */}
|
{/* Log Details - rendered inside table container */}
|
||||||
<LogDetails
|
<LogDetails
|
||||||
log={logDetailQuery.data || selectedLog}
|
log={logDetailQuery.data ? { ...selectedLog, ...logDetailQuery.data } : selectedLog}
|
||||||
isOpen={isSidebarOpen}
|
isOpen={isSidebarOpen}
|
||||||
onClose={handleCloseSidebar}
|
onClose={handleCloseSidebar}
|
||||||
onNavigateNext={handleNavigateNext}
|
onNavigateNext={handleNavigateNext}
|
||||||
|
|||||||
@@ -298,6 +298,8 @@ export function Terminal() {
|
|||||||
setOutputPanelWidth,
|
setOutputPanelWidth,
|
||||||
openOnRun,
|
openOnRun,
|
||||||
setOpenOnRun,
|
setOpenOnRun,
|
||||||
|
wrapText,
|
||||||
|
setWrapText,
|
||||||
setHasHydrated,
|
setHasHydrated,
|
||||||
} = useTerminalStore()
|
} = useTerminalStore()
|
||||||
const isExpanded = useTerminalStore((state) => state.terminalHeight > NEAR_MIN_THRESHOLD)
|
const isExpanded = useTerminalStore((state) => state.terminalHeight > NEAR_MIN_THRESHOLD)
|
||||||
@@ -312,7 +314,6 @@ export function Terminal() {
|
|||||||
const exportConsoleCSV = useTerminalConsoleStore((state) => state.exportConsoleCSV)
|
const exportConsoleCSV = useTerminalConsoleStore((state) => state.exportConsoleCSV)
|
||||||
const [selectedEntry, setSelectedEntry] = useState<ConsoleEntry | null>(null)
|
const [selectedEntry, setSelectedEntry] = useState<ConsoleEntry | null>(null)
|
||||||
const [isToggling, setIsToggling] = useState(false)
|
const [isToggling, setIsToggling] = useState(false)
|
||||||
const [wrapText, setWrapText] = useState(true)
|
|
||||||
const [showCopySuccess, setShowCopySuccess] = useState(false)
|
const [showCopySuccess, setShowCopySuccess] = useState(false)
|
||||||
const [showInput, setShowInput] = useState(false)
|
const [showInput, setShowInput] = useState(false)
|
||||||
const [autoSelectEnabled, setAutoSelectEnabled] = useState(true)
|
const [autoSelectEnabled, setAutoSelectEnabled] = useState(true)
|
||||||
@@ -1528,7 +1529,7 @@ export function Terminal() {
|
|||||||
showCheck
|
showCheck
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
setWrapText((prev) => !prev)
|
setWrapText(!wrapText)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>Wrap text</span>
|
<span>Wrap text</span>
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ async function runWorkflowExecution({
|
|||||||
const deployedData = await loadDeployedWorkflowState(payload.workflowId)
|
const deployedData = await loadDeployedWorkflowState(payload.workflowId)
|
||||||
|
|
||||||
const blocks = deployedData.blocks
|
const blocks = deployedData.blocks
|
||||||
|
const { deploymentVersionId } = deployedData
|
||||||
logger.info(`[${requestId}] Loaded deployed workflow ${payload.workflowId}`)
|
logger.info(`[${requestId}] Loaded deployed workflow ${payload.workflowId}`)
|
||||||
|
|
||||||
if (payload.blockId) {
|
if (payload.blockId) {
|
||||||
@@ -233,6 +234,7 @@ async function runWorkflowExecution({
|
|||||||
userId: actorUserId,
|
userId: actorUserId,
|
||||||
workspaceId: workflowRecord.workspaceId || '',
|
workspaceId: workflowRecord.workspaceId || '',
|
||||||
variables: variables || {},
|
variables: variables || {},
|
||||||
|
deploymentVersionId,
|
||||||
})
|
})
|
||||||
|
|
||||||
const metadata: ExecutionMetadata = {
|
const metadata: ExecutionMetadata = {
|
||||||
|
|||||||
@@ -138,18 +138,26 @@ async function executeWebhookJobInternal(
|
|||||||
requestId
|
requestId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Track deploymentVersionId at function scope so it's available in catch block
|
||||||
|
let deploymentVersionId: string | undefined
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const workflowData =
|
const useDraftState = payload.executionTarget === 'live'
|
||||||
payload.executionTarget === 'live'
|
const workflowData = useDraftState
|
||||||
? await loadWorkflowFromNormalizedTables(payload.workflowId)
|
? await loadWorkflowFromNormalizedTables(payload.workflowId)
|
||||||
: await loadDeployedWorkflowState(payload.workflowId)
|
: await loadDeployedWorkflowState(payload.workflowId)
|
||||||
if (!workflowData) {
|
if (!workflowData) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Workflow state not found. The workflow may not be ${payload.executionTarget === 'live' ? 'saved' : 'deployed'} or the deployment data may be corrupted.`
|
`Workflow state not found. The workflow may not be ${useDraftState ? 'saved' : 'deployed'} or the deployment data may be corrupted.`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { blocks, edges, loops, parallels } = workflowData
|
const { blocks, edges, loops, parallels } = workflowData
|
||||||
|
// Only deployed executions have a deployment version ID
|
||||||
|
deploymentVersionId =
|
||||||
|
!useDraftState && 'deploymentVersionId' in workflowData
|
||||||
|
? (workflowData.deploymentVersionId as string)
|
||||||
|
: undefined
|
||||||
|
|
||||||
const wfRows = await db
|
const wfRows = await db
|
||||||
.select({ workspaceId: workflowTable.workspaceId, variables: workflowTable.variables })
|
.select({ workspaceId: workflowTable.workspaceId, variables: workflowTable.variables })
|
||||||
@@ -229,6 +237,13 @@ async function executeWebhookJobInternal(
|
|||||||
useDraftState: false,
|
useDraftState: false,
|
||||||
startTime: new Date().toISOString(),
|
startTime: new Date().toISOString(),
|
||||||
isClientSession: false,
|
isClientSession: false,
|
||||||
|
workflowStateOverride: {
|
||||||
|
blocks,
|
||||||
|
edges,
|
||||||
|
loops: loops || {},
|
||||||
|
parallels: parallels || {},
|
||||||
|
deploymentVersionId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const snapshot = new ExecutionSnapshot(
|
const snapshot = new ExecutionSnapshot(
|
||||||
@@ -280,6 +295,18 @@ async function executeWebhookJobInternal(
|
|||||||
// No changes to process
|
// No changes to process
|
||||||
logger.info(`[${requestId}] No Airtable changes to process`)
|
logger.info(`[${requestId}] No Airtable changes to process`)
|
||||||
|
|
||||||
|
// Start logging session so the complete call has a log entry to update
|
||||||
|
await loggingSession.safeStart({
|
||||||
|
userId: payload.userId,
|
||||||
|
workspaceId: workspaceId || '',
|
||||||
|
variables: {},
|
||||||
|
triggerData: {
|
||||||
|
isTest: payload.testMode === true,
|
||||||
|
executionTarget: payload.executionTarget || 'deployed',
|
||||||
|
},
|
||||||
|
deploymentVersionId,
|
||||||
|
})
|
||||||
|
|
||||||
await loggingSession.safeComplete({
|
await loggingSession.safeComplete({
|
||||||
endedAt: new Date().toISOString(),
|
endedAt: new Date().toISOString(),
|
||||||
totalDurationMs: 0,
|
totalDurationMs: 0,
|
||||||
@@ -325,6 +352,19 @@ async function executeWebhookJobInternal(
|
|||||||
|
|
||||||
if (!input && payload.provider === 'whatsapp') {
|
if (!input && payload.provider === 'whatsapp') {
|
||||||
logger.info(`[${requestId}] No messages in WhatsApp payload, skipping execution`)
|
logger.info(`[${requestId}] No messages in WhatsApp payload, skipping execution`)
|
||||||
|
|
||||||
|
// Start logging session so the complete call has a log entry to update
|
||||||
|
await loggingSession.safeStart({
|
||||||
|
userId: payload.userId,
|
||||||
|
workspaceId: workspaceId || '',
|
||||||
|
variables: {},
|
||||||
|
triggerData: {
|
||||||
|
isTest: payload.testMode === true,
|
||||||
|
executionTarget: payload.executionTarget || 'deployed',
|
||||||
|
},
|
||||||
|
deploymentVersionId,
|
||||||
|
})
|
||||||
|
|
||||||
await loggingSession.safeComplete({
|
await loggingSession.safeComplete({
|
||||||
endedAt: new Date().toISOString(),
|
endedAt: new Date().toISOString(),
|
||||||
totalDurationMs: 0,
|
totalDurationMs: 0,
|
||||||
@@ -444,6 +484,13 @@ async function executeWebhookJobInternal(
|
|||||||
useDraftState: false,
|
useDraftState: false,
|
||||||
startTime: new Date().toISOString(),
|
startTime: new Date().toISOString(),
|
||||||
isClientSession: false,
|
isClientSession: false,
|
||||||
|
workflowStateOverride: {
|
||||||
|
blocks,
|
||||||
|
edges,
|
||||||
|
loops: loops || {},
|
||||||
|
parallels: parallels || {},
|
||||||
|
deploymentVersionId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const snapshot = new ExecutionSnapshot(metadata, workflow, input || {}, workflowVariables, [])
|
const snapshot = new ExecutionSnapshot(metadata, workflow, input || {}, workflowVariables, [])
|
||||||
@@ -495,7 +542,6 @@ async function executeWebhookJobInternal(
|
|||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Ensure logging session is started (safe to call multiple times)
|
|
||||||
await loggingSession.safeStart({
|
await loggingSession.safeStart({
|
||||||
userId: payload.userId,
|
userId: payload.userId,
|
||||||
workspaceId: '', // May not be available for early errors
|
workspaceId: '', // May not be available for early errors
|
||||||
@@ -504,6 +550,7 @@ async function executeWebhookJobInternal(
|
|||||||
isTest: payload.testMode === true,
|
isTest: payload.testMode === true,
|
||||||
executionTarget: payload.executionTarget || 'deployed',
|
executionTarget: payload.executionTarget || 'deployed',
|
||||||
},
|
},
|
||||||
|
deploymentVersionId, // Pass if available (undefined for early errors)
|
||||||
})
|
})
|
||||||
|
|
||||||
const executionResult = (error?.executionResult as ExecutionResult | undefined) || {
|
const executionResult = (error?.executionResult as ExecutionResult | undefined) || {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export interface ExecutionMetadata {
|
|||||||
edges: Edge[]
|
edges: Edge[]
|
||||||
loops?: Record<string, any>
|
loops?: Record<string, any>
|
||||||
parallels?: Record<string, any>
|
parallels?: Record<string, any>
|
||||||
|
deploymentVersionId?: string // ID of deployment version if this is deployed state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,11 +113,13 @@ export class ExecutionLogger implements IExecutionLoggerService {
|
|||||||
trigger: ExecutionTrigger
|
trigger: ExecutionTrigger
|
||||||
environment: ExecutionEnvironment
|
environment: ExecutionEnvironment
|
||||||
workflowState: WorkflowState
|
workflowState: WorkflowState
|
||||||
|
deploymentVersionId?: string
|
||||||
}): Promise<{
|
}): Promise<{
|
||||||
workflowLog: WorkflowExecutionLog
|
workflowLog: WorkflowExecutionLog
|
||||||
snapshot: WorkflowExecutionSnapshot
|
snapshot: WorkflowExecutionSnapshot
|
||||||
}> {
|
}> {
|
||||||
const { workflowId, executionId, trigger, environment, workflowState } = params
|
const { workflowId, executionId, trigger, environment, workflowState, deploymentVersionId } =
|
||||||
|
params
|
||||||
|
|
||||||
logger.debug(`Starting workflow execution ${executionId} for workflow ${workflowId}`)
|
logger.debug(`Starting workflow execution ${executionId} for workflow ${workflowId}`)
|
||||||
|
|
||||||
@@ -168,6 +170,7 @@ export class ExecutionLogger implements IExecutionLoggerService {
|
|||||||
workflowId,
|
workflowId,
|
||||||
executionId,
|
executionId,
|
||||||
stateSnapshotId: snapshotResult.snapshot.id,
|
stateSnapshotId: snapshotResult.snapshot.id,
|
||||||
|
deploymentVersionId: deploymentVersionId ?? null,
|
||||||
level: 'info',
|
level: 'info',
|
||||||
trigger: trigger.type,
|
trigger: trigger.type,
|
||||||
startedAt: startTime,
|
startedAt: startTime,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export interface SessionStartParams {
|
|||||||
variables?: Record<string, string>
|
variables?: Record<string, string>
|
||||||
triggerData?: Record<string, unknown>
|
triggerData?: Record<string, unknown>
|
||||||
skipLogCreation?: boolean // For resume executions - reuse existing log entry
|
skipLogCreation?: boolean // For resume executions - reuse existing log entry
|
||||||
|
deploymentVersionId?: string // ID of the deployment version used (null for manual/editor executions)
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SessionCompleteParams {
|
export interface SessionCompleteParams {
|
||||||
@@ -65,7 +66,8 @@ export class LoggingSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async start(params: SessionStartParams = {}): Promise<void> {
|
async start(params: SessionStartParams = {}): Promise<void> {
|
||||||
const { userId, workspaceId, variables, triggerData, skipLogCreation } = params
|
const { userId, workspaceId, variables, triggerData, skipLogCreation, deploymentVersionId } =
|
||||||
|
params
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.trigger = createTriggerObject(this.triggerType, triggerData)
|
this.trigger = createTriggerObject(this.triggerType, triggerData)
|
||||||
@@ -86,6 +88,7 @@ export class LoggingSession {
|
|||||||
trigger: this.trigger,
|
trigger: this.trigger,
|
||||||
environment: this.environment,
|
environment: this.environment,
|
||||||
workflowState: this.workflowState,
|
workflowState: this.workflowState,
|
||||||
|
deploymentVersionId,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.requestId) {
|
if (this.requestId) {
|
||||||
@@ -267,7 +270,7 @@ export class LoggingSession {
|
|||||||
|
|
||||||
// Fallback: create a minimal logging session without full workflow state
|
// Fallback: create a minimal logging session without full workflow state
|
||||||
try {
|
try {
|
||||||
const { userId, workspaceId, variables, triggerData } = params
|
const { userId, workspaceId, variables, triggerData, deploymentVersionId } = params
|
||||||
this.trigger = createTriggerObject(this.triggerType, triggerData)
|
this.trigger = createTriggerObject(this.triggerType, triggerData)
|
||||||
this.environment = createEnvironmentObject(
|
this.environment = createEnvironmentObject(
|
||||||
this.workflowId,
|
this.workflowId,
|
||||||
@@ -290,6 +293,7 @@ export class LoggingSession {
|
|||||||
trigger: this.trigger,
|
trigger: this.trigger,
|
||||||
environment: this.environment,
|
environment: this.environment,
|
||||||
workflowState: this.workflowState,
|
workflowState: this.workflowState,
|
||||||
|
deploymentVersionId,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.requestId) {
|
if (this.requestId) {
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ export async function executeWorkflowCore(
|
|||||||
let edges: Edge[]
|
let edges: Edge[]
|
||||||
let loops
|
let loops
|
||||||
let parallels
|
let parallels
|
||||||
|
let deploymentVersionId: string | undefined
|
||||||
|
|
||||||
// Use workflowStateOverride if provided (for diff workflows)
|
// Use workflowStateOverride if provided (for diff workflows)
|
||||||
if (metadata.workflowStateOverride) {
|
if (metadata.workflowStateOverride) {
|
||||||
@@ -118,6 +119,7 @@ export async function executeWorkflowCore(
|
|||||||
edges = metadata.workflowStateOverride.edges
|
edges = metadata.workflowStateOverride.edges
|
||||||
loops = metadata.workflowStateOverride.loops || {}
|
loops = metadata.workflowStateOverride.loops || {}
|
||||||
parallels = metadata.workflowStateOverride.parallels || {}
|
parallels = metadata.workflowStateOverride.parallels || {}
|
||||||
|
deploymentVersionId = metadata.workflowStateOverride.deploymentVersionId
|
||||||
|
|
||||||
logger.info(`[${requestId}] Using workflow state override (diff workflow execution)`, {
|
logger.info(`[${requestId}] Using workflow state override (diff workflow execution)`, {
|
||||||
blocksCount: Object.keys(blocks).length,
|
blocksCount: Object.keys(blocks).length,
|
||||||
@@ -144,6 +146,7 @@ export async function executeWorkflowCore(
|
|||||||
edges = deployedData.edges
|
edges = deployedData.edges
|
||||||
loops = deployedData.loops
|
loops = deployedData.loops
|
||||||
parallels = deployedData.parallels
|
parallels = deployedData.parallels
|
||||||
|
deploymentVersionId = deployedData.deploymentVersionId
|
||||||
|
|
||||||
logger.info(`[${requestId}] Using deployed workflow state (deployed execution)`)
|
logger.info(`[${requestId}] Using deployed workflow state (deployed execution)`)
|
||||||
}
|
}
|
||||||
@@ -174,6 +177,7 @@ export async function executeWorkflowCore(
|
|||||||
workspaceId: providedWorkspaceId,
|
workspaceId: providedWorkspaceId,
|
||||||
variables,
|
variables,
|
||||||
skipLogCreation, // Skip if resuming an existing execution
|
skipLogCreation, // Skip if resuming an existing execution
|
||||||
|
deploymentVersionId, // Only set for deployed executions
|
||||||
})
|
})
|
||||||
|
|
||||||
// Process block states with env var substitution using pre-decrypted values
|
// Process block states with env var substitution using pre-decrypted values
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export interface NormalizedWorkflowData {
|
|||||||
isFromNormalizedTables: boolean // Flag to indicate source (true = normalized tables, false = deployed state)
|
isFromNormalizedTables: boolean // Flag to indicate source (true = normalized tables, false = deployed state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DeployedWorkflowData extends NormalizedWorkflowData {
|
||||||
|
deploymentVersionId: string
|
||||||
|
}
|
||||||
|
|
||||||
export async function blockExistsInDeployment(
|
export async function blockExistsInDeployment(
|
||||||
workflowId: string,
|
workflowId: string,
|
||||||
blockId: string
|
blockId: string
|
||||||
@@ -68,12 +72,11 @@ export async function blockExistsInDeployment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadDeployedWorkflowState(
|
export async function loadDeployedWorkflowState(workflowId: string): Promise<DeployedWorkflowData> {
|
||||||
workflowId: string
|
|
||||||
): Promise<NormalizedWorkflowData> {
|
|
||||||
try {
|
try {
|
||||||
const [active] = await db
|
const [active] = await db
|
||||||
.select({
|
.select({
|
||||||
|
id: workflowDeploymentVersion.id,
|
||||||
state: workflowDeploymentVersion.state,
|
state: workflowDeploymentVersion.state,
|
||||||
createdAt: workflowDeploymentVersion.createdAt,
|
createdAt: workflowDeploymentVersion.createdAt,
|
||||||
})
|
})
|
||||||
@@ -99,6 +102,7 @@ export async function loadDeployedWorkflowState(
|
|||||||
loops: state.loops || {},
|
loops: state.loops || {},
|
||||||
parallels: state.parallels || {},
|
parallels: state.parallels || {},
|
||||||
isFromNormalizedTables: false,
|
isFromNormalizedTables: false,
|
||||||
|
deploymentVersionId: active.id,
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`Error loading deployed workflow state ${workflowId}:`, error)
|
logger.error(`Error loading deployed workflow state ${workflowId}:`, error)
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ export interface WorkflowLog {
|
|||||||
id: string
|
id: string
|
||||||
workflowId: string
|
workflowId: string
|
||||||
executionId?: string | null
|
executionId?: string | null
|
||||||
|
deploymentVersion?: number | null
|
||||||
|
deploymentVersionName?: string | null
|
||||||
level: string
|
level: string
|
||||||
duration: string | null
|
duration: string | null
|
||||||
trigger: string | null
|
trigger: string | null
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import { persist } from 'zustand/middleware'
|
|||||||
/**
|
/**
|
||||||
* Width constraints for the log details panel.
|
* Width constraints for the log details panel.
|
||||||
*/
|
*/
|
||||||
export const MIN_LOG_DETAILS_WIDTH = 340
|
export const MIN_LOG_DETAILS_WIDTH = 400
|
||||||
export const DEFAULT_LOG_DETAILS_WIDTH = 340
|
export const DEFAULT_LOG_DETAILS_WIDTH = 400
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum log details panel width (50vw).
|
* Returns the maximum log details panel width (50vw).
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ interface TerminalState {
|
|||||||
setOutputPanelWidth: (width: number) => void
|
setOutputPanelWidth: (width: number) => void
|
||||||
openOnRun: boolean
|
openOnRun: boolean
|
||||||
setOpenOnRun: (open: boolean) => void
|
setOpenOnRun: (open: boolean) => void
|
||||||
|
wrapText: boolean
|
||||||
|
setWrapText: (wrap: boolean) => void
|
||||||
/**
|
/**
|
||||||
* Indicates whether the terminal is currently being resized via mouse drag.
|
* Indicates whether the terminal is currently being resized via mouse drag.
|
||||||
*
|
*
|
||||||
@@ -35,8 +37,6 @@ interface TerminalState {
|
|||||||
* @param isResizing - True while the terminal is being resized.
|
* @param isResizing - True while the terminal is being resized.
|
||||||
*/
|
*/
|
||||||
setIsResizing: (isResizing: boolean) => void
|
setIsResizing: (isResizing: boolean) => void
|
||||||
// displayMode: DisplayMode
|
|
||||||
// setDisplayMode: (mode: DisplayMode) => void
|
|
||||||
_hasHydrated: boolean
|
_hasHydrated: boolean
|
||||||
setHasHydrated: (hasHydrated: boolean) => void
|
setHasHydrated: (hasHydrated: boolean) => void
|
||||||
}
|
}
|
||||||
@@ -119,10 +119,15 @@ export const useTerminalStore = create<TerminalState>()(
|
|||||||
setOpenOnRun: (open) => {
|
setOpenOnRun: (open) => {
|
||||||
set({ openOnRun: open })
|
set({ openOnRun: open })
|
||||||
},
|
},
|
||||||
// displayMode: DEFAULT_DISPLAY_MODE,
|
wrapText: true,
|
||||||
// setDisplayMode: (mode) => {
|
/**
|
||||||
// set({ displayMode: mode })
|
* Enables or disables text wrapping in the output panel.
|
||||||
// },
|
*
|
||||||
|
* @param wrap - Whether output text should wrap.
|
||||||
|
*/
|
||||||
|
setWrapText: (wrap) => {
|
||||||
|
set({ wrapText: wrap })
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Indicates whether the terminal store has finished client-side hydration.
|
* Indicates whether the terminal store has finished client-side hydration.
|
||||||
*/
|
*/
|
||||||
|
|||||||
3
packages/db/migrations/0121_new_mantis.sql
Normal file
3
packages/db/migrations/0121_new_mantis.sql
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE "workflow_execution_logs" ADD COLUMN "deployment_version_id" text;--> statement-breakpoint
|
||||||
|
ALTER TABLE "workflow_execution_logs" ADD CONSTRAINT "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk" FOREIGN KEY ("deployment_version_id") REFERENCES "public"."workflow_deployment_version"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||||
|
CREATE INDEX "workflow_execution_logs_deployment_version_id_idx" ON "workflow_execution_logs" USING btree ("deployment_version_id");
|
||||||
7816
packages/db/migrations/meta/0121_snapshot.json
Normal file
7816
packages/db/migrations/meta/0121_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -841,6 +841,13 @@
|
|||||||
"when": 1765339999291,
|
"when": 1765339999291,
|
||||||
"tag": "0120_illegal_moon_knight",
|
"tag": "0120_illegal_moon_knight",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 121,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1765434895472,
|
||||||
|
"tag": "0121_new_mantis",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,6 +293,10 @@ export const workflowExecutionLogs = pgTable(
|
|||||||
stateSnapshotId: text('state_snapshot_id')
|
stateSnapshotId: text('state_snapshot_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => workflowExecutionSnapshots.id),
|
.references(() => workflowExecutionSnapshots.id),
|
||||||
|
deploymentVersionId: text('deployment_version_id').references(
|
||||||
|
() => workflowDeploymentVersion.id,
|
||||||
|
{ onDelete: 'set null' }
|
||||||
|
),
|
||||||
|
|
||||||
level: text('level').notNull(), // 'info', 'error'
|
level: text('level').notNull(), // 'info', 'error'
|
||||||
trigger: text('trigger').notNull(), // 'api', 'webhook', 'schedule', 'manual', 'chat'
|
trigger: text('trigger').notNull(), // 'api', 'webhook', 'schedule', 'manual', 'chat'
|
||||||
@@ -311,6 +315,9 @@ export const workflowExecutionLogs = pgTable(
|
|||||||
stateSnapshotIdIdx: index('workflow_execution_logs_state_snapshot_id_idx').on(
|
stateSnapshotIdIdx: index('workflow_execution_logs_state_snapshot_id_idx').on(
|
||||||
table.stateSnapshotId
|
table.stateSnapshotId
|
||||||
),
|
),
|
||||||
|
deploymentVersionIdIdx: index('workflow_execution_logs_deployment_version_id_idx').on(
|
||||||
|
table.deploymentVersionId
|
||||||
|
),
|
||||||
triggerIdx: index('workflow_execution_logs_trigger_idx').on(table.trigger),
|
triggerIdx: index('workflow_execution_logs_trigger_idx').on(table.trigger),
|
||||||
levelIdx: index('workflow_execution_logs_level_idx').on(table.level),
|
levelIdx: index('workflow_execution_logs_level_idx').on(table.level),
|
||||||
startedAtIdx: index('workflow_execution_logs_started_at_idx').on(table.startedAt),
|
startedAtIdx: index('workflow_execution_logs_started_at_idx').on(table.startedAt),
|
||||||
|
|||||||
Reference in New Issue
Block a user