@@ -33,10 +33,12 @@ import {
33
33
DEFAULT_NEW_WORKFLOW_NAME ,
34
34
DEFAULT_NEW_WORKFLOW_DESCRIPTION ,
35
35
USE_CASE ,
36
+ WORKFLOW_STATE ,
36
37
} from '../../../../common' ;
37
38
import {
38
39
AppState ,
39
40
createWorkflow ,
41
+ deprovisionWorkflow ,
40
42
getWorkflowState ,
41
43
provisionWorkflow ,
42
44
removeDirty ,
@@ -66,14 +68,22 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
66
68
const history = useHistory ( ) ;
67
69
68
70
// Overall workspace state
69
- const isDirty = useSelector ( ( state : AppState ) => state . workspace . isDirty ) ;
71
+ const { isDirty } = useSelector ( ( state : AppState ) => state . workspace ) ;
72
+ const { loading } = useSelector ( ( state : AppState ) => state . workflows ) ;
70
73
const [ isFirstSave , setIsFirstSave ] = useState < boolean > ( props . isNewWorkflow ) ;
71
74
72
75
// Workflow state
73
76
const [ workflow , setWorkflow ] = useState < Workflow | undefined > (
74
77
props . workflow
75
78
) ;
76
79
80
+ // Loading state
81
+ const [ isProvisioning , setIsProvisioning ] = useState < boolean > ( false ) ;
82
+ const [ isDeprovisioning , setIsDeprovisioning ] = useState < boolean > ( false ) ;
83
+ const [ isSaving , setIsSaving ] = useState < boolean > ( false ) ;
84
+ const isLoadingGlobal =
85
+ loading || isProvisioning || isDeprovisioning || isSaving ;
86
+
77
87
// Formik form state
78
88
const [ formValues , setFormValues ] = useState < WorkspaceFormValues > ( { } ) ;
79
89
const [ formSchema , setFormSchema ] = useState < WorkspaceSchema > ( yup . object ( { } ) ) ;
@@ -102,7 +112,14 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
102
112
// Save/provision button state
103
113
const isSaveable = isFirstSave ? true : isDirty ;
104
114
const isProvisionable =
105
- ! isDirty && ! props . isNewWorkflow && formValidOnSubmit && flowValidOnSubmit ;
115
+ ! isDirty &&
116
+ ! props . isNewWorkflow &&
117
+ formValidOnSubmit &&
118
+ flowValidOnSubmit &&
119
+ props . workflow ?. state === WORKFLOW_STATE . NOT_STARTED ;
120
+ const isDeprovisionable =
121
+ ! props . isNewWorkflow &&
122
+ props . workflow ?. state !== WORKFLOW_STATE . NOT_STARTED ;
106
123
107
124
/**
108
125
* Custom listener on when nodes are selected / de-selected. Passed to
@@ -234,6 +251,7 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
234
251
// The workaround is to additionally execute validateForm() which will return any errors found.
235
252
formikProps . submitForm ( ) ;
236
253
formikProps . validateForm ( ) . then ( ( validationResults : { } ) => {
254
+ setIsSaving ( false ) ;
237
255
if ( Object . keys ( validationResults ) . length > 0 ) {
238
256
setFormValidOnSubmit ( false ) ;
239
257
} else {
@@ -298,30 +316,63 @@ export function ResizableWorkspace(props: ResizableWorkspaceProps) {
298
316
rightSideItems = { [
299
317
< EuiButton
300
318
fill = { false }
301
- disabled = { ! isProvisionable }
319
+ disabled = { ! isDeprovisionable || isLoadingGlobal }
320
+ isLoading = { isDeprovisioning }
321
+ onClick = { ( ) => {
322
+ if ( workflow ?. id ) {
323
+ setIsDeprovisioning ( true ) ;
324
+ dispatch ( deprovisionWorkflow ( workflow . id ) )
325
+ . unwrap ( )
326
+ . then ( async ( result ) => {
327
+ await new Promise ( ( f ) => setTimeout ( f , 3000 ) ) ;
328
+ dispatch ( getWorkflowState ( workflow . id as string ) ) ;
329
+ setIsDeprovisioning ( false ) ;
330
+ } )
331
+ . catch ( ( error : any ) => {
332
+ // TODO: process error (toast msg?)
333
+ console . log ( 'error: ' , error ) ;
334
+ setIsDeprovisioning ( false ) ;
335
+ } ) ;
336
+ } else {
337
+ // TODO: this case should not happen
338
+ }
339
+ } }
340
+ >
341
+ Deprovision
342
+ </ EuiButton > ,
343
+ < EuiButton
344
+ fill = { false }
345
+ disabled = { ! isProvisionable || isLoadingGlobal }
346
+ isLoading = { isProvisioning }
302
347
onClick = { ( ) => {
303
348
if ( workflow ?. id ) {
349
+ setIsProvisioning ( true ) ;
304
350
dispatch ( provisionWorkflow ( workflow . id ) )
305
351
. unwrap ( )
306
352
. then ( async ( result ) => {
307
353
await new Promise ( ( f ) => setTimeout ( f , 3000 ) ) ;
308
- console . log ( 'done waiting. fetching updated state...' ) ;
309
354
dispatch ( getWorkflowState ( workflow . id as string ) ) ;
355
+ setIsProvisioning ( false ) ;
310
356
} )
311
357
. catch ( ( error : any ) => {
312
358
// TODO: process error (toast msg?)
313
359
console . log ( 'error: ' , error ) ;
360
+ setIsProvisioning ( false ) ;
314
361
} ) ;
362
+ } else {
363
+ // TODO: this case should not happen
315
364
}
316
365
} }
317
366
>
318
367
Provision
319
368
</ EuiButton > ,
320
369
< EuiButton
321
370
fill = { false }
322
- disabled = { ! isSaveable }
371
+ disabled = { ! isSaveable || isLoadingGlobal }
372
+ isLoading = { isSaving }
323
373
// TODO: if props.isNewWorkflow is true, clear the workflow cache if saving is successful.
324
374
onClick = { ( ) => {
375
+ setIsSaving ( true ) ;
325
376
dispatch ( removeDirty ( ) ) ;
326
377
if ( isFirstSave ) {
327
378
setIsFirstSave ( false ) ;
0 commit comments