diff --git a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js index d29bf773c1c..f60771f8bf5 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -64,6 +64,7 @@ qx.Class.define("osparc.conversation.Conversation", { __messages: null, __nextRequestParams: null, __messagesTitle: null, + __messageScroll: null, __messagesList: null, __loadMoreMessages: null, @@ -147,10 +148,15 @@ qx.Class.define("osparc.conversation.Conversation", { this.__messagesTitle = new qx.ui.basic.Label(); this._add(this.__messagesTitle); + // add spacer to keep the messages list at the bottom + this._add(new qx.ui.core.Spacer(), { + flex: 100 // high number to keep even a one message list at the bottom + }); + this.__messagesList = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)).set({ alignY: "middle" }); - const scrollView = new qx.ui.container.Scroll(); + const scrollView = this.__messageScroll = new qx.ui.container.Scroll(); scrollView.add(this.__messagesList); this._add(scrollView, { flex: 1 @@ -197,7 +203,8 @@ qx.Class.define("osparc.conversation.Conversation", { __reloadMessages: function(removeMessages = true) { if (this.getConversationId() === null) { - this.__messagesTitle.setValue(this.tr("No messages yet")); + // temporary conversation page + this.__messagesTitle.setValue(this.tr("No Messages yet")); this.__messagesList.hide(); this.__loadMoreMessages.hide(); return; @@ -217,7 +224,7 @@ qx.Class.define("osparc.conversation.Conversation", { const messages = resp["data"]; messages.forEach(message => this.addMessage(message)); this.__nextRequestParams = resp["_links"]["next"]; - if (this.__nextRequestParams === null) { + if (this.__nextRequestParams === null && this.__loadMoreMessages) { this.__loadMoreMessages.exclude(); } }) @@ -226,7 +233,9 @@ qx.Class.define("osparc.conversation.Conversation", { __updateMessagesNumber: function() { const nMessages = this.__messages.filter(msg => msg["type"] === "MESSAGE").length; - if (nMessages === 1) { + if (nMessages === 0) { + this.__messagesTitle.setValue(this.tr("No Messages yet")); + } else if (nMessages === 1) { this.__messagesTitle.setValue(this.tr("1 Message")); } else if (nMessages > 1) { this.__messagesTitle.setValue(nMessages + this.tr(" Messages")); @@ -243,9 +252,9 @@ qx.Class.define("osparc.conversation.Conversation", { return; } - // determine insertion index for most‐recent‐first order + // determine insertion index for latest‐first order const newTime = new Date(message["created"]); - let insertAt = this.__messages.findIndex(m => new Date(m["created"]) < newTime); + let insertAt = this.__messages.findIndex(m => new Date(m["created"]) > newTime); if (insertAt === -1) { insertAt = this.__messages.length; } @@ -270,6 +279,12 @@ qx.Class.define("osparc.conversation.Conversation", { this.__messagesList.addAt(control, insertAt); } + // scroll to bottom + // add timeout to ensure the scroll happens after the UI is updated + setTimeout(() => { + this.__messageScroll.scrollToY(this.__messageScroll.getChildControl("pane").getScrollMaxY()); + }, 50); + this.__updateMessagesNumber(); }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/Node.js b/services/static-webserver/client/source/class/osparc/data/model/Node.js index 0e40eface10..258257c98aa 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Node.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Node.js @@ -718,7 +718,7 @@ qx.Class.define("osparc.data.model.Node", { }); } else { this.fireDataEvent("projectDocumentChanged", { - "op": "delete", + "op": "remove", "path": `/ui/workbench/${this.getNodeId()}/marker`, "osparc-resource": "ui", }); diff --git a/services/static-webserver/client/source/class/osparc/data/model/Study.js b/services/static-webserver/client/source/class/osparc/data/model/Study.js index 7e9cc12053b..fec6e34e4bc 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Study.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Study.js @@ -573,19 +573,21 @@ qx.Class.define("osparc.data.model.Study", { // Do not listen to output related backend updates if the node is a frontend node. // The frontend controls its output values, progress and states. // If a File Picker is uploading a file, the backend could override the current state with some older state. - if (node && nodeData && !osparc.data.model.Node.isFrontend(node.getMetaData())) { - node.setOutputData(nodeData.outputs); - if ("progress" in nodeData) { - const progress = Number.parseInt(nodeData["progress"]); - node.getStatus().setProgress(progress); + if (node) { + if (nodeData && !osparc.data.model.Node.isFrontend(node.getMetaData())) { + node.setOutputData(nodeData.outputs); + if ("progress" in nodeData) { + const progress = Number.parseInt(nodeData["progress"]); + node.getStatus().setProgress(progress); + } + node.populateStates(nodeData); + } + if ("errors" in nodeUpdatedData) { + const errors = nodeUpdatedData["errors"]; + node.setErrors(errors); + } else { + node.setErrors([]); } - node.populateStates(nodeData); - } - if (node && "errors" in nodeUpdatedData) { - const errors = nodeUpdatedData["errors"]; - node.setErrors(errors); - } else { - node.setErrors([]); } }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/StudyUI.js b/services/static-webserver/client/source/class/osparc/data/model/StudyUI.js index 54ce78cde8d..038c88ed8af 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/StudyUI.js +++ b/services/static-webserver/client/source/class/osparc/data/model/StudyUI.js @@ -143,7 +143,7 @@ qx.Class.define("osparc.data.model.StudyUI", { if (annotationId in this.getAnnotations()) { const annotation = this.getAnnotations()[annotationId] this.fireDataEvent("projectDocumentChanged", { - "op": "delete", + "op": "remove", "path": `/ui/annotations/${annotation.getId()}`, "osparc-resource": "study-ui", }); diff --git a/services/static-webserver/client/source/class/osparc/data/model/Workbench.js b/services/static-webserver/client/source/class/osparc/data/model/Workbench.js index 605e9bd77f2..ce7b1a9e841 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Workbench.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Workbench.js @@ -320,7 +320,7 @@ qx.Class.define("osparc.data.model.Workbench", { this.__addNode(node); node.populateNodeData(); - this.giveUniqueNameToNode(node, node.getLabel()); + this.__giveUniqueNameToNode(node, node.getLabel()); node.checkState(); return node; @@ -653,7 +653,7 @@ qx.Class.define("osparc.data.model.Workbench", { return false; }, - giveUniqueNameToNode: function(node, label, suffix = 2) { + __giveUniqueNameToNode: function(node, label, suffix = 2) { const newLabel = label + "_" + suffix; const allModels = this.getNodes(); const nodes = Object.values(allModels); @@ -661,7 +661,7 @@ qx.Class.define("osparc.data.model.Workbench", { if (node2.getNodeId() !== node.getNodeId() && node2.getLabel().localeCompare(node.getLabel()) === 0) { node.setLabel(newLabel); - this.giveUniqueNameToNode(node, label, suffix+1); + this.__giveUniqueNameToNode(node, label, suffix+1); } } }, @@ -720,7 +720,7 @@ qx.Class.define("osparc.data.model.Workbench", { nodeIds.forEach(nodeId => { const node = this.getNode(nodeId); - this.giveUniqueNameToNode(node, node.getLabel()); + this.__giveUniqueNameToNode(node, node.getLabel()); }); }); }, diff --git a/services/static-webserver/client/source/class/osparc/study/Conversations.js b/services/static-webserver/client/source/class/osparc/study/Conversations.js index 3f52680710e..9f37585b656 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -221,6 +221,12 @@ qx.Class.define("osparc.study.Conversations", { __addToPages: function(conversationPage) { const conversationsLayout = this.getChildControl("conversations-layout"); + if (conversationsLayout.getChildren().length === 1) { + // remove the temporary conversation page + if (conversationsLayout.getChildren()[0].getConversationId() === null) { + conversationsLayout.remove(conversationsLayout.getChildren()[0]); + } + } conversationsLayout.add(conversationPage); if (this.__newConversationButton === null) { @@ -246,8 +252,11 @@ qx.Class.define("osparc.study.Conversations", { conversationsLayout.getChildControl("bar").add(newConversationButton); } // remove and add to move to last position - conversationsLayout.getChildControl("bar").remove(this.__newConversationButton); - conversationsLayout.getChildControl("bar").add(this.__newConversationButton); + const bar = conversationsLayout.getChildControl("bar"); + if (bar.indexOf(this.__newConversationButton) > -1) { + bar.remove(this.__newConversationButton); + } + bar.add(this.__newConversationButton); }, __removeConversationPage: function(conversationId, changeSelection = false) { diff --git a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js index 4b98e89c6c6..2ef15ebc9bb 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -276,14 +276,8 @@ qx.Class.define("osparc.workbench.Annotation", { const serializeData = { type: this.getType(), attributes: this.getAttributes(), + color: this.getColor(), // TYPES.NOTE and TYPES.CONVERSATION do not need a color but backend expects it }; - if ([ - this.self().TYPES.RECT, - this.self().TYPES.TEXT, - this.self().TYPES.NOTE, - ].includes(this.getType())) { - serializeData.color = this.getColor(); - } return serializeData; } } diff --git a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js index df48c91120e..ad7bd682a3e 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -346,7 +346,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __addNode: async function(service, pos) { // render temporary node - let tempNodeUI = this.__createTemporaryNodeUI(pos); + let dashedNodeUI = this.__createTemporaryNodeUI(pos); let nodeUI = null; try { @@ -359,7 +359,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { console.error(err); } finally { // remove temporary node - this.__removeTemporaryNodeUI(tempNodeUI); + this.__removeTemporaryNodeUI(dashedNodeUI); } return nodeUI; },