Repository: kestra-io/kestra
Issue: Add/Improve error message while changing a flow namespace
Labels: backend
enhancement

### Feature description

As a **non-developer**

I created a **first flow with my first idea**

But I wanted to **change the namespace**

As a result, **I encountered multiple “Page not found” before understanding that it wasn’t possible**

So I end up **duplicating the flow and deleting the initial one**

*What would have helped?*

→ An error notification.

Issue comments:
Would it be better to add the possibility to change a flow's namespace ? @tchiotludo 
closing it, and move specs to https://github.com/kestra-io/kestra/issues/60
Reopen it to avoid the not found right now, that will be easy to fix

Pull request review comments:

Patch that resolved the issue:
diff --git a/ui/src/components/graph/Topology.vue b/ui/src/components/graph/Topology.vue
index e8292207bf..1af02db939 100644
--- a/ui/src/components/graph/Topology.vue
+++ b/ui/src/components/graph/Topology.vue
@@ -129,6 +129,7 @@
     const dragging = ref(false);
     const taskError = ref(store.getters["flow/taskError"])
     const user = store.getters["auth/user"];
+    const routeParams = router.currentRoute.value.params;
 
     const localStorageKey = computed(() => {
         return (props.isCreating ? "creation" : `${flow.namespace}.${flow.id}`) + "_draft";
@@ -849,8 +850,16 @@
                         });
                     })
             }else {
-                store
-                    .dispatch("flow/saveFlow", {flow: flowYaml.value})
+                if(routeParams.id !== flowParsed.id || routeParams.namespace !== flowParsed.namespace){
+                    store.dispatch("core/showMessage", {
+                        variant: "error",
+                        title: t("can not save"),
+                        message: t("namespace and id readonly"),
+                    })
+                    flowYaml.value = YamlUtils.replaceIdAndNamespace(flowYaml.value, routeParams.id, routeParams.namespace);
+                    return;
+                }
+                store.dispatch("flow/saveFlow", {flow: flowYaml.value})
                     .then((response) => {
                         toast.saved(response.id);
                         store.dispatch("core/isUnsaved", false);
diff --git a/ui/src/translations.json b/ui/src/translations.json
index c0f252dcb4..413e6f4654 100644
--- a/ui/src/translations.json
+++ b/ui/src/translations.json
@@ -407,6 +407,7 @@
     "delete task confirm": "Do you want to delete the task <code>{taskId}</code> ?",
     "can not save": "Can not save",
     "flow must have id and namespace": "Flow must have an id and a namespace.",
+    "namespace and id readonly": "Namespace and id are read-only. They were reinitialized to their initial value.",
     "avg": "Average",
     "sum": "Sum",
     "min": "Min",
@@ -837,6 +838,7 @@
     "delete task confirm": "Êtes-vous sûr de vouloir supprimer la tâche <code>{taskId}</code> ?",
     "can not save": "Impossible de sauvegarder",
     "flow must have id and namespace": "Le flow doit avoir un id et un namespace.",
+    "namespace and id readonly": "Le namespace et l'id ne sont pas modifiables. Ils ont été réinitialisés à leur valeur initiale.",
     "avg": "Moyenne",
     "sum": "Somme",
     "min": "Minimum",
diff --git a/ui/src/utils/yamlUtils.js b/ui/src/utils/yamlUtils.js
index fdd6cda190..956555e373 100644
--- a/ui/src/utils/yamlUtils.js
+++ b/ui/src/utils/yamlUtils.js
@@ -402,6 +402,10 @@ export default class YamlUtils {
         return isChildrenOf;
     }
 
+    static replaceIdAndNamespace(source, id, namespace) {
+        return source.replace(/^(id\s*:\s*(["']?))\S*/m, "$1"+id+"$2").replace(/^(namespace\s*:\s*(["']?))\S*/m, "$1"+namespace+"$2")
+    }
+
     static updateMetadata(source, metadata) {
         // TODO: check how to keep comments
         const yamlDoc = yaml.parseDocument(source);


Test patch: