diff --git a/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js b/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js
index 3c51e7d47d11..0fce20f0e48e 100644
--- a/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js
+++ b/services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js
@@ -97,7 +97,7 @@ qx.Class.define("osparc.desktop.MainPageHandler", {
 
       // check if there is any linked node missing
       if (osparc.study.Utils.isAnyLinkedNodeMissing(studyData)) {
-        const msg = `${qx.locale.Manager.tr("We encountered an issue with the")} ${studyAlias} 
${qx.locale.Manager.tr("Please contact support.")}`;
+        const msg = `${qx.locale.Manager.tr("We found an issue with some links.")}
${qx.locale.Manager.tr("They will be removed.")}`;
         throw new Error(msg);
       }
 
diff --git a/services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js b/services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js
index 01342db2c426..24818effe361 100644
--- a/services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js
+++ b/services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js
@@ -316,6 +316,29 @@ qx.Class.define("osparc.desktop.StudyEditor", {
       this.__listenToEvent();
       this.__listenToServiceStatus();
       this.__listenToStatePorts();
+
+      const socket = osparc.wrapper.WebSocket.getInstance();
+      [
+        "connect",
+        "reconnect",
+      ].forEach(evtName => {
+        socket.addListener(evtName, () => {
+          // after a reconnect, re-sync the project document
+          console.log("WebSocket reconnected, re-syncing project document");
+          const studyId = this.getStudy().getUuid();
+          osparc.store.Study.getInstance().getOne(studyId)
+            .then(latestStudyData => {
+              const latestData = {
+                "version": this.__lastSyncedProjectVersion, // do not increase the version
+                "document": latestStudyData,
+              };
+              this.__applyProjectDocument(latestData);
+            })
+            .catch(err => {
+              console.error("Failed to re-sync project document after WebSocket reconnect:", err);
+            });
+        });
+      });
     },
 
     __listenToProjectDocument: function() {
@@ -727,13 +750,14 @@ qx.Class.define("osparc.desktop.StudyEditor", {
       osparc.data.Resources.fetch("runPipeline", "startPipeline", params)
         .then(resp => this.__onPipelineSubmitted(resp))
         .catch(err => {
-          let msg = err.message;
           const errStatus = err.status;
           if (errStatus == "409") {
-            this.getStudyLogger().error(null, "Pipeline is already running");
+            osparc.FlashMessenger.logError(err);
+            const msg = osparc.FlashMessenger.extractMessage(err);
+            this.getStudyLogger().error(null, msg);
           } else if (errStatus == "422") {
             this.getStudyLogger().info(null, "The pipeline is up-to-date");
-            msg = this.tr("The pipeline is up-to-date. Do you want to re-run it?");
+            const msg = this.tr("The pipeline is up-to-date. Do you want to re-run it?");
             const win = new osparc.ui.window.Confirmation(msg).set({
               caption: this.tr("Re-run"),
               confirmText: this.tr("Run"),
diff --git a/services/static-webserver/client/source/class/osparc/form/renderer/PropForm.js b/services/static-webserver/client/source/class/osparc/form/renderer/PropForm.js
index 0e4578db488f..fb504f8c25fb 100644
--- a/services/static-webserver/client/source/class/osparc/form/renderer/PropForm.js
+++ b/services/static-webserver/client/source/class/osparc/form/renderer/PropForm.js
@@ -909,6 +909,11 @@ qx.Class.define("osparc.form.renderer.PropForm", {
       if (!this.__isPortAvailable(toPortId)) {
         return false;
       }
+      const fromNode = study.getWorkbench().getNode(fromNodeId);
+      if (!fromNode) {
+        console.error("Node not found while creating link", fromNodeId);
+        return false;
+      }
 
       const ctrlLink = this.getControlLink(toPortId);
       ctrlLink.setEnabled(false);
@@ -927,8 +932,6 @@ qx.Class.define("osparc.form.renderer.PropForm", {
       };
       ctrlLink.addListener("mouseover", () => highlightEdgeUI(true));
       ctrlLink.addListener("mouseout", () => highlightEdgeUI(false));
-
-      const fromNode = study.getWorkbench().getNode(fromNodeId);
       const prettifyLinkString = () => {
         const port = fromNode.getOutput(fromPortId);
         const fromPortLabel = port ? port.label : null;
diff --git a/services/static-webserver/client/source/class/osparc/navigation/StudyTitleWOptions.js b/services/static-webserver/client/source/class/osparc/navigation/StudyTitleWOptions.js
index fc88ae1866da..363fc816d2e1 100644
--- a/services/static-webserver/client/source/class/osparc/navigation/StudyTitleWOptions.js
+++ b/services/static-webserver/client/source/class/osparc/navigation/StudyTitleWOptions.js
@@ -68,6 +68,14 @@ qx.Class.define("osparc.navigation.StudyTitleWOptions", {
             });
           });
           break;
+        case "study-menu-share":
+          control = new qx.ui.menu.Button().set({
+            label: this.tr("Share..."),
+            icon: "@FontAwesome5Solid/share-alt/14",
+            ...this.self().BUTTON_OPTIONS
+          });
+          control.addListener("execute", () => this.__openAccessRights());
+          break;
         case "study-menu-reload":
           control = new qx.ui.menu.Button().set({
             label: this.tr("Reload"),
@@ -100,6 +108,7 @@ qx.Class.define("osparc.navigation.StudyTitleWOptions", {
           const optionsMenu = new qx.ui.menu.Menu();
           optionsMenu.setAppearance("menu-wider");
           optionsMenu.add(this.getChildControl("study-menu-info"));
+          optionsMenu.add(this.getChildControl("study-menu-share"));
           optionsMenu.add(this.getChildControl("study-menu-reload"));
           optionsMenu.add(this.getChildControl("study-menu-conversations"));
           if (osparc.product.Utils.showConvertToPipeline()) {
@@ -133,6 +142,17 @@ qx.Class.define("osparc.navigation.StudyTitleWOptions", {
       return control || this.base(arguments, id);
     },
 
+    __openAccessRights: function() {
+      const studyData = this.getStudy().serialize();
+      studyData["resourceType"] = this.getStudy().getTemplateType() ? "template" : "study";
+      const collaboratorsView = osparc.info.StudyUtils.openAccessRights(studyData);
+      collaboratorsView.addListener("updateAccessRights", e => {
+        const updatedData = e.getData();
+        this.getStudy().setAccessRights(updatedData["accessRights"]);
+        this.fireDataEvent("updateStudy", updatedData);
+      }, this);
+    },
+
     __reloadIFrame: function() {
       const nodes = this.getStudy().getWorkbench().getNodes();
       if (Object.keys(nodes).length === 1) {
@@ -145,6 +165,9 @@ qx.Class.define("osparc.navigation.StudyTitleWOptions", {
         const editTitle = this.getChildControl("edit-title-label");
         study.bind("name", editTitle, "value");
 
+        const shareButton = this.getChildControl("study-menu-share");
+        shareButton.setEnabled(osparc.data.model.Study.canIWrite(study.getAccessRights()));
+
         const reloadButton = this.getChildControl("study-menu-reload");
         study.getUi().bind("mode", reloadButton, "visibility", {
           converter: mode => mode === "standalone" ? "visible" : "excluded"
diff --git a/services/static-webserver/client/source/class/osparc/service/StatusUI.js b/services/static-webserver/client/source/class/osparc/service/StatusUI.js
index 092522376017..13631e61983b 100644
--- a/services/static-webserver/client/source/class/osparc/service/StatusUI.js
+++ b/services/static-webserver/client/source/class/osparc/service/StatusUI.js
@@ -192,14 +192,15 @@ qx.Class.define("osparc.service.StatusUI", {
 
         // ports
         case "modified":
-          return "busy-orange";
+          return "failed-red";
         case "up-to-date":
           return "ready-green";
 
         // output
         case "busy":
-        case "out-of-date":
           return "busy-orange";
+        case "out-of-date":
+          return "failed-red";
           /*
         case "up-to-date":
           return "ready-green";
diff --git a/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js b/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js
index f1f6d693aff5..bbbc448d7d05 100644
--- a/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js
+++ b/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js
@@ -258,7 +258,9 @@ qx.Class.define("osparc.workbench.NodeUI", {
             maxHeight: 20,
             font: "text-10",
           });
-          const statusLabel = control.getChildControl("label");
+          const statusLabel = control.getChildControl("label").set({
+            maxWidth: 80,
+          });
           const requestOpenLogger = () => this.fireEvent("requestOpenLogger");
           const evaluateLabel = () => {
             const failed = statusLabel.getValue() === "Unsuccessful";