Repository: kestra-io/kestra (java)

Issue:
Subflow with wait is neverending 
All subflow with `wait:true` are neverending: 
- Execution `master-flow`
- Subflow start 
- Subflow end 
- The `master-flow` is stucked 

 
```yaml 
id: master-flow
namespace: company.team

tasks:
  - id: delete
    type: io.kestra.core.tasks.flows.Subflow
    namespace: company.team
    flowId: child-flow
    transmitFailed: true
    wait: true
    inputs:
      message: "delete"
```

```yaml 
id: child-flow
namespace: company.team

tasks:
  - id: delete
    type: io.kestra.core.tasks.flows.Subflow
    namespace: fr.leroymerlin.datacomponent.dataplatform.keys-rotation
    flowId: subflow
    transmitFailed: true
    wait: true
    inputs:
      message: "delete"
```


Pull request description:
fix(core): Subflow using the old task name never ends
Fixes #7506

Patch:
diff --git a/core/src/main/java/io/kestra/core/runners/ExecutableUtils.java b/core/src/main/java/io/kestra/core/runners/ExecutableUtils.java
index 054c03869..08d201880 100644
--- a/core/src/main/java/io/kestra/core/runners/ExecutableUtils.java
+++ b/core/src/main/java/io/kestra/core/runners/ExecutableUtils.java
@@ -206,7 +206,7 @@ public final class ExecutableUtils {
         if (ListUtils.isEmpty(flow.getLabels())) {
             return labels;
         }
-        
+
         return labels.stream()
             .filter(label -> flow.getLabels().stream().noneMatch(flowLabel -> flowLabel.key().equals(label.key())))
             .toList();
@@ -313,7 +313,10 @@ public final class ExecutableUtils {
     public static boolean isSubflow(Execution execution) {
         return execution.getTrigger() != null && (
             "io.kestra.plugin.core.flow.Subflow".equals(execution.getTrigger().getType()) ||
-                "io.kestra.plugin.core.flow.ForEachItem$ForEachItemExecutable".equals(execution.getTrigger().getType())
+                "io.kestra.plugin.core.flow.ForEachItem$ForEachItemExecutable".equals(execution.getTrigger().getType()) ||
+                "io.kestra.core.tasks.flows.Subflow".equals(execution.getTrigger().getType()) ||
+                "io.kestra.core.tasks.flows.Flow".equals(execution.getTrigger().getType()) ||
+                "io.kestra.core.tasks.flows.ForEachItem$ForEachItemExecutable".equals(execution.getTrigger().getType())
         );
     }
 }
diff --git a/platform/build.gradle b/platform/build.gradle
index 0c5598b2d..f1dd684bb 100644
--- a/platform/build.gradle
+++ b/platform/build.gradle
@@ -28,7 +28,7 @@ dependencies {
     api enforcedPlatform("com.fasterxml.jackson:jackson-bom:$jacksonVersion")
     // needed because httpclient fails to communicate with docker socket with > v5.4 (https://github.com/docker-java/docker-java/pull/2293#issuecomment-2435455322) and opensearch-java brings that version
     api enforcedPlatform("org.apache.httpcomponents.client5:httpclient5:5.3.1")
-    api platform("io.micronaut.platform:micronaut-platform:4.7.5")
+    api platform("io.micronaut.platform:micronaut-platform:4.7.6")
     api platform("io.qameta.allure:allure-bom:2.29.1")
     // we define cloud bom here for GCP, Azure and AWS so they are aligned for all plugins that use them (secret, storage, oss and ee plugins)
     api platform('com.google.cloud:libraries-bom:26.54.0')
diff --git a/ui/src/components/flows/FlowRun.vue b/ui/src/components/flows/FlowRun.vue
index 34e1861b0..1eb0c8f0f 100644
--- a/ui/src/components/flows/FlowRun.vue
+++ b/ui/src/components/flows/FlowRun.vue
@@ -70,7 +70,7 @@
 </script>
 
 <script>
-    import {mapState} from "vuex";
+    import {mapState, mapGetters} from "vuex";
     import {executeTask} from "../../utils/submitTask"
     import InputsForm from "../../components/inputs/InputsForm.vue";
     import LabelInput from "../../components/labels/LabelInput.vue";
@@ -108,6 +108,7 @@
         computed: {
             ...mapState("execution", ["flow", "execution"]),
             ...mapState("core", ["guidedProperties"]),
+            ...mapGetters("misc", ["configs"]),
             haveBadLabels() {
                 return this.executionLabels.some(label => (label.key && !label.value) || (!label.key && label.value));
             },
@@ -132,7 +133,8 @@
             },
             fillInputsFromExecution(){
                 // Add all labels except the one from flow to prevent duplicates
-                this.executionLabels = this.getExecutionLabels().filter(item => !item.key.startsWith("system."));
+                const toIgnore = this.configs.hiddenLabelsPrefixes || [];
+                this.executionLabels = this.getExecutionLabels().filter(item => !toIgnore.some(prefix => item.key.startsWith(prefix)));
 
                 if (!this.flow.inputs) {
                     return;
diff --git a/ui/src/components/labels/LabelInput.vue b/ui/src/components/labels/LabelInput.vue
index 49a8295a3..97ef9fd94 100644
--- a/ui/src/components/labels/LabelInput.vue
+++ b/ui/src/components/labels/LabelInput.vue
@@ -18,7 +18,7 @@
         <div class="flex-shrink-1">
             <el-button-group class="d-flex">
                 <el-button :icon="Plus" @click="addItem" />
-                <el-button :icon="Minus" @click="removeItem(index)" :disabled="index === 0 && locals.length === 1" />
+                <el-button :icon="Minus" @click="removeItem(index)" />
             </el-button-group>
         </div>
     </div>
@@ -31,6 +31,8 @@
 
 
 <script>
+    import {mapGetters} from "vuex";
+
     export default {
         props: {
             labels: {
@@ -49,13 +51,21 @@
             }
         },
         emits: ["update:labels"],
+        computed: {
+            ...mapGetters("misc", ["configs"]),
+        },
         created() {
+            const toIgnore = this.configs.hiddenLabelsPrefixes || [];
+
             if (this.labels.length === 0) {
                 this.addItem();
             } else {
-                this.locals = this.labels
+                this.locals = this.labels.filter(item => !item || !toIgnore.some(prefix => item.key?.startsWith(prefix)))
+                if(this.locals.length === 0) {
+                    this.addItem();
+                }
             }
-            this.localExisting = this.existingLabels.map(label => label.key);
+            this.localExisting = this.existingLabels.filter(item => !item || !toIgnore.some(prefix => item.key?.startsWith(prefix))).map(label => label.key);
         },
         methods: {
             addItem() {
@@ -64,6 +74,11 @@
             },
             removeItem(index) {
                 this.locals.splice(index, 1);
+
+                if (this.locals.length === 0) {
+                    this.addItem();
+                }
+                
                 this.$emit("update:labels", this.locals);
             },
             update(index, value, prop) {


Test patch:
diff --git a/core/src/test/java/io/kestra/plugin/core/flow/FlowCaseTest.java b/core/src/test/java/io/kestra/plugin/core/flow/FlowCaseTest.java
index c21d83311..909c91560 100644
--- a/core/src/test/java/io/kestra/plugin/core/flow/FlowCaseTest.java
+++ b/core/src/test/java/io/kestra/plugin/core/flow/FlowCaseTest.java
@@ -49,6 +49,36 @@ public class FlowCaseTest {
         this.run("OK", State.Type.SUCCESS, State.Type.SUCCESS, 2, "default > amazing", false);
     }
 
+    public void oldTaskName() throws Exception {
+        CountDownLatch countDownLatch = new CountDownLatch(1);
+        AtomicReference<Execution> triggered = new AtomicReference<>();
+
+        Flux<Execution> receive = TestsUtils.receive(executionQueue, either -> {
+            Execution execution = either.getLeft();
+            if (execution.getFlowId().equals("minimal") && execution.getState().getCurrent().isTerminated()) {
+                triggered.set(execution);
+                countDownLatch.countDown();
+            }
+        });
+
+        Execution execution = runnerUtils.runOne(
+            null,
+            "io.kestra.tests",
+            "subflow-old-task-name"
+        );
+
+        countDownLatch.await(1, TimeUnit.MINUTES);
+        receive.blockLast();
+
+        assertThat(execution.getTaskRunList(), hasSize(1));
+        assertThat(execution.getState().getCurrent(), is(State.Type.SUCCESS));
+        assertThat(execution.getTaskRunList().getFirst().getOutputs().get("executionId"), is(triggered.get().getId()));
+        assertThat(triggered.get().getTrigger().getType(), is("io.kestra.core.tasks.flows.Subflow"));
+        assertThat(triggered.get().getTrigger().getVariables().get("executionId"), is(execution.getId()));
+        assertThat(triggered.get().getTrigger().getVariables().get("flowId"), is(execution.getFlowId()));
+        assertThat(triggered.get().getTrigger().getVariables().get("namespace"), is(execution.getNamespace()));
+    }
+
     @SuppressWarnings({"ResultOfMethodCallIgnored", "unchecked"})
     void run(String input, State.Type fromState, State.Type triggerState, int count, String outputs, boolean testInherited) throws Exception {
         CountDownLatch countDownLatch = new CountDownLatch(1);
diff --git a/core/src/test/java/io/kestra/plugin/core/flow/FlowTest.java b/core/src/test/java/io/kestra/plugin/core/flow/FlowTest.java
index 51e0abfd1..9e4665ed0 100644
--- a/core/src/test/java/io/kestra/plugin/core/flow/FlowTest.java
+++ b/core/src/test/java/io/kestra/plugin/core/flow/FlowTest.java
@@ -7,7 +7,7 @@ import org.junit.jupiter.api.Test;
 import jakarta.inject.Inject;
 
 @KestraTest(startRunner = true)
-public class FlowTest {
+class FlowTest {
     @Inject
     FlowCaseTest flowCaseTest;
 
@@ -15,7 +15,7 @@ public class FlowTest {
     @LoadFlows({"flows/valids/task-flow.yaml",
         "flows/valids/task-flow-inherited-labels.yaml",
         "flows/valids/switch.yaml"})
-    public void waitSuccess() throws Exception {
+    void waitSuccess() throws Exception {
         flowCaseTest.waitSuccess();
     }
 
@@ -23,7 +23,7 @@ public class FlowTest {
     @LoadFlows({"flows/valids/task-flow.yaml",
         "flows/valids/task-flow-inherited-labels.yaml",
         "flows/valids/switch.yaml"})
-    public void waitFailed() throws Exception {
+    void waitFailed() throws Exception {
         flowCaseTest.waitFailed();
     }
 
@@ -31,7 +31,7 @@ public class FlowTest {
     @LoadFlows({"flows/valids/task-flow.yaml",
         "flows/valids/task-flow-inherited-labels.yaml",
         "flows/valids/switch.yaml"})
-    public void invalidOutputs() throws Exception {
+    void invalidOutputs() throws Exception {
         flowCaseTest.invalidOutputs();
     }
 
@@ -39,7 +39,14 @@ public class FlowTest {
     @LoadFlows({"flows/valids/task-flow.yaml",
         "flows/valids/task-flow-inherited-labels.yaml",
         "flows/valids/switch.yaml"})
-    public void noLabels() throws Exception {
+    void noLabels() throws Exception {
         flowCaseTest.noLabels();
     }
+
+    @Test
+    @LoadFlows({"flows/valids/subflow-old-task-name.yaml",
+        "flows/valids/minimal.yaml"})
+    void oldTaskName() throws Exception {
+        flowCaseTest.oldTaskName();
+    }
 }
diff --git a/core/src/test/resources/flows/valids/subflow-old-task-name.yaml b/core/src/test/resources/flows/valids/subflow-old-task-name.yaml
new file mode 100644
index 000000000..251154f3b
--- /dev/null
+++ b/core/src/test/resources/flows/valids/subflow-old-task-name.yaml
@@ -0,0 +1,8 @@
+id: subflow-old-task-name
+namespace: io.kestra.tests
+
+tasks:
+  - id: subflow
+    type: io.kestra.core.tasks.flows.Subflow
+    namespace: io.kestra.tests
+    flowId: minimal
\ No newline at end of file