@@ -36,6 +36,7 @@ import {
3636 Tooltip ,
3737} from '@/components/emcn'
3838import { getEnv , isTruthy } from '@/lib/core/config/env'
39+ import { formatTimeWithSeconds } from '@/lib/core/utils/formatting'
3940import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
4041import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils'
4142import {
@@ -82,18 +83,6 @@ const COLUMN_WIDTHS = {
8283 OUTPUT_PANEL : 'w-[400px]' ,
8384} as const
8485
85- /**
86- * Color palette for run IDs - matching code syntax highlighting colors
87- */
88- const RUN_ID_COLORS = [
89- { text : '#4ADE80' } , // Green
90- { text : '#F472B6' } , // Pink
91- { text : '#60C5FF' } , // Blue
92- { text : '#FF8533' } , // Orange
93- { text : '#C084FC' } , // Purple
94- { text : '#FCD34D' } , // Yellow
95- ] as const
96-
9786/**
9887 * Shared styling constants
9988 */
@@ -183,22 +172,6 @@ const ToggleButton = ({
183172 </ Button >
184173)
185174
186- /**
187- * Formats timestamp to H:MM:SS AM/PM TZ format
188- */
189- const formatTimestamp = ( timestamp : string ) : string => {
190- const date = new Date ( timestamp )
191- const fullString = date . toLocaleTimeString ( 'en-US' , {
192- hour : 'numeric' ,
193- minute : '2-digit' ,
194- second : '2-digit' ,
195- hour12 : true ,
196- timeZoneName : 'short' ,
197- } )
198- // Format: "5:54:55 PM PST" - return as is
199- return fullString
200- }
201-
202175/**
203176 * Truncates execution ID for display as run ID
204177 */
@@ -208,16 +181,25 @@ const formatRunId = (executionId?: string): string => {
208181}
209182
210183/**
211- * Gets color for a run ID based on its index in the execution ID order map
184+ * Run ID colors
185+ */
186+ const RUN_ID_COLORS = [
187+ '#4ADE80' , // Green
188+ '#F472B6' , // Pink
189+ '#60C5FF' , // Blue
190+ '#FF8533' , // Orange
191+ '#C084FC' , // Purple
192+ '#EAB308' , // Yellow
193+ '#2DD4BF' , // Teal
194+ '#FB7185' , // Rose
195+ ] as const
196+
197+ /**
198+ * Gets color for a run ID from the precomputed color map.
212199 */
213- const getRunIdColor = (
214- executionId : string | undefined ,
215- executionIdOrderMap : Map < string , number >
216- ) => {
200+ const getRunIdColor = ( executionId : string | undefined , colorMap : Map < string , string > ) => {
217201 if ( ! executionId ) return null
218- const colorIndex = executionIdOrderMap . get ( executionId )
219- if ( colorIndex === undefined ) return null
220- return RUN_ID_COLORS [ colorIndex % RUN_ID_COLORS . length ]
202+ return colorMap . get ( executionId ) ?? null
221203}
222204
223205/**
@@ -464,25 +446,52 @@ export function Terminal() {
464446 } , [ allWorkflowEntries ] )
465447
466448 /**
467- * Create stable execution ID to color index mapping based on order of first appearance.
468- * Once an execution ID is assigned a color index, it keeps that index.
469- * Uses all workflow entries to maintain consistent colors regardless of active filters.
449+ * Track color offset - increments when old executions are trimmed
450+ * so remaining executions keep their colors.
470451 */
471- const executionIdOrderMap = useMemo ( ( ) => {
472- const orderMap = new Map < string , number > ( )
473- let colorIndex = 0
452+ const colorStateRef = useRef < { executionIds : string [ ] ; offset : number } > ( {
453+ executionIds : [ ] ,
454+ offset : 0 ,
455+ } )
474456
475- // Process entries in reverse order (oldest first) since entries array is newest-first
476- // Use allWorkflowEntries to ensure colors remain consistent when filters change
457+ /**
458+ * Compute colors for each execution ID using sequential assignment.
459+ * Colors cycle through RUN_ID_COLORS based on position + offset.
460+ * When old executions are trimmed, offset increments to preserve colors.
461+ */
462+ const executionColorMap = useMemo ( ( ) => {
463+ const currentIds : string [ ] = [ ]
464+ const seen = new Set < string > ( )
477465 for ( let i = allWorkflowEntries . length - 1 ; i >= 0 ; i -- ) {
478- const entry = allWorkflowEntries [ i ]
479- if ( entry . executionId && ! orderMap . has ( entry . executionId ) ) {
480- orderMap . set ( entry . executionId , colorIndex )
481- colorIndex ++
466+ const execId = allWorkflowEntries [ i ] . executionId
467+ if ( execId && ! seen . has ( execId ) ) {
468+ currentIds . push ( execId )
469+ seen . add ( execId )
482470 }
483471 }
484472
485- return orderMap
473+ const { executionIds : prevIds , offset : prevOffset } = colorStateRef . current
474+ let newOffset = prevOffset
475+
476+ if ( prevIds . length > 0 && currentIds . length > 0 ) {
477+ const currentOldest = currentIds [ 0 ]
478+ if ( prevIds [ 0 ] !== currentOldest ) {
479+ const trimmedCount = prevIds . indexOf ( currentOldest )
480+ if ( trimmedCount > 0 ) {
481+ newOffset = ( prevOffset + trimmedCount ) % RUN_ID_COLORS . length
482+ }
483+ }
484+ }
485+
486+ const colorMap = new Map < string , string > ( )
487+ for ( let i = 0 ; i < currentIds . length ; i ++ ) {
488+ const colorIndex = ( newOffset + i ) % RUN_ID_COLORS . length
489+ colorMap . set ( currentIds [ i ] , RUN_ID_COLORS [ colorIndex ] )
490+ }
491+
492+ colorStateRef . current = { executionIds : currentIds , offset : newOffset }
493+
494+ return colorMap
486495 } , [ allWorkflowEntries ] )
487496
488497 /**
@@ -1128,7 +1137,7 @@ export function Terminal() {
11281137 < PopoverScrollArea style = { { maxHeight : '140px' } } >
11291138 { uniqueRunIds . map ( ( runId , index ) => {
11301139 const isSelected = filters . runIds . has ( runId )
1131- const runIdColor = getRunIdColor ( runId , executionIdOrderMap )
1140+ const runIdColor = getRunIdColor ( runId , executionColorMap )
11321141
11331142 return (
11341143 < PopoverItem
@@ -1139,7 +1148,7 @@ export function Terminal() {
11391148 >
11401149 < span
11411150 className = 'flex-1 font-mono text-[12px]'
1142- style = { { color : runIdColor ?. text || '#D2D2D2' } }
1151+ style = { { color : runIdColor || '#D2D2D2' } }
11431152 >
11441153 { formatRunId ( runId ) }
11451154 </ span >
@@ -1335,7 +1344,7 @@ export function Terminal() {
13351344 const statusInfo = getStatusInfo ( entry . success , entry . error )
13361345 const isSelected = selectedEntry ?. id === entry . id
13371346 const BlockIcon = getBlockIcon ( entry . blockType )
1338- const runIdColor = getRunIdColor ( entry . executionId , executionIdOrderMap )
1347+ const runIdColor = getRunIdColor ( entry . executionId , executionColorMap )
13391348
13401349 return (
13411350 < div
@@ -1385,7 +1394,7 @@ export function Terminal() {
13851394 COLUMN_BASE_CLASS ,
13861395 'truncate font-medium font-mono text-[12px]'
13871396 ) }
1388- style = { { color : runIdColor ?. text || '#D2D2D2' } }
1397+ style = { { color : runIdColor || '#D2D2D2' } }
13891398 >
13901399 { formatRunId ( entry . executionId ) }
13911400 </ span >
@@ -1411,7 +1420,7 @@ export function Terminal() {
14111420 ROW_TEXT_CLASS
14121421 ) }
14131422 >
1414- { formatTimestamp ( entry . timestamp ) }
1423+ { formatTimeWithSeconds ( new Date ( entry . timestamp ) ) }
14151424 </ span >
14161425 </ div >
14171426 )
0 commit comments