Repository: kestra-io/kestra
Issue: Missing actions buttons on Topology Only view
Labels: bug

### Explain the bug

Topology view does not have the action button displayed anymore

This prevent from doing a flow from 100% low code on this view

![image](https://github.com/kestra-io/kestra/assets/37600690/7328e98e-f1f2-4b14-8638-94919032cbba)


### Environment Information

- Kestra Version: 0.13.0
- Operating System and Java Version (if not using Kestra Docker image):


Issue comments:
can you explain more? how did it look like before?

it seems you can edit tasks + add new ones directly from the UI forms

![image](https://github.com/kestra-io/kestra/assets/86264395/a77053d8-26e5-4173-aa90-2efa192b3a7f)



When you're in full topology view, the "Actions" button I highlighted above isn't show, so you can edit your flow metadata for example

Pull request review comments:

Patch that resolved the issue:
diff --git a/ui/src/components/inputs/Editor.vue b/ui/src/components/inputs/Editor.vue
index 5d6d4cd71f..4790fb268c 100644
--- a/ui/src/components/inputs/Editor.vue
+++ b/ui/src/components/inputs/Editor.vue
@@ -456,15 +456,15 @@
             }
 
             .bottom-right {
-                bottom: var(--spacer);
-                right: var(--spacer);
+                bottom: 0px;
+                right: 0px;
 
                 ul {
                     display: flex;
                     list-style: none;
                     padding: 0;
                     margin: 0;
-                    gap: calc(var(--spacer) / 2);
+                    //gap: calc(var(--spacer) / 2);
                 }
             }
         }
diff --git a/ui/src/components/inputs/EditorButtons.vue b/ui/src/components/inputs/EditorButtons.vue
new file mode 100644
index 0000000000..e25518fdf7
--- /dev/null
+++ b/ui/src/components/inputs/EditorButtons.vue
@@ -0,0 +1,121 @@
+<template>
+    <div class="to-action-button">
+        <div v-if="isAllowedEdit || canDelete" class="mx-2">
+            <el-dropdown>
+                <el-button type="default" :disabled="isReadOnly">
+                    <DotsVertical title=""/>
+                    {{ $t("actions") }}
+                </el-button>
+                <template #dropdown>
+                    <el-dropdown-menu class="m-dropdown-menu">
+                        <el-dropdown-item
+                            v-if="!isCreating && canDelete"
+                            :icon="Delete"
+                            size="large"
+                            @click="forwardEvent('delete-flow', $event)"
+                        >
+                            {{ $t("delete") }}
+                        </el-dropdown-item>
+
+                        <el-dropdown-item
+                            v-if="!isCreating"
+                            :icon="ContentCopy"
+                            size="large"
+                            @click="forwardEvent('copy', $event)"
+                        >
+                            {{ $t("copy") }}
+                        </el-dropdown-item>
+                        <el-dropdown-item
+                            v-if="isAllowedEdit"
+                            :icon="Exclamation"
+                            size="large"
+                            @click="forwardEvent('open-new-error', null)"
+                            :disabled="!flowHaveTasks"
+                        >
+                            {{ $t("add global error handler") }}
+                        </el-dropdown-item>
+                        <el-dropdown-item
+                            v-if="isAllowedEdit"
+                            :icon="LightningBolt"
+                            size="large"
+                            @click="forwardEvent('open-new-trigger', null)"
+                            :disabled="!flowHaveTasks"
+                        >
+                            {{ $t("add trigger") }}
+                        </el-dropdown-item>
+                        <el-dropdown-item
+                            v-if="isAllowedEdit"
+                            :icon="FileEdit"
+                            size="large"
+                            @click="forwardEvent('open-edit-metadata', null)"
+                        >
+                            {{ $t("edit metadata") }}
+                        </el-dropdown-item>
+                    </el-dropdown-menu>
+                </template>
+            </el-dropdown>
+        </div>
+        <div>
+            <el-button
+                :icon="ContentSave"
+                @click="forwardEvent('save', $event)"
+                v-if="isAllowedEdit"
+                :type="flowError ? 'danger' : 'primary'"
+                :disabled="!haveChange && !isCreating"
+                class="edit-flow-save-button"
+            >
+                {{ $t("save") }}
+            </el-button>
+        </div>
+    </div>
+</template>
+<script setup>
+    import DotsVertical from "vue-material-design-icons/DotsVertical.vue";
+    import Delete from "vue-material-design-icons/Delete.vue";
+    import ContentCopy from "vue-material-design-icons/ContentCopy.vue";
+    import Exclamation from "vue-material-design-icons/Exclamation.vue";
+    import LightningBolt from "vue-material-design-icons/LightningBolt.vue";
+    import FileEdit from "vue-material-design-icons/FileEdit.vue";
+    import ContentSave from "vue-material-design-icons/ContentSave.vue";
+</script>
+<script>
+    import {defineComponent} from "vue";
+
+    export default defineComponent({
+        props: {
+            isCreating: {
+                type: Boolean,
+                default: false
+            },
+            isReadOnly: {
+                type: Boolean,
+                default: false
+            },
+            canDelete: {
+                type: Boolean,
+                default: false
+            },
+            isAllowedEdit: {
+                type: Boolean,
+                default: false
+            },
+            haveChange: {
+                type: Boolean,
+                default: false
+            },
+            flowHaveTasks: {
+                type: Boolean,
+                default: false
+            },
+            flowError: {
+                type: String,
+                default: null
+            }
+        },
+        methods: {
+            forwardEvent(type, event) {
+                this.$emit(type, event);
+            }
+        }
+    })
+</script>
\ No newline at end of file
diff --git a/ui/src/components/inputs/EditorView.vue b/ui/src/components/inputs/EditorView.vue
index ff2b20668b..7166772f30 100644
--- a/ui/src/components/inputs/EditorView.vue
+++ b/ui/src/components/inputs/EditorView.vue
@@ -28,6 +28,7 @@
     import {editorViewTypes} from "../../utils/constants";
     import Utils from "@kestra-io/ui-libs/src/utils/Utils";
     import {apiUrl} from "override/utils/route";
+    import EditorButtons from "./EditorButtons.vue";
 
     const store = useStore();
     const router = getCurrentInstance().appContext.config.globalProperties.$router;
@@ -675,75 +676,22 @@
                 <ValidationError ref="validationDomElement" tooltip-placement="bottom-start" size="small" class="ms-2" :error="flowError" :warnings="flowWarnings" />
             </template>
             <template #buttons>
-                <ul>
-                    <li v-if="isAllowedEdit || canDelete">
-                        <el-dropdown>
-                            <el-button type="default" :disabled="isReadOnly">
-                                <DotsVertical title="" />
-                                {{ $t("actions") }}
-                            </el-button>
-                            <template #dropdown>
-                                <el-dropdown-menu class="m-dropdown-menu">
-                                    <el-dropdown-item
-                                        v-if="!props.isCreating && canDelete"
-                                        :icon="Delete"
-                                        size="large"
-                                        @click="deleteFlow"
-                                    >
-                                        {{ $t("delete") }}
-                                    </el-dropdown-item>
-
-                                    <el-dropdown-item
-                                        v-if="!props.isCreating"
-                                        :icon="ContentCopy"
-                                        size="large"
-                                        @click="() => router.push({name: 'flows/create', query: {copy: true}})"
-                                    >
-                                        {{ $t("copy") }}
-                                    </el-dropdown-item>
-                                    <el-dropdown-item
-                                        v-if="isAllowedEdit"
-                                        :icon="Exclamation"
-                                        size="large"
-                                        @click="isNewErrorOpen = true;"
-                                        :disabled="!flowHaveTasks()"
-                                    >
-                                        {{ $t("add global error handler") }}
-                                    </el-dropdown-item>
-                                    <el-dropdown-item
-                                        v-if="isAllowedEdit"
-                                        :icon="LightningBolt"
-                                        size="large"
-                                        @click="isNewTriggerOpen = true;"
-                                        :disabled="!flowHaveTasks()"
-                                    >
-                                        {{ $t("add trigger") }}
-                                    </el-dropdown-item>
-                                    <el-dropdown-item
-                                        v-if="isAllowedEdit"
-                                        :icon="FileEdit"
-                                        size="large"
-                                        @click="isEditMetadataOpen = true;"
-                                    >
-                                        {{ $t("edit metadata") }}
-                                    </el-dropdown-item>
-                                </el-dropdown-menu>
-                            </template>
-                        </el-dropdown>
-                    </li>
-                    <li>
-                        <el-button
-                            :icon="ContentSave"
-                            @click="save"
-                            v-if="isAllowedEdit"
-                            :type="flowError ? 'danger' : 'primary'"
-                            :disabled="!haveChange && !isCreating"
-                            class="edit-flow-save-button"
-                        >
-                            {{ $t("save") }}
-                        </el-button>
-                    </li>
-                </ul>
+                <EditorButtons
+                    v-if="![editorViewTypes.TOPOLOGY, editorViewTypes.SOURCE_TOPOLOGY].includes(viewType)"
+                    :is-creating="props.isCreating"
+                    :is-read-only="props.isReadOnly"
+                    :can-delete="canDelete"
+                    :is-allowed-edit="isAllowedEdit"
+                    :have-change="haveChange"
+                    :flow-have-tasks="flowHaveTasks()"
+                    :flow-error="flowError"
+                    @delete-flow="deleteFlow"
+                    @save="save"
+                    @copy="() => router.push({name: 'flows/create', query: {copy: true}})"
+                    @open-new-error="isNewErrorOpen = true;"
+                    @open-new-trigger="isNewTriggerOpen = true;"
+                    @open-edit-metadata="isEditMetadataOpen = true;"
+                />
             </template>
         </editor>
         <div class="slider" @mousedown="dragEditor" v-if="combinedEditor" />
@@ -859,6 +807,22 @@
             class="to-topology-button"
             @switch-view="switchViewType"
         />
+        <EditorButtons
+            v-if="[editorViewTypes.TOPOLOGY, editorViewTypes.SOURCE_TOPOLOGY].includes(viewType)"
+            :is-creating="props.isCreating"
+            :is-read-only="props.isReadOnly"
+            :can-delete="canDelete"
+            :is-allowed-edit="isAllowedEdit"
+            :have-change="haveChange"
+            :flow-have-tasks="flowHaveTasks()"
+            :flow-error="flowError"
+            @delete-flow="deleteFlow"
+            @save="save"
+            @copy="() => router.push({name: 'flows/create', query: {copy: true}})"
+            @open-new-error="isNewErrorOpen = true;"
+            @open-new-trigger="isNewTriggerOpen = true;"
+            @open-edit-metadata="isEditMetadataOpen = true;"
+        />
     </el-card>
 </template>
 
@@ -879,6 +843,13 @@
         right: 45px;
     }
 
+    .to-action-button {
+        position: absolute;
+        bottom: 30px;
+        right: 45px;
+        display: flex;
+    }
+
     .editor-combined {
         height: 100%;
         width: 50%;


Test patch: