diff --git a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx index fa16d94240..7bdd7a526a 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx +++ b/apps/sim/app/workspace/[workspaceId]/logs/components/log-details/components/trace-spans/trace-spans.tsx @@ -234,7 +234,7 @@ function ProgressBar({ {segments.map((segment, index) => (
- + {log.deploymentVersionName || `v${log.deploymentVersion}`}
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 e5d50d6da2..11280214fb 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 @@ -19,6 +19,7 @@ import { DatePicker } from '@/components/emcn/components/date-picker/date-picker import { cn } from '@/lib/core/utils/cn' import { hasActiveFilters } from '@/lib/logs/filters' import { getTriggerOptions } from '@/lib/logs/get-trigger-options' +import { type LogStatus, STATUS_CONFIG } from '@/app/workspace/[workspaceId]/logs/utils' import { getBlock } from '@/blocks/registry' import { useFolderStore } from '@/stores/folders/store' import { useFilterStore } from '@/stores/logs/filters/store' @@ -211,12 +212,12 @@ export function LogsToolbar({ }, [level]) const statusOptions: ComboboxOption[] = useMemo( - () => [ - { value: 'error', label: 'Error', icon: getColorIcon('var(--text-error)') }, - { value: 'info', label: 'Info', icon: getColorIcon('var(--terminal-status-info-color)') }, - { value: 'running', label: 'Running', icon: getColorIcon('#22c55e') }, - { value: 'pending', label: 'Pending', icon: getColorIcon('#f59e0b') }, - ], + () => + (Object.keys(STATUS_CONFIG) as LogStatus[]).map((status) => ({ + value: status, + label: STATUS_CONFIG[status].label, + icon: getColorIcon(STATUS_CONFIG[status].color), + })), [] ) @@ -242,12 +243,8 @@ export function LogsToolbar({ const selectedStatusColor = useMemo(() => { if (selectedStatuses.length !== 1) return null - const status = selectedStatuses[0] - if (status === 'error') return 'var(--text-error)' - if (status === 'info') return 'var(--terminal-status-info-color)' - if (status === 'running') return '#22c55e' - if (status === 'pending') return '#f59e0b' - return null + const status = selectedStatuses[0] as LogStatus + return STATUS_CONFIG[status]?.color ?? null }, [selectedStatuses]) const workflowOptions: ComboboxOption[] = useMemo( diff --git a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts index 5c4d83c54e..ef7a8c544d 100644 --- a/apps/sim/app/workspace/[workspaceId]/logs/utils.ts +++ b/apps/sim/app/workspace/[workspaceId]/logs/utils.ts @@ -5,7 +5,6 @@ import { getIntegrationMetadata } from '@/lib/logs/get-trigger-options' import { getBlock } from '@/blocks/registry' import { CORE_TRIGGER_TYPES } from '@/stores/logs/filters/types' -/** Column configuration for logs table - shared between header and rows */ export const LOG_COLUMNS = { date: { width: 'w-[8%]', minWidth: 'min-w-[70px]', label: 'Date' }, time: { width: 'w-[12%]', minWidth: 'min-w-[90px]', label: 'Time' }, @@ -16,10 +15,8 @@ export const LOG_COLUMNS = { duration: { width: 'w-[20%]', minWidth: 'min-w-[100px]', label: 'Duration' }, } as const -/** Type-safe column key derived from LOG_COLUMNS */ export type LogColumnKey = keyof typeof LOG_COLUMNS -/** Ordered list of column keys for rendering table headers */ export const LOG_COLUMN_ORDER: readonly LogColumnKey[] = [ 'date', 'time', @@ -30,7 +27,6 @@ export const LOG_COLUMN_ORDER: readonly LogColumnKey[] = [ 'duration', ] as const -/** Possible execution status values for workflow logs */ export type LogStatus = 'error' | 'pending' | 'running' | 'info' | 'cancelled' /** @@ -53,30 +49,28 @@ export function getDisplayStatus(status: string | null | undefined): LogStatus { } } -/** Configuration mapping log status to Badge variant and display label */ -const STATUS_VARIANT_MAP: Record< +export const STATUS_CONFIG: Record< LogStatus, - { variant: React.ComponentProps['variant']; label: string } + { variant: React.ComponentProps['variant']; label: string; color: string } > = { - error: { variant: 'red', label: 'Error' }, - pending: { variant: 'amber', label: 'Pending' }, - running: { variant: 'green', label: 'Running' }, - cancelled: { variant: 'gray', label: 'Cancelled' }, - info: { variant: 'gray', label: 'Info' }, + error: { variant: 'red', label: 'Error', color: 'var(--text-error)' }, + pending: { variant: 'amber', label: 'Pending', color: '#f59e0b' }, + running: { variant: 'green', label: 'Running', color: '#22c55e' }, + cancelled: { variant: 'orange', label: 'Cancelled', color: '#f97316' }, + info: { variant: 'gray', label: 'Info', color: 'var(--terminal-status-info-color)' }, } -/** Configuration mapping core trigger types to Badge color variants */ const TRIGGER_VARIANT_MAP: Record['variant']> = { manual: 'gray-secondary', api: 'blue', schedule: 'green', chat: 'purple', webhook: 'orange', + mcp: 'cyan', a2a: 'teal', } interface StatusBadgeProps { - /** The execution status to display */ status: LogStatus } @@ -86,14 +80,13 @@ interface StatusBadgeProps { * @returns A Badge with dot indicator and status label */ export const StatusBadge = React.memo(({ status }: StatusBadgeProps) => { - const config = STATUS_VARIANT_MAP[status] + const config = STATUS_CONFIG[status] return React.createElement(Badge, { variant: config.variant, dot: true }, config.label) }) StatusBadge.displayName = 'StatusBadge' interface TriggerBadgeProps { - /** The trigger type identifier (e.g., 'manual', 'api', or integration block type) */ trigger: string } diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx index 835cf02184..59b3e5b091 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx @@ -142,7 +142,7 @@ export const ActionBar = memo( )} - {!isStartBlock && !isResponseBlock && !isSubflowBlock && ( + {!isStartBlock && !isResponseBlock && ( + + + {getTooltipMessage(isEnabled ? 'Disable Block' : 'Enable Block')} + + + )} +
+ {!isEnabled && disabled} {!isPreview && ( diff --git a/apps/sim/components/emcn/components/badge/badge.tsx b/apps/sim/components/emcn/components/badge/badge.tsx index 7b728df058..22ea477174 100644 --- a/apps/sim/components/emcn/components/badge/badge.tsx +++ b/apps/sim/components/emcn/components/badge/badge.tsx @@ -25,7 +25,7 @@ const badgeVariants = cva( orange: `${STATUS_BASE} bg-[#fed7aa] text-[#c2410c] dark:bg-[rgba(249,115,22,0.2)] dark:text-[#fdba74]`, amber: `${STATUS_BASE} bg-[#fde68a] text-[#a16207] dark:bg-[rgba(245,158,11,0.2)] dark:text-[#fcd34d]`, teal: `${STATUS_BASE} bg-[#99f6e4] text-[#0f766e] dark:bg-[rgba(20,184,166,0.2)] dark:text-[#5eead4]`, - cyan: `${STATUS_BASE} bg-[#a5f3fc] text-[#0e7490] dark:bg-[rgba(14,165,233,0.2)] dark:text-[#7dd3fc]`, + cyan: `${STATUS_BASE} bg-[var(--surface-4)] text-[#0891b2] dark:bg-[rgba(14,165,233,0.2)] dark:text-[#7dd3fc]`, 'gray-secondary': `${STATUS_BASE} bg-[var(--surface-4)] text-[var(--text-secondary)]`, }, size: { diff --git a/apps/sim/lib/workflows/persistence/utils.test.ts b/apps/sim/lib/workflows/persistence/utils.test.ts index a908056757..d95cd633a9 100644 --- a/apps/sim/lib/workflows/persistence/utils.test.ts +++ b/apps/sim/lib/workflows/persistence/utils.test.ts @@ -376,6 +376,7 @@ describe('Database Helpers', () => { forEachItems: '', doWhileCondition: '', whileCondition: '', + enabled: true, }) expect(result?.parallels['parallel-1']).toEqual({ @@ -384,6 +385,7 @@ describe('Database Helpers', () => { count: 5, distribution: ['item1', 'item2'], parallelType: 'count', + enabled: true, }) }) diff --git a/apps/sim/lib/workflows/persistence/utils.ts b/apps/sim/lib/workflows/persistence/utils.ts index d3b26e4ea6..cd1d4500ef 100644 --- a/apps/sim/lib/workflows/persistence/utils.ts +++ b/apps/sim/lib/workflows/persistence/utils.ts @@ -273,6 +273,7 @@ export async function loadWorkflowFromNormalizedTables( forEachItems: (config as Loop).forEachItems ?? '', whileCondition: (config as Loop).whileCondition ?? '', doWhileCondition: (config as Loop).doWhileCondition ?? '', + enabled: migratedBlocks[subflow.id]?.enabled ?? true, } loops[subflow.id] = loop @@ -301,6 +302,7 @@ export async function loadWorkflowFromNormalizedTables( (config as Parallel).parallelType === 'collection' ? (config as Parallel).parallelType : 'count', + enabled: migratedBlocks[subflow.id]?.enabled ?? true, } parallels[subflow.id] = parallel } else { diff --git a/apps/sim/stores/logs/filters/types.ts b/apps/sim/stores/logs/filters/types.ts index dde0bb9303..f533b69961 100644 --- a/apps/sim/stores/logs/filters/types.ts +++ b/apps/sim/stores/logs/filters/types.ts @@ -172,7 +172,14 @@ export type TimeRange = | 'All time' | 'Custom range' -export type LogLevel = 'error' | 'info' | 'running' | 'pending' | 'all' | (string & {}) +export type LogLevel = + | 'error' + | 'info' + | 'running' + | 'pending' + | 'cancelled' + | 'all' + | (string & {}) /** Core trigger types for workflow execution */ export const CORE_TRIGGER_TYPES = [ 'manual', diff --git a/apps/sim/stores/workflows/workflow/types.ts b/apps/sim/stores/workflows/workflow/types.ts index fae9a4a4a0..c5d99e17ab 100644 --- a/apps/sim/stores/workflows/workflow/types.ts +++ b/apps/sim/stores/workflows/workflow/types.ts @@ -130,6 +130,7 @@ export interface Loop { forEachItems?: any[] | Record | string // Items or expression whileCondition?: string // JS expression that evaluates to boolean (for while loops) doWhileCondition?: string // JS expression that evaluates to boolean (for do-while loops) + enabled: boolean } export interface Parallel { @@ -138,6 +139,7 @@ export interface Parallel { distribution?: any[] | Record | string // Items or expression count?: number // Number of parallel executions for count-based parallel parallelType?: 'count' | 'collection' // Explicit parallel type to avoid inference bugs + enabled: boolean } export interface Variable { diff --git a/apps/sim/stores/workflows/workflow/utils.ts b/apps/sim/stores/workflows/workflow/utils.ts index 2105a0f636..dc200792a2 100644 --- a/apps/sim/stores/workflows/workflow/utils.ts +++ b/apps/sim/stores/workflows/workflow/utils.ts @@ -72,6 +72,7 @@ export function convertLoopBlockToLoop( nodes: findChildNodes(loopBlockId, blocks), iterations: loopBlock.data?.count || DEFAULT_LOOP_ITERATIONS, loopType, + enabled: loopBlock.enabled, } loop.forEachItems = loopBlock.data?.collection || '' @@ -113,6 +114,7 @@ export function convertParallelBlockToParallel( distribution, count, parallelType: validatedParallelType, + enabled: parallelBlock.enabled, } }