@@ -143,11 +143,20 @@ const StepCard: React.FC<StepCardProps> = ({ step, index, onUpdate, onDelete, av
143143 { getStepIcon ( step . type ) }
144144 </ div >
145145 < div style = { { flex : 1 } } >
146- < div style = { { fontWeight : 'bold' , fontSize : '14px' } } >
146+ < div style = { { fontWeight : 'bold' , fontSize : '14px' , display : 'flex' , alignItems : 'center' } } >
147147 { index + 1 } . { moduleInfo ?. name || step . type }
148+ { /* RSA 스텝에서 키가 선택되지 않은 경우 경고 표시 */ }
149+ { needsKeySelection && ( ! step . params || ! step . params . keyId ) && (
150+ < Tooltip title = "키를 선택해주세요" >
151+ < span style = { { marginLeft : 8 , color : '#ff4d4f' , fontSize : '12px' } } > ⚠️</ span >
152+ </ Tooltip >
153+ ) }
148154 </ div >
149155 < div style = { { fontSize : '12px' , color : '#666' } } >
150156 { moduleInfo ?. description || '' }
157+ { needsKeySelection && step . params ?. keyId && (
158+ < span style = { { color : '#52c41a' , marginLeft : 8 } } > ✓ 키 선택됨</ span >
159+ ) }
151160 </ div >
152161 </ div >
153162 </ div >
@@ -290,18 +299,6 @@ const ChainBuilderPage: React.FC = () => {
290299 } ) ;
291300 } ;
292301
293- const handleMoveStep = ( fromIndex : number , toIndex : number ) => {
294- if ( ! currentTemplate ) return ;
295-
296- const steps = Array . from ( currentTemplate . steps ) ;
297- const [ movedStep ] = steps . splice ( fromIndex , 1 ) ;
298- steps . splice ( toIndex , 0 , movedStep ) ;
299-
300- setCurrentTemplate ( {
301- ...currentTemplate ,
302- steps,
303- } ) ;
304- } ;
305302
306303 const handleExecuteChain = async ( ) => {
307304 if ( ! currentTemplate || ! inputText . trim ( ) ) {
@@ -312,14 +309,19 @@ const ChainBuilderPage: React.FC = () => {
312309 const validation = validateChainSteps ( currentTemplate . steps ) ;
313310 if ( ! validation . valid ) {
314311 notification . error ( {
315- message : '체인 검증 실패 ' ,
312+ message : '체인 실행 불가 ' ,
316313 description : (
317- < ul >
318- { validation . errors . map ( ( error , index ) => (
319- < li key = { index } > { error } </ li >
320- ) ) }
321- </ ul >
314+ < div >
315+ < p style = { { marginBottom : 8 } } > 다음 문제들을 해결해주세요:</ p >
316+ < ul style = { { paddingLeft : 20 , margin : 0 } } >
317+ { validation . errors . map ( ( error , index ) => (
318+ < li key = { index } style = { { marginBottom : 4 } } > { error } </ li >
319+ ) ) }
320+ </ ul >
321+ </ div >
322322 ) ,
323+ duration : 8 ,
324+ style : { width : 400 } ,
323325 } ) ;
324326 return ;
325327 }
@@ -510,15 +512,47 @@ const ChainBuilderPage: React.FC = () => {
510512 < Card
511513 title = "실행 및 결과"
512514 extra = {
513- < Button
514- type = "primary"
515- icon = { < PlayCircleOutlined /> }
516- loading = { isExecuting }
517- onClick = { handleExecuteChain }
518- disabled = { ! currentTemplate || currentTemplate . steps . length === 0 }
519- >
520- 실행
521- </ Button >
515+ ( ( ) => {
516+ const canExecute = currentTemplate && currentTemplate . steps . length > 0 && inputText . trim ( ) ;
517+ const validation = currentTemplate ? validateChainSteps ( currentTemplate . steps ) : { valid : false , errors : [ ] } ;
518+ const hasValidationErrors = ! validation . valid ;
519+
520+ return (
521+ < Space >
522+ { hasValidationErrors && (
523+ < Tooltip
524+ title = {
525+ < div >
526+ < div style = { { marginBottom : 4 } } > 실행 불가 사유:</ div >
527+ < ul style = { { paddingLeft : 16 , margin : 0 } } >
528+ { validation . errors . map ( ( error , index ) => (
529+ < li key = { index } > { error } </ li >
530+ ) ) }
531+ </ ul >
532+ </ div >
533+ }
534+ >
535+ < Button
536+ size = "small"
537+ danger
538+ icon = { < span > ⚠️</ span > }
539+ >
540+ 문제 있음
541+ </ Button >
542+ </ Tooltip >
543+ ) }
544+ < Button
545+ type = "primary"
546+ icon = { < PlayCircleOutlined /> }
547+ loading = { isExecuting }
548+ onClick = { handleExecuteChain }
549+ disabled = { ! canExecute || hasValidationErrors }
550+ >
551+ 실행
552+ </ Button >
553+ </ Space >
554+ ) ;
555+ } ) ( )
522556 }
523557 >
524558 < div style = { { marginBottom : 16 } } >
0 commit comments