@@ -26,6 +26,9 @@ import { Link } from '@stackstorm/module-router';
26
26
import ActionReporter from '@stackstorm/module-action-reporter' ;
27
27
import AutoForm from '@stackstorm/module-auto-form' ;
28
28
import StringField from '@stackstorm/module-auto-form/fields/string' ;
29
+ import EnumField from '@stackstorm/module-auto-form/fields/enum' ;
30
+ import get from 'lodash/fp/get' ;
31
+
29
32
import {
30
33
FlexTable ,
31
34
FlexTableRow ,
@@ -48,7 +51,6 @@ import {
48
51
} from '@stackstorm/module-panel' ;
49
52
import Time from '@stackstorm/module-time' ;
50
53
51
-
52
54
@connect ( ( state ) => {
53
55
const { action, executions, entrypoint } = state ;
54
56
return { action, executions, entrypoint } ;
@@ -64,14 +66,28 @@ export default class ActionsDetails extends React.Component {
64
66
action : PropTypes . object ,
65
67
executions : PropTypes . array ,
66
68
entrypoint : PropTypes . string ,
69
+ groups : PropTypes . array ,
70
+ filter : PropTypes . string ,
71
+ match : PropTypes . shape ( {
72
+ params : PropTypes . shape ( {
73
+ ref : PropTypes . string ,
74
+ section : PropTypes . string ,
75
+ } ) ,
76
+ } ) ,
67
77
}
68
78
69
79
state = {
70
80
runPreview : false ,
71
81
runValue : null ,
72
82
runTrace : null ,
73
83
executionsVisible : { } ,
74
- isChecked :false ,
84
+ openModel : false ,
85
+ isChecked : false ,
86
+ destinationPack :'' ,
87
+ destinationAction :'' ,
88
+ packs :[ ] ,
89
+ isRemoveFiles : false ,
90
+
75
91
}
76
92
77
93
componentDidMount ( ) {
@@ -129,11 +145,29 @@ export default class ActionsDetails extends React.Component {
129
145
}
130
146
}
131
147
132
- componentDidUpdate ( prevProps ) {
133
- const { id } = this . props ;
148
+ UNSAFE_componentWillReceiveProps ( nextProps ) {
149
+ const { groups, filter} = nextProps ;
150
+ const packs = [ ] ;
151
+ if ( ! filter ) {
152
+ groups && groups . map ( data => {
153
+ packs . push ( data . pack ) ;
154
+ } ) ;
155
+
156
+ this . setState ( { packs : packs } ) ;
157
+ }
158
+ }
159
+
160
+ componentDidUpdate ( prevProps , prevState ) {
161
+ const { id , filter} = this . props ;
162
+
163
+
134
164
if ( id && id !== prevProps . id ) {
135
165
this . fetchAction ( id ) ;
136
166
}
167
+
168
+ if ( filter && filter !== prevProps . filter ) {
169
+ this . setState ( { packs : prevState . packs } ) ;
170
+ }
137
171
}
138
172
139
173
componentWillUnmount ( ) {
@@ -254,6 +288,101 @@ export default class ActionsDetails extends React.Component {
254
288
return this . props . handleRun ( ...args ) ;
255
289
}
256
290
291
+ handleClone ( e , srcPack , srcAction , destAction , destPack , overwrite ) {
292
+ e . preventDefault ( ) ;
293
+ return store . dispatch ( {
294
+ type : 'CLONE_ACTION' ,
295
+ promise : api . request ( {
296
+ method : 'post' ,
297
+ path : `/actions/${ srcPack } .${ srcAction } /clone` ,
298
+ } , {
299
+ 'dest_pack' : destPack ,
300
+ 'dest_action' : destAction ,
301
+ 'overwrite' : overwrite ,
302
+
303
+ } )
304
+ . then ( ( execution ) => {
305
+ document . getElementById ( 'overlay' ) . style . display = 'none' ;
306
+ notification . success ( `Action "${ srcAction } " has been cloned successfully.` ) ;
307
+ this . getActions ( ) ;
308
+ return execution ;
309
+ } )
310
+ . catch ( ( err ) => {
311
+ if ( err . response ) {
312
+ const error = document . getElementById ( 'error' ) ;
313
+ error . textContent = err . response . data . faultstring ;
314
+ error . style . color = 'red' ;
315
+ }
316
+ } ) ,
317
+ } ) ;
318
+ }
319
+
320
+ getActions ( ) {
321
+ return store . dispatch ( {
322
+ type : 'FETCH_GROUPS' ,
323
+ promise : api . request ( {
324
+ path : '/actions' ,
325
+ query : {
326
+ include_attributes : [
327
+ 'ref' ,
328
+ 'pack' ,
329
+ 'name' ,
330
+ 'description' ,
331
+ 'runner_type' ,
332
+ ] ,
333
+ } ,
334
+ } )
335
+ . catch ( ( err ) => {
336
+ notification . error ( 'Unable to retrieve actions.' , { err } ) ;
337
+ throw err ;
338
+ } ) ,
339
+ } )
340
+ . then ( ( ) => {
341
+ const { id } = this . urlParams ;
342
+ const { groups } = this . props ;
343
+
344
+ if ( id && groups && ! groups . some ( ( { actions } ) => actions . some ( ( { ref } ) => ref === id ) ) ) {
345
+ this . navigate ( { id : false } ) ;
346
+ }
347
+ } )
348
+ ;
349
+ }
350
+
351
+ get urlParams ( ) {
352
+ const {
353
+ ref = get ( 'groups[0].actions[0].ref' , this . props ) ,
354
+ section = 'general' ,
355
+ } = this . props . match . params ;
356
+
357
+ return {
358
+ id : ref ,
359
+ section,
360
+ } ;
361
+ }
362
+
363
+ openModel ( e ) {
364
+ const { action} = this . props ;
365
+ const el = document . getElementById ( 'overlay' ) ;
366
+ el . style . display = 'block' ;
367
+ this . setState ( { destinationPack :action . pack , destinationAction :'' , isChecked : false } ) ;
368
+ }
369
+
370
+ closeModel ( ) {
371
+ document . getElementById ( 'overlay' ) . style . display = 'none' ;
372
+ }
373
+
374
+ handleDropdown ( e ) {
375
+ const error = document . getElementById ( 'error' ) ;
376
+ error . textContent = '' ;
377
+ this . setState ( { destinationPack :e } ) ;
378
+ }
379
+
380
+ handleInput ( e ) {
381
+ const error = document . getElementById ( 'error' ) ;
382
+ error . textContent = '' ;
383
+ this . setState ( { destinationAction :e } ) ;
384
+ }
385
+
257
386
handleChange ( e ) {
258
387
const isChecked = document . getElementById ( 'checkbox' ) . checked ;
259
388
if ( isChecked ) {
@@ -264,28 +393,37 @@ export default class ActionsDetails extends React.Component {
264
393
}
265
394
}
266
395
267
- openModel ( e ) {
268
- this . setState ( { isChecked : false } ) ;
269
- const el = document . getElementById ( 'overlay' ) ;
396
+ handleDeleteChange ( e ) {
397
+ const isChecked = document . getElementById ( 'deletecheckbox' ) . checked ;
398
+ if ( isChecked ) {
399
+ this . setState ( { isRemoveFiles :true } ) ;
400
+ }
401
+ else {
402
+ this . setState ( { isRemoveFiles :false } ) ;
403
+ }
404
+ }
405
+
406
+ openDeleteModel ( e ) {
407
+ this . setState ( { isRemoveFiles : false } ) ;
408
+ const el = document . getElementById ( 'delete' ) ;
270
409
el . style . display = 'block' ;
271
410
}
272
411
273
412
handleDelete ( e ) {
274
413
e . preventDefault ( ) ;
275
414
const { id } = this . props ;
276
- const { isChecked } = this . state ;
277
- document . getElementById ( 'overlay ' ) . style . display = 'none' ;
278
- return this . props . handleDelete ( id , isChecked ) ;
415
+ const { isRemoveFiles } = this . state ;
416
+ document . getElementById ( 'delete ' ) . style . display = 'none' ;
417
+ return this . props . handleDelete ( id , isRemoveFiles ) ;
279
418
}
280
419
281
- closeModel ( ) {
282
-
283
- document . getElementById ( 'overlay' ) . style . display = 'none' ;
420
+ closeDeleteModel ( ) {
421
+ document . getElementById ( 'delete' ) . style . display = 'none' ;
284
422
}
285
-
286
423
287
424
render ( ) {
288
- const { section, action, executions, entrypoint } = this . props ;
425
+ const { section, action, executions, entrypoint} = this . props ;
426
+
289
427
if ( ! action ) {
290
428
return null ;
291
429
}
@@ -325,7 +463,8 @@ export default class ActionsDetails extends React.Component {
325
463
/>
326
464
< Button flat value = "Preview" onClick = { ( ) => this . handleToggleRunPreview ( ) } />
327
465
< DetailsToolbarSeparator />
328
- < Button className = "st2-forms__button st2-details__toolbar-button" value = "Delete" onClick = { ( e ) => this . openModel ( e ) } />
466
+ < Button disabled = { this . props . id !== action . ref } className = "st2-forms__button st2-details__toolbar-button" value = "Clone" onClick = { ( e ) => this . openModel ( e ) } />
467
+ < Button className = "st2-forms__button st2-details__toolbar-button" value = "Delete" onClick = { ( e ) => this . openDeleteModel ( e ) } />
329
468
330
469
{ action . runner_type === 'mistral-v2' || action . runner_type === 'orquesta' ? (
331
470
< Link
@@ -425,15 +564,29 @@ export default class ActionsDetails extends React.Component {
425
564
</ DetailsPanel >
426
565
</ DetailsBody >
427
566
) : null }
567
+
568
+ { /* Written pop-up box code here */ }
569
+ < div id = "overlay" className = "web_dialog_overlay" style = { { display : 'none' , position : 'fixed' , zIndex : '10' , left : '0' , top : '0' , width : '100%' , minHeight : '-webkit-fill-available' , overflow : 'auto' , backgroundColor : 'rgba(0,0,0,0.4)' } } >
570
+ < div id = "dialog" className = "web_dialog" style = { { backgroundColor : '#fefefe' , margin : '15% auto' , padding : '20px' , border : '1px solid #888' , width : '28%' , height :'50%' } } >
571
+ < EnumField name = "Destination Pack Name *" value = { this . state . destinationPack ? this . state . destinationPack : action . pack } spec = { { enum : this . state . packs } } onChange = { ( e ) => this . handleDropdown ( e ) } /> < br /> < br />
572
+ < StringField style = { { height :'30%' } } name = "Destination Action Name *" value = { this . state . destinationAction } onChange = { ( e ) => this . handleInput ( e ) } required /> < br /> < br />
428
573
574
+ < input id = "checkbox" name = "checkbox" type = "checkbox" checked = { this . state . isChecked } value = { this . state . isChecked } onChange = { ( e ) => this . handleChange ( e ) } /> Overwrite < br /> < br /> < br />
575
+ < span id = "error" /> < br /> < br />
576
+ < div style = { { width :'100%' , display :'inline-block' } } >
577
+ < button onClick = { ( e ) => this . handleClone ( e , action . pack , action . name , this . state . destinationAction , this . state . destinationPack , this . state . isChecked ) } type = "submit" className = "btn" style = { { backgroundColor : '#04AA6D' , color : 'white' , padding : '16px 20px' , border : 'none' , cursor : 'pointer' , width : '45%' , marginBottom :'10px' , opacity : '0.8' , float :'left' } } > Submit</ button >
578
+ < button onClick = { ( e ) => this . closeModel ( e ) } type = "close" className = "btn cancel" style = { { backgroundColor : 'red' , color : 'white' , padding : '16px 20px' , border : 'none' , cursor : 'pointer' , width : '45%' , marginBottom :'10px' , opacity : '0.8' , float :'right' } } > Close</ button >
579
+ </ div >
580
+ </ div >
581
+ </ div >
429
582
430
- < div id = "overlay " className = "web_dialog_overlay" style = { { display : 'none' , position : 'fixed' , zIndex : '10' , left : '0' , top : '0' , width : '100%' , minHeight : '-webkit-fill-available' , overflow : 'auto' , backgroundColor : 'rgba(0,0,0,0.4)' } } >
583
+ < div id = "delete " className = "web_dialog_overlay" style = { { display : 'none' , position : 'fixed' , zIndex : '10' , left : '0' , top : '0' , width : '100%' , minHeight : '-webkit-fill-available' , overflow : 'auto' , backgroundColor : 'rgba(0,0,0,0.4)' } } >
431
584
< div id = "dialog" className = "web_dialog" style = { { backgroundColor : '#fefefe' , margin : '15% auto' , padding : '20px' , border : '1px solid #888' , width : '24%' , height :'20%' } } >
432
585
< p > You are about to delete the action. Are you sure? </ p >
433
- < input id = "checkbox " name = "checkbox" type = "checkbox" checked = { this . state . isChecked } value = { this . state . isChecked } onChange = { ( e ) => this . handleChange ( e ) } /> Remove Files (This operation is irreversible.) < br /> < br /> < br />
586
+ < input id = "deletecheckbox " name = "checkbox" type = "checkbox" checked = { this . state . isRemoveFiles } value = { this . state . isRemoveFiles } onChange = { ( e ) => this . handleDeleteChange ( e ) } /> Remove Files (This operation is irreversible.) < br /> < br /> < br />
434
587
< div style = { { width :'100%' , display :'inline-block' } } >
435
588
< button onClick = { ( e ) => this . handleDelete ( e ) } type = "submit" className = "btn" style = { { backgroundColor : '#04AA6D' , color : 'white' , padding : '16px 20px' , border : 'none' , cursor : 'pointer' , width : '45%' , marginBottom :'10px' , opacity : '0.8' , float :'left' } } > Submit</ button >
436
- < button onClick = { ( e ) => this . closeModel ( e ) } type = "close" className = "btn cancel" style = { { backgroundColor : 'red' , color : 'white' , padding : '16px 20px' , border : 'none' , cursor : 'pointer' , width : '45%' , marginBottom :'10px' , opacity : '0.8' , float :'right' } } > Close</ button >
589
+ < button onClick = { ( e ) => this . closeDeleteModel ( e ) } type = "close" className = "btn cancel" style = { { backgroundColor : 'red' , color : 'white' , padding : '16px 20px' , border : 'none' , cursor : 'pointer' , width : '45%' , marginBottom :'10px' , opacity : '0.8' , float :'right' } } > Close</ button >
437
590
</ div >
438
591
</ div >
439
592
</ div >
0 commit comments