@@ -5,146 +5,78 @@ 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
108
9+ /** Possible execution status values for workflow logs */
1110export type LogStatus = 'error' | 'pending' | 'running' | 'info'
1211
13- /**
14- * Checks if a hex color is gray/neutral (low saturation) or too light/dark
15- */
16- export function isGrayOrNeutral ( hex : string ) : boolean {
17- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
18- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
19- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
20-
21- const max = Math . max ( r , g , b )
22- const min = Math . min ( r , g , b )
23- const lightness = ( max + min ) / 2 / 255
24-
25- const delta = max - min
26- const saturation = delta === 0 ? 0 : delta / ( 1 - Math . abs ( 2 * lightness - 1 ) ) / 255
27-
28- return saturation < 0.2 || lightness > 0.8 || lightness < 0.25
29- }
30-
31- /**
32- * Converts a hex color to a background variant with appropriate opacity
33- */
34- export function hexToBackground ( hex : string ) : string {
35- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
36- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
37- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
38- return `rgba(${ r } , ${ g } , ${ b } , 0.2)`
12+ /** Configuration mapping log status to Badge variant and display label */
13+ const STATUS_VARIANT_MAP : Record <
14+ LogStatus ,
15+ { variant : React . ComponentProps < typeof Badge > [ 'variant' ] ; label : string }
16+ > = {
17+ error : { variant : 'red' , label : 'Error' } ,
18+ pending : { variant : 'amber' , label : 'Pending' } ,
19+ running : { variant : 'green' , label : 'Running' } ,
20+ info : { variant : 'gray' , label : 'Info' } ,
3921}
4022
41- /**
42- * Lightens a hex color to make it more vibrant for text
43- */
44- export function lightenColor ( hex : string , percent = 30 ) : string {
45- const r = Number . parseInt ( hex . slice ( 1 , 3 ) , 16 )
46- const g = Number . parseInt ( hex . slice ( 3 , 5 ) , 16 )
47- const b = Number . parseInt ( hex . slice ( 5 , 7 ) , 16 )
48-
49- const newR = Math . min ( 255 , Math . round ( r + ( 255 - r ) * ( percent / 100 ) ) )
50- const newG = Math . min ( 255 , Math . round ( g + ( 255 - g ) * ( percent / 100 ) ) )
51- const newB = Math . min ( 255 , Math . round ( b + ( 255 - b ) * ( percent / 100 ) ) )
52-
53- return `#${ newR . toString ( 16 ) . padStart ( 2 , '0' ) } ${ newG . toString ( 16 ) . padStart ( 2 , '0' ) } ${ newB . toString ( 16 ) . padStart ( 2 , '0' ) } `
23+ /** Configuration mapping core trigger types to Badge color variants */
24+ const TRIGGER_VARIANT_MAP : Record < string , React . ComponentProps < typeof Badge > [ 'variant' ] > = {
25+ manual : 'gray-secondary' ,
26+ api : 'blue' ,
27+ schedule : 'teal' ,
28+ chat : 'purple' ,
29+ webhook : 'orange' ,
5430}
5531
5632interface StatusBadgeProps {
33+ /** The execution status to display */
5734 status : LogStatus
5835}
5936
6037/**
61- * Displays a styled badge for a log execution status
38+ * Renders a colored badge indicating log execution status.
39+ * @param props - Component props containing the status
40+ * @returns A Badge with dot indicator and status label
6241 */
6342export const StatusBadge = React . memo ( ( { status } : StatusBadgeProps ) => {
64- const config = {
65- error : {
66- bg : 'var(--terminal-status-error-bg)' ,
67- color : 'var(--text-error)' ,
68- label : 'Error' ,
69- } ,
70- pending : {
71- bg : hexToBackground ( PENDING_COLOR ) ,
72- color : lightenColor ( PENDING_COLOR , 65 ) ,
73- label : 'Pending' ,
74- } ,
75- running : {
76- bg : hexToBackground ( RUNNING_COLOR ) ,
77- color : lightenColor ( RUNNING_COLOR , 65 ) ,
78- label : 'Running' ,
79- } ,
80- info : {
81- bg : 'var(--terminal-status-info-bg)' ,
82- color : 'var(--terminal-status-info-color)' ,
83- label : 'Info' ,
84- } ,
85- } [ status ]
86-
87- return React . createElement (
88- 'div' ,
89- {
90- className :
91- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
92- style : { backgroundColor : config . bg , color : config . color } ,
93- } ,
94- React . createElement ( 'div' , {
95- className : 'h-[6px] w-[6px] rounded-[2px]' ,
96- style : { backgroundColor : config . color } ,
97- } ) ,
98- config . label
99- )
43+ const config = STATUS_VARIANT_MAP [ status ]
44+ return React . createElement ( Badge , { variant : config . variant , dot : true } , config . label )
10045} )
10146
10247StatusBadge . displayName = 'StatusBadge'
10348
10449interface TriggerBadgeProps {
50+ /** The trigger type identifier (e.g., 'manual', 'api', or integration block type) */
10551 trigger : string
10652}
10753
10854/**
109- * Displays a styled badge for a workflow trigger type
55+ * Renders a colored badge indicating the workflow trigger type.
56+ * Core triggers display with their designated colors; integrations show with icons.
57+ * @param props - Component props containing the trigger type
58+ * @returns A Badge with appropriate styling for the trigger type
11059 */
11160export const TriggerBadge = React . memo ( ( { trigger } : TriggerBadgeProps ) => {
11261 const metadata = getIntegrationMetadata ( trigger )
11362 const isIntegration = ! ( CORE_TRIGGER_TYPES as readonly string [ ] ) . includes ( trigger )
11463 const block = isIntegration ? getBlock ( trigger ) : null
11564 const IconComponent = block ?. icon
11665
117- const isUnknownIntegration = isIntegration && trigger !== 'generic' && ! block
118- if (
119- trigger === 'manual' ||
120- trigger === 'generic' ||
121- isUnknownIntegration ||
122- isGrayOrNeutral ( metadata . color )
123- ) {
66+ const coreVariant = TRIGGER_VARIANT_MAP [ trigger ]
67+ if ( coreVariant ) {
68+ return React . createElement ( Badge , { variant : coreVariant } , metadata . label )
69+ }
70+
71+ if ( IconComponent ) {
12472 return React . createElement (
12573 Badge ,
126- {
127- variant : 'default' ,
128- className :
129- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
130- } ,
131- IconComponent && React . createElement ( IconComponent , { className : 'h-[12px] w-[12px]' } ) ,
74+ { variant : 'gray-secondary' , icon : IconComponent } ,
13275 metadata . label
13376 )
13477 }
13578
136- const textColor = lightenColor ( metadata . color , 65 )
137-
138- return React . createElement (
139- 'div' ,
140- {
141- className :
142- 'inline-flex items-center gap-[6px] rounded-[6px] px-[9px] py-[2px] font-medium text-[12px]' ,
143- style : { backgroundColor : hexToBackground ( metadata . color ) , color : textColor } ,
144- } ,
145- IconComponent && React . createElement ( IconComponent , { className : 'h-[12px] w-[12px]' } ) ,
146- metadata . label
147- )
79+ return React . createElement ( Badge , { variant : 'gray-secondary' } , metadata . label )
14880} )
14981
15082TriggerBadge . displayName = 'TriggerBadge'
0 commit comments