@@ -5,10 +5,15 @@ import { getIntegrationMetadata } from '@/lib/logs/get-trigger-options'
55import { getBlock } from '@/blocks/registry'
66
77const CORE_TRIGGER_TYPES = [ 'manual' , 'api' , 'schedule' , 'chat' , 'webhook' ] as const
8- const RUNNING_COLOR = '#22c55e' as const
9- const PENDING_COLOR = '#f59e0b' as const
8+
9+ /** Possible execution status values for workflow logs */
1010export type LogStatus = 'error' | 'pending' | 'running' | 'info' | 'cancelled'
1111
12+ /**
13+ * Maps raw status string to LogStatus for display.
14+ * @param status - Raw status from API
15+ * @returns Normalized LogStatus value
16+ */
1217export function getDisplayStatus ( status : string | null | undefined ) : LogStatus {
1318 switch ( status ) {
1419 case 'running' :
@@ -24,146 +29,75 @@ export function getDisplayStatus(status: string | null | undefined): LogStatus {
2429 }
2530}
2631
27- /**
28- * Checks if a hex color is gray/neutral (low saturation) or too light/dark
29- */
30- export function isGrayOrNeutral ( hex : string ) : boolean {
31- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
32- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
33- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
34-
35- const max = Math . max ( r , g , b )
36- const min = Math . min ( r , g , b )
37- const lightness = ( max + min ) / 2 / 255
38-
39- const delta = max - min
40- const saturation = delta === 0 ? 0 : delta / ( 1 - Math . abs ( 2 * lightness - 1 ) ) / 255
41-
42- return saturation < 0.2 || lightness > 0.8 || lightness < 0.25
32+ /** Configuration mapping log status to Badge variant and display label */
33+ const STATUS_VARIANT_MAP : Record <
34+ LogStatus ,
35+ { variant : React . ComponentProps < typeof Badge > [ 'variant' ] ; label : string }
36+ > = {
37+ error : { variant : 'red' , label : 'Error' } ,
38+ pending : { variant : 'amber' , label : 'Pending' } ,
39+ running : { variant : 'green' , label : 'Running' } ,
40+ cancelled : { variant : 'gray' , label : 'Cancelled' } ,
41+ info : { variant : 'gray' , label : 'Info' } ,
4342}
4443
45- /**
46- * Converts a hex color to a background variant with appropriate opacity
47- */
48- export function hexToBackground ( hex : string ) : string {
49- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
50- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
51- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
52- return `rgba(${ r } , ${ g } , ${ b } , 0.2)`
53- }
54-
55- /**
56- * Lightens a hex color to make it more vibrant for text
57- */
58- export function lightenColor ( hex : string , percent = 30 ) : string {
59- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
60- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
61- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
62-
63- const newR = Math . min ( 255 , Math . round ( r + ( 255 - r ) * ( percent / 100 ) ) )
64- const newG = Math . min ( 255 , Math . round ( g + ( 255 - g ) * ( percent / 100 ) ) )
65- const newB = Math . min ( 255 , Math . round ( b + ( 255 - b ) * ( percent / 100 ) ) )
66-
67- return `#${ newR . toString ( 16 ) . padStart ( 2 , '0' ) } ${ newG . toString ( 16 ) . padStart ( 2 , '0' ) } ${ newB . toString ( 16 ) . padStart ( 2 , '0' ) } `
44+ /** Configuration mapping core trigger types to Badge color variants */
45+ const TRIGGER_VARIANT_MAP : Record < string , React . ComponentProps < typeof Badge > [ 'variant' ] > = {
46+ manual : 'gray-secondary' ,
47+ api : 'blue' ,
48+ schedule : 'teal' ,
49+ chat : 'purple' ,
50+ webhook : 'orange' ,
6851}
6952
7053interface StatusBadgeProps {
54+ /** The execution status to display */
7155 status : LogStatus
7256}
7357
7458/**
75- * Displays a styled badge for a log execution status
59+ * Renders a colored badge indicating log execution status.
60+ * @param props - Component props containing the status
61+ * @returns A Badge with dot indicator and status label
7662 */
7763export const StatusBadge = React . memo ( ( { status } : StatusBadgeProps ) => {
78- const config = {
79- error : {
80- bg : 'var(--terminal-status-error-bg)' ,
81- color : 'var(--text-error)' ,
82- label : 'Error' ,
83- } ,
84- pending : {
85- bg : hexToBackground ( PENDING_COLOR ) ,
86- color : lightenColor ( PENDING_COLOR , 65 ) ,
87- label : 'Pending' ,
88- } ,
89- running : {
90- bg : hexToBackground ( RUNNING_COLOR ) ,
91- color : lightenColor ( RUNNING_COLOR , 65 ) ,
92- label : 'Running' ,
93- } ,
94- cancelled : {
95- bg : 'var(--terminal-status-info-bg)' ,
96- color : 'var(--terminal-status-info-color)' ,
97- label : 'Cancelled' ,
98- } ,
99- info : {
100- bg : 'var(--terminal-status-info-bg)' ,
101- color : 'var(--terminal-status-info-color)' ,
102- label : 'Info' ,
103- } ,
104- } [ status ]
105-
106- return React . createElement (
107- 'div' ,
108- {
109- className :
110- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
111- style : { backgroundColor : config . bg , color : config . color } ,
112- } ,
113- React . createElement ( 'div' , {
114- className : 'h-[6px] w-[6px] rounded-[2px]' ,
115- style : { backgroundColor : config . color } ,
116- } ) ,
117- config . label
118- )
64+ const config = STATUS_VARIANT_MAP [ status ]
65+ return React . createElement ( Badge , { variant : config . variant , dot : true } , config . label )
11966} )
12067
12168StatusBadge . displayName = 'StatusBadge'
12269
12370interface TriggerBadgeProps {
71+ /** The trigger type identifier (e.g., 'manual', 'api', or integration block type) */
12472 trigger : string
12573}
12674
12775/**
128- * Displays a styled badge for a workflow trigger type
76+ * Renders a colored badge indicating the workflow trigger type.
77+ * Core triggers display with their designated colors; integrations show with icons.
78+ * @param props - Component props containing the trigger type
79+ * @returns A Badge with appropriate styling for the trigger type
12980 */
13081export const TriggerBadge = React . memo ( ( { trigger } : TriggerBadgeProps ) => {
13182 const metadata = getIntegrationMetadata ( trigger )
13283 const isIntegration = ! ( CORE_TRIGGER_TYPES as readonly string [ ] ) . includes ( trigger )
13384 const block = isIntegration ? getBlock ( trigger ) : null
13485 const IconComponent = block ?. icon
13586
136- const isUnknownIntegration = isIntegration && trigger !== 'generic' && ! block
137- if (
138- trigger === 'manual' ||
139- trigger === 'generic' ||
140- isUnknownIntegration ||
141- isGrayOrNeutral ( metadata . color )
142- ) {
87+ const coreVariant = TRIGGER_VARIANT_MAP [ trigger ]
88+ if ( coreVariant ) {
89+ return React . createElement ( Badge , { variant : coreVariant } , metadata . label )
90+ }
91+
92+ if ( IconComponent ) {
14393 return React . createElement (
14494 Badge ,
145- {
146- variant : 'default' ,
147- className :
148- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
149- } ,
150- IconComponent && React . createElement ( IconComponent , { className : 'h-[12px] w-[12px]' } ) ,
95+ { variant : 'gray-secondary' , icon : IconComponent } ,
15196 metadata . label
15297 )
15398 }
15499
155- const textColor = lightenColor ( metadata . color , 65 )
156-
157- return React . createElement (
158- 'div' ,
159- {
160- className :
161- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
162- style : { backgroundColor : hexToBackground ( metadata . color ) , color : textColor } ,
163- } ,
164- IconComponent && React . createElement ( IconComponent , { className : 'h-[12px] w-[12px]' } ) ,
165- metadata . label
166- )
100+ return React . createElement ( Badge , { variant : 'gray-secondary' } , metadata . label )
167101} )
168102
169103TriggerBadge . displayName = 'TriggerBadge'
0 commit comments