Repository: kestra-io/kestra
Issue: [UI] VS Code Execute button does not reflect recently saved flow (inputs are displayed for the previous revision of the flow)
Labels: bug
quick-win

If I update a flow on vscode and I add a new inputs for example. 
When I click on execute, the old revision is used and will not display the form with that new input. 
We need to reload the definition of the flow on save 

Issue comments:

Pull request review comments:

Patch that resolved the issue:
diff --git a/ui/public/init.js b/ui/public/init.js
index a6791318af..5407984dd3 100644
--- a/ui/public/init.js
+++ b/ui/public/init.js
@@ -17,8 +17,8 @@ require.config({
 const extensionsToFetch = {
     // to handle dark theme
     "PROxZIMA/sweetdracula": "1.0.9",
-    // to apply Kestra's flow validation schema
-    "kestra-io/kestra": "0.1.8",
+    // to apply Kestra's flow validation schema, comment for local extension testing
+    "kestra-io/kestra": "0.1.9",
 };
 
 let url;
@@ -114,6 +114,12 @@ window.product = {
             authority: window.location.host,
             path: KESTRA_UI_PATH + "vscode/extensions/yaml/extension"
         },
+        // uncomment for local extension testing
+        /*{
+            scheme: window.location.protocol.replace(":", ""),
+            authority: window.location.host,
+            path: KESTRA_UI_PATH + "vscode/extensions/kestra/extension"
+        },*/
         ...extensionUrls
     ],
     configurationDefaults: {
diff --git a/ui/src/components/flows/TriggerFlow.vue b/ui/src/components/flows/TriggerFlow.vue
index 22124e8871..8af0625b30 100644
--- a/ui/src/components/flows/TriggerFlow.vue
+++ b/ui/src/components/flows/TriggerFlow.vue
@@ -24,8 +24,7 @@
         },
         props: {
             flowId: {
-                type: String,
-                required: true
+                type: String
             },
             namespace: {
                 type: String,
@@ -48,16 +47,6 @@
                 }
             };
         },
-        mounted() {
-            if (!this.flow && this.flowId && this.namespace) {
-                this.$store
-                    .dispatch("flow/loadFlow", {
-                        id: this.flowId,
-                        namespace: this.namespace,
-                        allowDeleted: true
-                    });
-            }
-        },
         methods: {
             onClick() {
                 if (this.$tours["guidedTour"].isRunning.value && !this.guidedProperties.executeFlow) {
@@ -79,6 +68,13 @@
             },
             isDisabled() {
                 return this.disabled || this.flow?.deleted;
+            },
+            loadDefinition() {
+                this.$store.dispatch("flow/loadFlow", {
+                    id: this.flowId,
+                    namespace: this.namespace,
+                    allowDeleted: true
+                });
             }
         },
         computed: {
@@ -104,15 +100,13 @@
             },
             flowId: {
                 handler() {
-                    if ((!this.flow || this.flow.id !== this.flowId) && this.flowId && this.namespace) {
-                        this.$store
-                            .dispatch("flow/loadFlow", {
-                                id: this.flowId,
-                                namespace: this.namespace,
-                                allowDeleted: true
-                            });
+                    if (!this.flowId) {
+                        return;
                     }
-                }
+
+                    this.loadDefinition();
+                },
+                immediate: true
             }
         }
     };
diff --git a/ui/src/components/namespace/Editor.vue b/ui/src/components/namespace/Editor.vue
index 1738e53fe7..3cd114d84f 100644
--- a/ui/src/components/namespace/Editor.vue
+++ b/ui/src/components/namespace/Editor.vue
@@ -31,10 +31,11 @@
                     </el-dropdown-menu>
                 </template>
             </el-dropdown>
-            <el-tooltip hide-after="50" :content="$t('namespace files.export')">
+            <el-tooltip :hide-after="50" :content="$t('namespace files.export')">
                 <el-button :icon="FolderZip" class="p-2 m-0" @click="exportNsFiles" />
             </el-tooltip>
             <trigger-flow
+                ref="triggerFlow"
                 :disabled="!flow"
                 :flow-id="flow"
                 :namespace="namespace"
@@ -144,10 +145,12 @@
                         // trim the eventual extension
                         this.flow = fileName.split(".")[0];
                     } else {
-                        this.flow = null;
+                        this.flow = undefined;
                     }
                 } else if (message.type === "kestra.tabsChanged") {
                     this.handleTabsDirty(message.tabs);
+                } else if (message.type === "kestra.flowSaved") {
+                    this.$refs.triggerFlow.loadDefinition();
                 }
             });
 


Test patch:
diff --git a/core/src/test/java/io/kestra/core/tasks/flows/ForEachItemCaseTest.java b/core/src/test/java/io/kestra/core/tasks/flows/ForEachItemCaseTest.java
index 7499a89597..39e9c04fe4 100644
--- a/core/src/test/java/io/kestra/core/tasks/flows/ForEachItemCaseTest.java
+++ b/core/src/test/java/io/kestra/core/tasks/flows/ForEachItemCaseTest.java
@@ -9,6 +9,7 @@
 import jakarta.inject.Inject;
 import jakarta.inject.Named;
 import jakarta.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 
 import java.io.File;
@@ -30,6 +31,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.*;
 
+@Slf4j
 @Singleton
 public class ForEachItemCaseTest {
     @Inject
@@ -89,9 +91,12 @@ public void forEachItemNoWait() throws TimeoutException, InterruptedException, U
 
         executionQueue.receive(either -> {
             Execution execution = either.getLeft();
-            if (execution.getFlowId().equals("for-each-item-subflow") && execution.getState().getCurrent().isTerminated()) {
-                countDownLatch.countDown();
-                triggered.set(execution);
+            if (execution.getFlowId().equals("for-each-item-subflow")) {
+                log.info("Received sub-execution " + execution.getId() + " with status " + execution.getState().getCurrent());
+                if (execution.getState().getCurrent().isTerminated()) {
+                    countDownLatch.countDown();
+                    triggered.set(execution);
+                }
             }
         });
 
@@ -119,7 +124,7 @@ public void forEachItemNoWait() throws TimeoutException, InterruptedException, U
         assertThat(countDownLatch.getCount(), greaterThan(0L));
 
         // wait for the 3 flows to ends
-        assertThat(countDownLatch.await(1, TimeUnit.MINUTES), is(true));
+        assertThat("Remaining count was " + countDownLatch.getCount(), countDownLatch.await(1, TimeUnit.MINUTES), is(true));
 
         // assert on the last subflow execution
         assertThat(triggered.get().getState().getCurrent(), is(State.Type.SUCCESS));