From 16495dbd28d3eb67da726224203eb79c7a2a02db Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 13:30:03 +0200 Subject: [PATCH 01/63] I can create conversation only if I have write access --- .../class/osparc/conversation/Conversation.js | 24 +++++++++---------- .../class/osparc/study/Conversations.js | 3 ++- 2 files changed, 14 insertions(+), 13 deletions(-) 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 8ed290b1e09c..c7eba0416132 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -166,18 +166,18 @@ qx.Class.define("osparc.conversation.Conversation", { this.__loadMoreMessages.addListener("execute", () => this.__reloadMessages(false)); this._add(this.__loadMoreMessages); - if (osparc.data.model.Study.canIWrite(this.__studyData["accessRights"])) { - const addMessages = new osparc.conversation.AddMessage(this.__studyData, this.getConversationId()); - addMessages.setPaddingLeft(10); - addMessages.addListener("messageAdded", e => { - const data = e.getData(); - if (data["conversationId"]) { - this.setConversationId(data["conversationId"]); - this.addMessage(data); - } - }); - this._add(addMessages); - } + const addMessages = new osparc.conversation.AddMessage(this.__studyData, this.getConversationId()).set({ + enabled: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]), + paddingLeft: 10, + }); + addMessages.addListener("messageAdded", e => { + const data = e.getData(); + if (data["conversationId"]) { + this.setConversationId(data["conversationId"]); + this.addMessage(data); + } + }); + this._add(addMessages); }, __getNextRequest: function() { 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 0839624779e0..4de86d25f2d4 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -307,15 +307,16 @@ qx.Class.define("osparc.study.Conversations", { conversationsLayout.add(conversationPage); if (this.__newConversationButton === null) { + const studyData = this.getStudyData(); // initialize the new button only once const newConversationButton = this.__newConversationButton = new qx.ui.form.Button().set({ icon: "@FontAwesome5Solid/plus/12", toolTipText: this.tr("Add new conversation"), allowGrowX: false, backgroundColor: "transparent", + enabled: osparc.data.model.Study.canIWrite(studyData["accessRights"]), }); newConversationButton.addListener("execute", () => { - const studyData = this.getStudyData(); osparc.study.Conversations.addConversation(studyData["uuid"], "new " + (this.__conversations.length + 1)) .then(conversationDt => { this.__addConversationPage(conversationDt); From d85019a38278a96b3e42a537857444ccd0e11396 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 13:34:37 +0200 Subject: [PATCH 02/63] catch errors --- .../client/source/class/osparc/conversation/Conversation.js | 3 ++- .../client/source/class/osparc/study/Conversations.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) 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 c7eba0416132..c9cef5e5332b 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -197,7 +197,8 @@ qx.Class.define("osparc.conversation.Conversation", { const options = { resolveWResponse: true }; - return osparc.data.Resources.fetch("conversations", "getMessagesPage", params, options); + return osparc.data.Resources.fetch("conversations", "getMessagesPage", params, options) + .catch(err => osparc.FlashMessenger.logError(err)); }, __reloadMessages: function(removeMessages = true) { 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 4de86d25f2d4..c4cd01ae4a2a 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -259,6 +259,7 @@ qx.Class.define("osparc.study.Conversations", { this.__addTempConversationPage(); } }) + .catch(err => osparc.FlashMessenger.logError(err)) .finally(() => { loadMoreButton.setFetching(false); loadMoreButton.exclude(); From ef1cb97fd5033a9c8b4609a704ed21b0f7a7e0d7 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 13:49:12 +0200 Subject: [PATCH 03/63] definitions --- .../client/source/class/osparc/study/Conversations.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 c4cd01ae4a2a..b54be1492ae7 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -46,6 +46,11 @@ qx.Class.define("osparc.study.Conversations", { }, statics: { + TYPES: { + PROJECT_STATIC: "PROJECT_STATIC", + PROJECT_DYNAMIC: "PROJECT_DYNAMIC", + }, + popUpInWindow: function(studyData) { const conversations = new osparc.study.Conversations(studyData); const title = qx.locale.Manager.tr("Conversations"); @@ -58,14 +63,14 @@ qx.Class.define("osparc.study.Conversations", { return win; }, - addConversation: function(studyId, name = "new 1") { + addConversation: function(studyId, name = "new 1", type = this.TYPES.PROJECT_STATIC) { const params = { url: { studyId, }, data: { name, - "type": "PROJECT_STATIC", + type, } }; return osparc.data.Resources.fetch("conversations", "addConversation", params) From e07b03912f77b35098f31e123dff580c675451f1 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 13:56:02 +0200 Subject: [PATCH 04/63] rename and delete --- .../client/source/class/osparc/conversation/Conversation.js | 2 ++ 1 file changed, 2 insertions(+) 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 c9cef5e5332b..e60b1bc6617b 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -82,6 +82,7 @@ qx.Class.define("osparc.conversation.Conversation", { }; const renameButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/pencil-alt/10").set({ ...buttonsAesthetics, + visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]), }); renameButton.addListener("execute", () => { const titleEditor = new osparc.widget.Renamer(tabButton.getLabel()); @@ -112,6 +113,7 @@ qx.Class.define("osparc.conversation.Conversation", { const closeButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/times/12").set({ ...buttonsAesthetics, paddingLeft: 4, // adds spacing between buttons + visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]), }); closeButton.addListener("execute", () => { const deleteConversation = () => { From f38f4ee7f0e7c50283e7e3fec09f8a88369b702a Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 14:05:45 +0200 Subject: [PATCH 05/63] fix --- .../client/source/class/osparc/conversation/Conversation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 e60b1bc6617b..62d90f54db04 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -82,7 +82,7 @@ qx.Class.define("osparc.conversation.Conversation", { }; const renameButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/pencil-alt/10").set({ ...buttonsAesthetics, - visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]), + visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]) ? "visible" : "excluded", }); renameButton.addListener("execute", () => { const titleEditor = new osparc.widget.Renamer(tabButton.getLabel()); @@ -113,7 +113,7 @@ qx.Class.define("osparc.conversation.Conversation", { const closeButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/times/12").set({ ...buttonsAesthetics, paddingLeft: 4, // adds spacing between buttons - visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]), + visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]) ? "visible" : "excluded", }); closeButton.addListener("execute", () => { const deleteConversation = () => { From 3255d3f079bd54629bc14300af9efeb501b2b155 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 14:22:45 +0200 Subject: [PATCH 06/63] startConversation --- .../class/osparc/desktop/WorkbenchView.js | 21 +++++++++++++------ .../class/osparc/workbench/WorkbenchUI.js | 4 ++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js b/services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js index f4f0bbc9fc67..53b560ad9ce9 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js +++ b/services/static-webserver/client/source/class/osparc/desktop/WorkbenchView.js @@ -873,25 +873,34 @@ qx.Class.define("osparc.desktop.WorkbenchView", { __getAnnotationsSection: function() { const annotationsSection = new qx.ui.container.Composite(new qx.ui.layout.VBox(10)); - annotationsSection.add(new qx.ui.basic.Label(this.tr("Annotations")).set({ + annotationsSection.add(new qx.ui.basic.Label(this.tr("Add to Workbench")).set({ font: "text-14" })); - const annotationsButtons = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)); + const annotationsButtons = new qx.ui.container.Composite(new qx.ui.layout.Flow(5, 5)); annotationsSection.add(annotationsButtons); const buttonsHeight = 28; + + const addConversationBtn = new qx.ui.form.Button().set({ + label: this.tr("Conversation"), + icon: "@FontAwesome5Solid/comment/14", + height: buttonsHeight + }); + addConversationBtn.addListener("execute", () => this.__workbenchUI.startConversation(), this); + annotationsButtons.add(addConversationBtn); + const addNoteBtn = new qx.ui.form.Button().set({ label: this.tr("Note"), - icon: "@FontAwesome5Solid/plus/14", + icon: "@FontAwesome5Solid/sticky-note/14", height: buttonsHeight }); addNoteBtn.addListener("execute", () => this.__workbenchUI.startAnnotationsNote(), this); annotationsButtons.add(addNoteBtn); const addRectBtn = new qx.ui.form.Button().set({ - label: this.tr("Rectangle"), - icon: "@FontAwesome5Solid/plus/14", + label: this.tr("Box"), + icon: "@FontAwesome5Regular/square/14", height: buttonsHeight }); addRectBtn.addListener("execute", () => this.__workbenchUI.startAnnotationsRect(), this); @@ -899,7 +908,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", { const addTextBtn = new qx.ui.form.Button().set({ label: this.tr("Text"), - icon: "@FontAwesome5Solid/plus/14", + icon: "@FontAwesome5Solid/font/14", height: buttonsHeight }); addTextBtn.addListener("execute", () => this.__workbenchUI.startAnnotationsText(), this); 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 a4380c731958..cfe073b80c0e 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1602,6 +1602,10 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.setScale(closestDown); }, + startConversation: function() { + this.__toolHint.setValue(this.tr("Pick the position")); + }, + startAnnotationsNote: function() { this.__annotatingNote = true; this.__annotatingRect = false; From ca5905ca1fb44aa78e9bd28eab65ed6fa2696d62 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 16:37:32 +0200 Subject: [PATCH 07/63] Types --- .../class/osparc/editor/AnnotationEditor.js | 7 ++- .../source/class/osparc/file/FileDrop.js | 10 ++-- .../class/osparc/workbench/Annotation.js | 23 +++++--- .../class/osparc/workbench/WorkbenchUI.js | 59 +++++++------------ 4 files changed, 45 insertions(+), 54 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js index f62e7b8ef1e7..0089ad940f7c 100644 --- a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js +++ b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js @@ -130,19 +130,20 @@ qx.Class.define("osparc.editor.AnnotationEditor", { } const attrs = annotation.getAttributes(); - if (annotation.getType() === "text") { + if (annotation.getType() === osparc.workbench.Annotation.TYPES.TEXT) { const textField = this.getChildControl("text-field").set({ value: attrs.text }); textField.addListener("changeValue", e => annotation.setText(e.getData())); - } else if (annotation.getType() === "note") { + } else if (annotation.getType() === osparc.workbench.Annotation.TYPES.NOTE) { const textArea = this.getChildControl("text-area").set({ value: attrs.text }); textArea.addListener("changeValue", e => annotation.setText(e.getData())); } - if (["text", "rect"].includes(annotation.getType())) { + const annotationTypes = osparc.workbench.Annotation.TYPES; + if ([annotationTypes.TEXT, annotationTypes.RECT].includes(annotation.getType())) { const colorPicker = this.getChildControl("color-picker"); annotation.bind("color", colorPicker, "value"); colorPicker.bind("value", annotation, "color"); diff --git a/services/static-webserver/client/source/class/osparc/file/FileDrop.js b/services/static-webserver/client/source/class/osparc/file/FileDrop.js index 92b4f15206c9..6411e33276dd 100644 --- a/services/static-webserver/client/source/class/osparc/file/FileDrop.js +++ b/services/static-webserver/client/source/class/osparc/file/FileDrop.js @@ -256,9 +256,9 @@ qx.Class.define("osparc.file.FileDrop", { this._add(this.__dropMe); const svgLayer = this.__svgLayer; if (svgLayer.getReady()) { - this.__dropMe.rect = svgLayer.drawDashedRect(boxWidth, boxHeight); + this.__dropMe["rect"] = svgLayer.drawDashedRect(boxWidth, boxHeight); } else { - svgLayer.addListenerOnce("SvgWidgetReady", () => this.__dropMe.rect = svgLayer.drawDashedRect(boxWidth, boxHeight), this); + svgLayer.addListenerOnce("SvgWidgetReady", () => this.__dropMe["rect"] = svgLayer.drawDashedRect(boxWidth, boxHeight), this); } } const dropMe = this.__dropMe; @@ -269,10 +269,10 @@ qx.Class.define("osparc.file.FileDrop", { top: posY - parseInt(dropMeBounds.height/2)- parseInt(boxHeight/2) }); if ("rect" in dropMe) { - dropMe.rect.stroke({ + dropMe["rect"].stroke({ width: 1 }); - osparc.wrapper.Svg.updateItemPos(dropMe.rect, posX - boxWidth, posY - boxHeight); + osparc.wrapper.Svg.updateItemPos(dropMe["rect"], posX - boxWidth, posY - boxHeight); } }, @@ -280,7 +280,7 @@ qx.Class.define("osparc.file.FileDrop", { const dropMe = this.__dropMe; if (dropMe) { if ("rect" in dropMe) { - dropMe.rect.stroke({ + dropMe["rect"].stroke({ width: 0 }); } 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 7444094680a9..05f2d7d2dd60 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -46,7 +46,13 @@ qx.Class.define("osparc.workbench.Annotation", { }, statics: { - DEFAULT_COLOR: "#FFFF01" + DEFAULT_COLOR: "#FFFF01", + + TYPES: { + NOTE: "note", + RECT: "rect", + TEXT: "text", + }, }, properties: { @@ -56,6 +62,7 @@ qx.Class.define("osparc.workbench.Annotation", { }, type: { + // check: [this.TYPES.NOTE, this.TYPES.RECT, , this.TYPES.TEXT], check: ["note", "rect", "text"], nullable: false }, @@ -95,15 +102,15 @@ qx.Class.define("osparc.workbench.Annotation", { let representation = null; switch (this.getType()) { - case "note": { + case this.self().TYPES.NOTE: { const user = osparc.store.Groups.getInstance().getUserByGroupId(attrs.recipientGid); representation = this.__svgLayer.drawAnnotationNote(attrs.x, attrs.y, user ? user.getLabel() : "", attrs.text); break; } - case "rect": + case this.self().TYPES.RECT: representation = this.__svgLayer.drawAnnotationRect(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); break; - case "text": + case this.self().TYPES.TEXT: representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; } @@ -124,10 +131,10 @@ qx.Class.define("osparc.workbench.Annotation", { const representation = this.getRepresentation(); if (representation) { switch (this.getType()) { - case "rect": + case this.self().TYPES.RECT: osparc.wrapper.Svg.updateItemColor(representation, color); break; - case "text": + case this.self().TYPES.TEXT: osparc.wrapper.Svg.updateTextColor(representation, color); break; } @@ -188,8 +195,8 @@ qx.Class.define("osparc.workbench.Annotation", { const representation = this.getRepresentation(); if (representation) { switch (this.getType()) { - case "rect": - case "text": { + case this.self().TYPES.RECT: + case this.self().TYPES.TEXT: { if (selected) { if (!("bBox" in representation.node)) { const bBox = this.__svgLayer.drawBoundingBox(this); 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 cfe073b80c0e..a3a226d5cd1a 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -136,9 +136,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __isDraggingFile: null, __isDraggingLink: null, __annotations: null, - __annotatingNote: null, - __annotatingRect: null, - __annotatingText: null, + __annotating: null, __annotationInitPos: null, __selectedAnnotations: null, __annotationEditor: null, @@ -329,19 +327,19 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }); temporaryNodeUI.getContentElement().addClass("rotate"); this.__workbenchLayout.add(temporaryNodeUI); - temporaryNodeUI.rect = this.__svgLayer.drawDashedRect(boxWidth, boxHeight); + temporaryNodeUI["rect"] = this.__svgLayer.drawDashedRect(boxWidth, boxHeight); temporaryNodeUI.setLayoutProperties({ left: pos.x + parseInt(boxWidth/2) - parseInt(circleSize/2), top: pos.y + parseInt(boxHeight/2) - parseInt(circleSize/2) }); - osparc.wrapper.Svg.updateItemPos(temporaryNodeUI.rect, pos.x, pos.y); + osparc.wrapper.Svg.updateItemPos(temporaryNodeUI["rect"], pos.x, pos.y); return temporaryNodeUI; }, __removeTemporaryNodeUI: function(temporaryNodeUI) { temporaryNodeUI.exclude(); - osparc.wrapper.Svg.removeItem(temporaryNodeUI.rect); + osparc.wrapper.Svg.removeItem(temporaryNodeUI["rect"]); this.__workbenchLayout.add(temporaryNodeUI); temporaryNodeUI = null; }, @@ -1408,7 +1406,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __mouseDownOnSVG: function(e) { if (e.isLeftPressed()) { - if (this.__annotatingNote || this.__annotatingRect || this.__annotatingText) { + if (this.__annotating) { this.__annotationInitPos = this.__pointerEventToWorkbenchPos(e); } else { this.__selectionRectInitPos = this.__pointerEventToWorkbenchPos(e); @@ -1419,7 +1417,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __mouseMove: function(e) { if (this.__isDraggingLink) { this.__draggingLink(e, true); - } else if (this.__tempEdgeRepr === null && (this.__annotatingNote || this.__annotatingRect || this.__annotatingText) && this.__annotationInitPos && e.isLeftPressed()) { + } else if (this.__tempEdgeRepr === null && this.__annotating && this.__annotationInitPos && e.isLeftPressed()) { this.__drawingAnnotation(e); } else if (this.__tempEdgeRepr === null && this.__selectionRectInitPos && e.isLeftPressed()) { this.__drawingSelectionRect(e); @@ -1449,23 +1447,13 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { if (this.__annotationInitPos) { this.__annotationInitPos = null; } - if (this.__annotatingNote || this.__annotatingRect || this.__annotatingText) { - let annotationType = null; - if (this.__annotatingNote) { - annotationType = "note"; - } else if (this.__annotatingRect) { - annotationType = "rect"; - } else if (this.__annotatingText) { - annotationType = "text"; - } - if (this.__consolidateAnnotation(annotationType, annotationInitPos, this.__rectAnnotationRepr)) { + if (this.__annotating) { + if (this.__consolidateAnnotation(this.__annotating, annotationInitPos, this.__rectAnnotationRepr)) { if (this.__rectAnnotationRepr) { osparc.wrapper.Svg.removeItem(this.__rectAnnotationRepr); this.__rectAnnotationRepr = null; } - this.__annotatingNote = false; - this.__annotatingRect = false; - this.__annotatingText = false; + this.__annotating = null; this.__toolHint.setValue(null); } } @@ -1607,23 +1595,17 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }, startAnnotationsNote: function() { - this.__annotatingNote = true; - this.__annotatingRect = false; - this.__annotatingText = false; + this.__annotating = osparc.workbench.Annotation.TYPES.NOTE; this.__toolHint.setValue(this.tr("Pick the position")); }, startAnnotationsRect: function() { - this.__annotatingNote = false; - this.__annotatingRect = true; - this.__annotatingText = false; + this.__annotating = osparc.workbench.Annotation.TYPES.RECT; this.__toolHint.setValue(this.tr("Draw a rectangle")); }, startAnnotationsText: function(workbenchPos) { - this.__annotatingNote = false; - this.__annotatingText = true; - this.__annotatingRect = false; + this.__annotating = osparc.workbench.Annotation.TYPES.TEXT; if (workbenchPos) { this.__annotationInitPos = workbenchPos; this.__mouseUp(); @@ -1825,7 +1807,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }); dropHereNodeUI.exclude(); this.__workbenchLayout.add(dropHereNodeUI); - dropHereNodeUI.rect = this.__svgLayer.drawDashedRect(boxWidth, boxHeight); + dropHereNodeUI["rect"] = this.__svgLayer.drawDashedRect(boxWidth, boxHeight); } let dropHere = this.__dropHereUI; if (show) { @@ -1836,11 +1818,11 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { top: posY - parseInt(dropMeBounds.height/2)- parseInt(boxHeight/2) }); if ("rect" in dropHere) { - osparc.wrapper.Svg.updateItemPos(dropHere.rect, posX - boxWidth, posY - boxHeight); + osparc.wrapper.Svg.updateItemPos(dropHere["rect"], posX - boxWidth, posY - boxHeight); } } else { dropHere.exclude(); - osparc.wrapper.Svg.removeItem(dropHere.rect); + osparc.wrapper.Svg.removeItem(dropHere["rect"]); dropHere = null; } }, @@ -1915,13 +1897,14 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }, __consolidateAnnotation: function(type, initPos, annotation) { + const annotationTypes = osparc.workbench.Annotation.TYPES; const color = this.__annotationLastColor ? this.__annotationLastColor : osparc.workbench.Annotation.DEFAULT_COLOR; const serializeData = { type, color, attributes: {} }; - if (type === "rect") { + if (type === annotationTypes.RECT) { if ([null, undefined].includes(annotation)) { osparc.FlashMessenger.logAs(this.tr("Draw a rectangle first"), "WARNING"); return false; @@ -1930,7 +1913,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } else { serializeData.attributes = initPos; } - if (type === "note") { + if (type === annotationTypes.NOTE) { const noteEditor = new osparc.editor.AnnotationNoteCreator(this.getStudy()); const win = osparc.editor.AnnotationNoteCreator.popUpInWindow(noteEditor); noteEditor.addListener("addNote", () => { @@ -1945,11 +1928,11 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { win.close(); }, this); noteEditor.addListener("cancel", () => win.close()); - } else if (type === "rect") { + } else if (type === annotationTypes.RECT) { this.__addAnnotation(serializeData); - } else if (type === "text") { + } else if (type === annotationTypes.TEXT) { const tempAnnotation = new osparc.workbench.Annotation(null, { - type: "text", + type: annotationTypes.TEXT, color, attributes: { text: "", From 7343fd092b42de509005a01c45d438a52f0dab59 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 16:39:35 +0200 Subject: [PATCH 08/63] minor --- .../client/source/class/osparc/workbench/Annotation.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 05f2d7d2dd60..110708925b4a 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -62,8 +62,11 @@ qx.Class.define("osparc.workbench.Annotation", { }, type: { - // check: [this.TYPES.NOTE, this.TYPES.RECT, , this.TYPES.TEXT], - check: ["note", "rect", "text"], + check: [ + "note", // osparc.workbench.Annotation.TYPES.NOTE + "rect", // osparc.workbench.Annotation.TYPES.RECT + "text", // osparc.workbench.Annotation.TYPES.TEXT + ], nullable: false }, From 42fe33967e95cb7fc7786dc7fd37bcd86b743dc1 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 16:56:55 +0200 Subject: [PATCH 09/63] minor --- .../client/source/class/osparc/editor/AnnotationEditor.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js index 0089ad940f7c..7f8b4553c97e 100644 --- a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js +++ b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js @@ -129,20 +129,21 @@ qx.Class.define("osparc.editor.AnnotationEditor", { return; } + const annotationTypes = osparc.workbench.Annotation.TYPES; + const attrs = annotation.getAttributes(); - if (annotation.getType() === osparc.workbench.Annotation.TYPES.TEXT) { + if (annotation.getType() === annotationTypes.TEXT) { const textField = this.getChildControl("text-field").set({ value: attrs.text }); textField.addListener("changeValue", e => annotation.setText(e.getData())); - } else if (annotation.getType() === osparc.workbench.Annotation.TYPES.NOTE) { + } else if (annotation.getType() === annotationTypes.NOTE) { const textArea = this.getChildControl("text-area").set({ value: attrs.text }); textArea.addListener("changeValue", e => annotation.setText(e.getData())); } - const annotationTypes = osparc.workbench.Annotation.TYPES; if ([annotationTypes.TEXT, annotationTypes.RECT].includes(annotation.getType())) { const colorPicker = this.getChildControl("color-picker"); annotation.bind("color", colorPicker, "value"); From 643eeebd58f8ac512f1d9d6aef5f7049a4332364 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Fri, 27 Jun 2025 16:57:29 +0200 Subject: [PATCH 10/63] minor --- .../client/source/class/osparc/editor/AnnotationEditor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js index 7f8b4553c97e..d26d6296d89b 100644 --- a/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js +++ b/services/static-webserver/client/source/class/osparc/editor/AnnotationEditor.js @@ -150,7 +150,7 @@ qx.Class.define("osparc.editor.AnnotationEditor", { colorPicker.bind("value", annotation, "color"); } - if (annotation.getType() === "text") { + if (annotation.getType() === annotationTypes.TEXT) { const fontSizeField = this.getChildControl("font-size").set({ value: attrs.fontSize }) From 7aea0a36164d2c8eb29dece5fb14d3a943b78ade Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 07:52:25 +0200 Subject: [PATCH 11/63] refactor --- .../class/osparc/workbench/WorkbenchUI.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) 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 a3a226d5cd1a..e0da24bb7310 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1448,7 +1448,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__annotationInitPos = null; } if (this.__annotating) { - if (this.__consolidateAnnotation(this.__annotating, annotationInitPos, this.__rectAnnotationRepr)) { + if (this.__consolidateAnnotation(annotationInitPos, this.__rectAnnotationRepr)) { if (this.__rectAnnotationRepr) { osparc.wrapper.Svg.removeItem(this.__rectAnnotationRepr); this.__rectAnnotationRepr = null; @@ -1590,10 +1590,6 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.setScale(closestDown); }, - startConversation: function() { - this.__toolHint.setValue(this.tr("Pick the position")); - }, - startAnnotationsNote: function() { this.__annotating = osparc.workbench.Annotation.TYPES.NOTE; this.__toolHint.setValue(this.tr("Pick the position")); @@ -1614,6 +1610,16 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } }, + startConversation: function(workbenchPos) { + this.__annotating = osparc.workbench.Annotation.TYPES.CONVERSATION; + if (workbenchPos) { + this.__annotationInitPos = workbenchPos; + this.__mouseUp(); + } else { + this.__toolHint.setValue(this.tr("Pick the position")); + } + }, + __openNodeRenamer: function(nodeId) { const node = this.getStudy().getWorkbench().getNode(nodeId); const treeItemRenamer = new osparc.widget.Renamer(node.getLabel()); @@ -1896,7 +1902,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } }, - __consolidateAnnotation: function(type, initPos, annotation) { + __consolidateAnnotation: function(initPos, annotation) { + const type = this.__annotating; const annotationTypes = osparc.workbench.Annotation.TYPES; const color = this.__annotationLastColor ? this.__annotationLastColor : osparc.workbench.Annotation.DEFAULT_COLOR; const serializeData = { From 87b28971193ae02890e76002483710b8fe6cd39c Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 07:52:41 +0200 Subject: [PATCH 12/63] new type --- .../client/source/class/osparc/workbench/Annotation.js | 7 +++++++ 1 file changed, 7 insertions(+) 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 110708925b4a..249ac29ec6dc 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -52,6 +52,7 @@ qx.Class.define("osparc.workbench.Annotation", { NOTE: "note", RECT: "rect", TEXT: "text", + CONVERSATION: "conversation", }, }, @@ -66,6 +67,7 @@ qx.Class.define("osparc.workbench.Annotation", { "note", // osparc.workbench.Annotation.TYPES.NOTE "rect", // osparc.workbench.Annotation.TYPES.RECT "text", // osparc.workbench.Annotation.TYPES.TEXT + "conversation", // osparc.workbench.Annotation.TYPES.CONVERSATION ], nullable: false }, @@ -116,6 +118,11 @@ qx.Class.define("osparc.workbench.Annotation", { case this.self().TYPES.TEXT: representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; + case this.self().TYPES.CONVERSATION: { + console.log("attrs", attrs); + representation = this.__svgLayer.drawAnnotationRect(100, 30, attrs.x, attrs.y, "#00FF00"); + break; + } } if (representation) { osparc.wrapper.Svg.makeDraggable(representation); From c29dba773010ede0cd2fe5205a847c7128ff1a7b Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:02:20 +0200 Subject: [PATCH 13/63] refactor --- .../class/osparc/workbench/WorkbenchUI.js | 105 ++++++++++-------- 1 file changed, 57 insertions(+), 48 deletions(-) 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 e0da24bb7310..fbecc8ce8691 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1904,13 +1904,14 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __consolidateAnnotation: function(initPos, annotation) { const type = this.__annotating; - const annotationTypes = osparc.workbench.Annotation.TYPES; const color = this.__annotationLastColor ? this.__annotationLastColor : osparc.workbench.Annotation.DEFAULT_COLOR; const serializeData = { type, color, attributes: {} }; + + const annotationTypes = osparc.workbench.Annotation.TYPES; if (type === annotationTypes.RECT) { if ([null, undefined].includes(annotation)) { osparc.FlashMessenger.logAs(this.tr("Draw a rectangle first"), "WARNING"); @@ -1920,55 +1921,63 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } else { serializeData.attributes = initPos; } - if (type === annotationTypes.NOTE) { - const noteEditor = new osparc.editor.AnnotationNoteCreator(this.getStudy()); - const win = osparc.editor.AnnotationNoteCreator.popUpInWindow(noteEditor); - noteEditor.addListener("addNote", () => { - const gid = noteEditor.getRecipientGid(); - serializeData.attributes.recipientGid = gid; - serializeData.attributes.text = noteEditor.getNote(); - const user = osparc.store.Groups.getInstance().getUserByGroupId(gid) - if (user) { - osparc.notification.Notifications.pushNewAnnotationNote(user.getUserId(), this.getStudy().getUuid()); - } - this.__addAnnotation(serializeData); - win.close(); - }, this); - noteEditor.addListener("cancel", () => win.close()); - } else if (type === annotationTypes.RECT) { - this.__addAnnotation(serializeData); - } else if (type === annotationTypes.TEXT) { - const tempAnnotation = new osparc.workbench.Annotation(null, { - type: annotationTypes.TEXT, - color, - attributes: { - text: "", - fontSize: 12 - } - }); - const annotationEditor = new osparc.editor.AnnotationEditor(tempAnnotation); - annotationEditor.addAddButtons(); - tempAnnotation.addListener("changeColor", e => this.__annotationLastColor = e.getData()); - annotationEditor.addListener("appear", () => { - const textField = annotationEditor.getChildControl("text-field"); - textField.focus(); - textField.activate(); - }); - const win = osparc.ui.window.Window.popUpInWindow(annotationEditor, "Add Text Annotation", 220, 135).set({ - clickAwayClose: true, - showClose: true - }); - annotationEditor.addListener("addAnnotation", () => { - win.close(); - const form = annotationEditor.getForm(); - serializeData.attributes.text = form.getItem("text").getValue(); - serializeData.attributes.color = form.getItem("color").getValue(); - serializeData.color = form.getItem("color").getValue(); - serializeData.attributes.fontSize = form.getItem("size").getValue(); + + switch (type) { + case annotationTypes.NOTE: { + const noteEditor = new osparc.editor.AnnotationNoteCreator(this.getStudy()); + const win = osparc.editor.AnnotationNoteCreator.popUpInWindow(noteEditor); + noteEditor.addListener("addNote", () => { + const gid = noteEditor.getRecipientGid(); + serializeData.attributes.recipientGid = gid; + serializeData.attributes.text = noteEditor.getNote(); + const user = osparc.store.Groups.getInstance().getUserByGroupId(gid) + if (user) { + osparc.notification.Notifications.pushNewAnnotationNote(user.getUserId(), this.getStudy().getUuid()); + } + this.__addAnnotation(serializeData); + win.close(); + }, this); + noteEditor.addListener("cancel", () => win.close()); + break; + } + case annotationTypes.RECT: this.__addAnnotation(serializeData); - }, this); - win.open(); + break; + case annotationTypes.TEXT: { + const tempAnnotation = new osparc.workbench.Annotation(null, { + type: annotationTypes.TEXT, + color, + attributes: { + text: "", + fontSize: 12 + } + }); + const annotationEditor = new osparc.editor.AnnotationEditor(tempAnnotation); + annotationEditor.addAddButtons(); + tempAnnotation.addListener("changeColor", e => this.__annotationLastColor = e.getData()); + annotationEditor.addListener("appear", () => { + const textField = annotationEditor.getChildControl("text-field"); + textField.focus(); + textField.activate(); + }); + const win = osparc.ui.window.Window.popUpInWindow(annotationEditor, "Add Text Annotation", 220, 135).set({ + clickAwayClose: true, + showClose: true + }); + annotationEditor.addListener("addAnnotation", () => { + win.close(); + const form = annotationEditor.getForm(); + serializeData.attributes.text = form.getItem("text").getValue(); + serializeData.attributes.color = form.getItem("color").getValue(); + serializeData.color = form.getItem("color").getValue(); + serializeData.attributes.fontSize = form.getItem("size").getValue(); + this.__addAnnotation(serializeData); + }, this); + win.open(); + break; + } } + return true; }, From 9d63145f08a9e025a1215aa6a04d0e6ae0c764a1 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:16:58 +0200 Subject: [PATCH 14/63] refactor --- .../class/osparc/workbench/WorkbenchUI.js | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) 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 fbecc8ce8691..cfaa4a4eab7e 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -132,6 +132,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __dropHereUI: null, __selectionRectInitPos: null, __selectionRectRepr: null, + __rectAnnotationRepr: null, __panning: null, __isDraggingFile: null, __isDraggingLink: null, @@ -1448,14 +1449,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__annotationInitPos = null; } if (this.__annotating) { - if (this.__consolidateAnnotation(annotationInitPos, this.__rectAnnotationRepr)) { - if (this.__rectAnnotationRepr) { - osparc.wrapper.Svg.removeItem(this.__rectAnnotationRepr); - this.__rectAnnotationRepr = null; - } - this.__annotating = null; - this.__toolHint.setValue(null); - } + this.__consolidateAnnotation(annotationInitPos); } if (this.__panning) { @@ -1894,15 +1888,21 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { const y = Math.min(initPos.y, currentPos.y); const width = Math.abs(initPos.x - currentPos.x); const height = Math.abs(initPos.y - currentPos.y); - if ([null, undefined].includes(this.__rectAnnotationRepr)) { + if (this.__rectAnnotationRepr) { + osparc.wrapper.Svg.updateRect(this.__rectAnnotationRepr, width, height, x, y); + } else { const color = this.__annotationLastColor ? this.__annotationLastColor : osparc.workbench.Annotation.DEFAULT_COLOR; this.__rectAnnotationRepr = this.__svgLayer.drawAnnotationRect(width, height, x, y, color); - } else { - osparc.wrapper.Svg.updateRect(this.__rectAnnotationRepr, width, height, x, y); } }, - __consolidateAnnotation: function(initPos, annotation) { + __consolidateAnnotation: function(initPos) { + const annotationTypes = osparc.workbench.Annotation.TYPES; + if (type === annotationTypes.RECT && !this.__rectAnnotationRepr) { + osparc.FlashMessenger.logAs(this.tr("Draw a rectangle first"), "WARNING"); + return; + } + const type = this.__annotating; const color = this.__annotationLastColor ? this.__annotationLastColor : osparc.workbench.Annotation.DEFAULT_COLOR; const serializeData = { @@ -1910,14 +1910,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { color, attributes: {} }; - - const annotationTypes = osparc.workbench.Annotation.TYPES; if (type === annotationTypes.RECT) { - if ([null, undefined].includes(annotation)) { - osparc.FlashMessenger.logAs(this.tr("Draw a rectangle first"), "WARNING"); - return false; - } - serializeData.attributes = osparc.wrapper.Svg.getRectAttributes(annotation); + serializeData.attributes = osparc.wrapper.Svg.getRectAttributes(this.__rectAnnotationRepr); } else { serializeData.attributes = initPos; } @@ -1940,9 +1934,14 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { noteEditor.addListener("cancel", () => win.close()); break; } - case annotationTypes.RECT: + case annotationTypes.RECT: { this.__addAnnotation(serializeData); + if (this.__rectAnnotationRepr) { + osparc.wrapper.Svg.removeItem(this.__rectAnnotationRepr); + this.__rectAnnotationRepr = null; + } break; + } case annotationTypes.TEXT: { const tempAnnotation = new osparc.workbench.Annotation(null, { type: annotationTypes.TEXT, @@ -1976,9 +1975,14 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { win.open(); break; } + case annotationTypes.CONVERSATION: { + console.log("CONVERSATION", initPos); + break; + } } - return true; + this.__annotating = null; + this.__toolHint.setValue(null); }, __addAnnotation: function(data, id) { From 41012f5480ecb5cd19e988a8e759977941cb03ae Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:29:45 +0200 Subject: [PATCH 15/63] Add conversation --- .../client/source/class/osparc/study/Conversations.js | 2 +- .../client/source/class/osparc/workbench/WorkbenchUI.js | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) 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 b54be1492ae7..10f99bb7ac54 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -48,7 +48,7 @@ qx.Class.define("osparc.study.Conversations", { statics: { TYPES: { PROJECT_STATIC: "PROJECT_STATIC", - PROJECT_DYNAMIC: "PROJECT_DYNAMIC", + PROJECT_ANNOTATION: "PROJECT_ANNOTATION", }, popUpInWindow: function(studyData) { 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 cfaa4a4eab7e..c4d5aee8185f 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1976,7 +1976,12 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { break; } case annotationTypes.CONVERSATION: { - console.log("CONVERSATION", initPos); + const conversationTitle = `${x}, ${y}`; + osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) + .then(conversationData => { + console.log("Conversation created", conversationData); + osparc.study.Conversations.popUpInWindow(this.getStudy().serialize()); + }); break; } } From 5a946a486ec5c5b70227fe88776dc7967d434279 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:37:46 +0200 Subject: [PATCH 16/63] create conversation logic --- .../source/class/osparc/study/Conversations.js | 16 ++++++++++++++-- .../source/class/osparc/workbench/WorkbenchUI.js | 5 ++--- 2 files changed, 16 insertions(+), 5 deletions(-) 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 10f99bb7ac54..e76077c13d50 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -22,12 +22,13 @@ qx.Class.define("osparc.study.Conversations", { /** * @param studyData {Object} Study Data */ - construct: function(studyData) { + construct: function(studyData, openConversationId = null) { this.base(arguments); this._setLayout(new qx.ui.layout.VBox()); this.__conversations = []; + this.__openConversationId = openConversationId; this.set({ studyData, @@ -51,7 +52,7 @@ qx.Class.define("osparc.study.Conversations", { PROJECT_ANNOTATION: "PROJECT_ANNOTATION", }, - popUpInWindow: function(studyData) { + popUpInWindow: function(studyData, openConversationId = null) { const conversations = new osparc.study.Conversations(studyData); const title = qx.locale.Manager.tr("Conversations"); const viewWidth = 600; @@ -161,6 +162,7 @@ qx.Class.define("osparc.study.Conversations", { }, members: { + __openConversationId: null, __conversations: null, __newConversationButton: null, __wsHandlers: null, @@ -259,7 +261,17 @@ qx.Class.define("osparc.study.Conversations", { osparc.data.Resources.fetch("conversations", "getConversationsPage", params) .then(conversations => { if (conversations.length) { + // Sort conversations by created date, newest first + conversations.sort((a, b) => new Date(b.created) - new Date(a.created)); conversations.forEach(conversation => this.__addConversationPage(conversation)); + if (this.__openConversationId) { + const conversationsLayout = this.getChildControl("conversations-layout"); + const conversation = conversationsLayout.getSelectables().find(c => c.getConversationId() === this.__openConversationId); + if (conversation) { + conversationsLayout.setSelection([conversation]); + } + this.__openConversationId = null; // reset it so it does not open again + } } else { this.__addTempConversationPage(); } 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 c4d5aee8185f..3148cf58ebfe 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1976,11 +1976,10 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { break; } case annotationTypes.CONVERSATION: { - const conversationTitle = `${x}, ${y}`; + const conversationTitle = `${initPos.x}, ${initPos.y}`; osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) .then(conversationData => { - console.log("Conversation created", conversationData); - osparc.study.Conversations.popUpInWindow(this.getStudy().serialize()); + osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); }); break; } From 9918b372ae0dc91168cbf903c194cff991ba1a2e Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:50:24 +0200 Subject: [PATCH 17/63] AnnotationUI --- .../api_schemas_webserver/projects_ui.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py index 9bbb92f447c2..7205bf1fde44 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py @@ -40,7 +40,7 @@ class SlideshowUI(TypedDict): class AnnotationUI(BaseModel): - type: Literal["note", "rect", "text"] + type: Literal["note", "rect", "text", "conversation"] color: Annotated[Color, PlainSerializer(Color.as_hex)] attributes: Annotated[dict, Field(description="svg attributes")] @@ -71,6 +71,10 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "color": "#0000FF", "attributes": {"x": 415, "y": 100, "text": "Hey!"}, }, + { + "type": "conversation", + "attributes": {"x": 415, "y": 100}, + }, ] }, ) @@ -169,6 +173,13 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "fontSize": 12, }, }, + "cf94f068-259c-4192-89f9-b2a56d51249d": { + "type": "conversation", + "attributes": { + "x": 119, + "y": 223, + }, + }, }, "current_node_id": "4b3345e5-861f-47b0-8b52-a4508449be79", "template_type": "hypertool", From f89623ee9ca0802c8d3ae9f9143460fcb13388fe Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:50:44 +0200 Subject: [PATCH 18/63] add annotationUI --- .../client/source/class/osparc/study/Conversations.js | 2 +- .../client/source/class/osparc/workbench/Annotation.js | 4 ++-- .../client/source/class/osparc/workbench/WorkbenchUI.js | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) 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 e76077c13d50..3946b8e813d9 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -262,7 +262,7 @@ qx.Class.define("osparc.study.Conversations", { .then(conversations => { if (conversations.length) { // Sort conversations by created date, newest first - conversations.sort((a, b) => new Date(b.created) - new Date(a.created)); + conversations.sort((a, b) => new Date(b["created"]) - new Date(a["created"])); conversations.forEach(conversation => this.__addConversationPage(conversation)); if (this.__openConversationId) { const conversationsLayout = this.getChildControl("conversations-layout"); 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 249ac29ec6dc..9e3d83bad4c7 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -119,8 +119,8 @@ qx.Class.define("osparc.workbench.Annotation", { representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; case this.self().TYPES.CONVERSATION: { - console.log("attrs", attrs); - representation = this.__svgLayer.drawAnnotationRect(100, 30, attrs.x, attrs.y, "#00FF00"); + const text = `${attrs.x}, ${attrs.y}`; + representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, text, "#00FF00", 12); break; } } 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 3148cf58ebfe..b930a67f48fd 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1976,10 +1976,15 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { break; } case annotationTypes.CONVERSATION: { + const annotation = this.__addAnnotation(serializeData); const conversationTitle = `${initPos.x}, ${initPos.y}`; osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) .then(conversationData => { osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); + }) + .catch(() => { + // remove annotation if conversation creation fails + this.__removeAnnotation(annotation.getId()); }); break; } @@ -1994,6 +1999,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__addAnnotationListeners(annotation); this.__annotations[annotation.getId()] = annotation; this.getStudy().getUi().addAnnotation(annotation); + return annotation; }, __removeAnnotation: function(id) { From b2e6fe13a23ddd8024634ea52e91fbe12db94405 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:52:45 +0200 Subject: [PATCH 19/63] openapi-specs --- .../web/server/src/simcore_service_webserver/api/v0/openapi.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml index 23dbe53f649c..768cee9ee94d 100644 --- a/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml +++ b/services/web/server/src/simcore_service_webserver/api/v0/openapi.yaml @@ -8466,6 +8466,7 @@ components: - note - rect - text + - conversation title: Type color: type: string From 2894e7d5716db0dfc5443c42527e2a8043264924 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 08:55:58 +0200 Subject: [PATCH 20/63] conversationId attributes --- .../models_library/api_schemas_webserver/projects_ui.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py index 7205bf1fde44..94b8371e3880 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py @@ -73,7 +73,11 @@ def _update_json_schema_extra(schema: JsonDict) -> None: }, { "type": "conversation", - "attributes": {"x": 415, "y": 100}, + "attributes": { + "x": 415, + "y": 100, + "conversationId": 2, + }, }, ] }, @@ -178,6 +182,7 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "attributes": { "x": 119, "y": 223, + "conversation": 2, }, }, }, From c3f81f0ed32e7a34b2570587c8ab2141bb3a2ec0 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:04:06 +0200 Subject: [PATCH 21/63] save conversationId --- .../client/source/class/osparc/workbench/WorkbenchUI.js | 1 + 1 file changed, 1 insertion(+) 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 b930a67f48fd..5406ad67ebf0 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1980,6 +1980,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { const conversationTitle = `${initPos.x}, ${initPos.y}`; osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) .then(conversationData => { + serializeData.attributes.conversationId = conversationData["conversationId"]; osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); }) .catch(() => { From 42db8898547bdf409196837f77ab4cf97cbfe7d9 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:12:54 +0200 Subject: [PATCH 22/63] nullable color --- .../source/class/osparc/workbench/Annotation.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) 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 9e3d83bad4c7..5462d7356f60 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -76,7 +76,8 @@ qx.Class.define("osparc.workbench.Annotation", { check: "Color", event: "changeColor", init: "#FFFF01", - apply: "__applyColor" + nullable: true, + apply: "__applyColor", }, attributes: { @@ -223,11 +224,14 @@ qx.Class.define("osparc.workbench.Annotation", { }, serialize: function() { - return { + const data = { type: this.getType(), attributes: this.getAttributes(), - color: this.getColor() - }; + } + if (this.getColor()) { + data.color = this.getColor(); + } + return data; } } }); From 37bc778f99662b191f81008020c84ecfdb531739 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:23:48 +0200 Subject: [PATCH 23/63] minor --- .../client/source/class/osparc/workbench/Annotation.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 5462d7356f60..eb149709f9dc 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -224,11 +224,12 @@ qx.Class.define("osparc.workbench.Annotation", { }, serialize: function() { + const type = this.getType(); const data = { - type: this.getType(), + type, attributes: this.getAttributes(), } - if (this.getColor()) { + if (type !== this.self().TYPES.CONVERSATION) { data.color = this.getColor(); } return data; From 365f3ab9ec2dbcbdfe45728d0193fab0bdc4e142 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:31:44 +0200 Subject: [PATCH 24/63] non filterable --- .../class/osparc/workbench/BaseNodeUI.js | 30 ----------------- .../source/class/osparc/workbench/NodeUI.js | 32 ------------------- 2 files changed, 62 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js b/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js index bd43406a5183..5d1d971a93ab 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js @@ -17,8 +17,6 @@ qx.Class.define("osparc.workbench.BaseNodeUI", { extend: qx.ui.window.Window, - include: osparc.filter.MFilterable, - implement: osparc.filter.IFilterable, type: "abstract", construct: function() { @@ -308,33 +306,5 @@ qx.Class.define("osparc.workbench.BaseNodeUI", { e.stopPropagation(); }, - - // implement osparc.filter.IFilterable - _filter: function() { - this.setOpacity(0.4); - }, - - // implement osparc.filter.IFilterable - _unfilter: function() { - this.setOpacity(1); - }, - - /** - * @abstract - */ - _shouldApplyFilter: function(data) { - throw new Error("Abstract method called!"); - }, - - // implement osparc.filter.IFilterable - _shouldReactToFilter: function(data) { - if (data.text && data.text.length > 1) { - return true; - } - if (data.tags && data.tags.length) { - return true; - } - return false; - } } }); 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 e6772e9c28f7..80fb1522b45e 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/NodeUI.js @@ -666,37 +666,5 @@ qx.Class.define("osparc.workbench.NodeUI", { }); } }, - - __filterText: function(text) { - const label = this.getNode().getLabel() - .trim() - .toLowerCase(); - if (label.indexOf(text) === -1) { - return true; - } - return false; - }, - - __filterTags: function(tags) { - if (tags && tags.length) { - const category = this.getNode().getMetaData().category || ""; - const type = this.getNode().getMetaData().type || ""; - if (!tags.includes(osparc.utils.Utils.capitalize(category.trim())) && !tags.includes(osparc.utils.Utils.capitalize(type.trim()))) { - return true; - } - } - return false; - }, - - // implement osparc.filter.IFilterable - _shouldApplyFilter: function(data) { - if (data.text) { - return this.__filterText(data.text); - } - if (data.tags && data.tags.length) { - return this.__filterTags(data.tags); - } - return false; - } } }); From 4ade7c86381bb1e2d4c6bf8c460c514453623195 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:31:54 +0200 Subject: [PATCH 25/63] minor --- .../class/osparc/workbench/Annotation.js | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) 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 eb149709f9dc..eed69b2a0610 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -111,29 +111,41 @@ qx.Class.define("osparc.workbench.Annotation", { case this.self().TYPES.NOTE: { const user = osparc.store.Groups.getInstance().getUserByGroupId(attrs.recipientGid); representation = this.__svgLayer.drawAnnotationNote(attrs.x, attrs.y, user ? user.getLabel() : "", attrs.text); + representation.isSVG = true; break; } case this.self().TYPES.RECT: representation = this.__svgLayer.drawAnnotationRect(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); + representation.isSVG = true; break; case this.self().TYPES.TEXT: representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); + representation.isSVG = true; break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, text, "#00FF00", 12); + representation.isSVG = false; break; } } if (representation) { - osparc.wrapper.Svg.makeDraggable(representation); - representation.node.addEventListener("click", e => { - this.fireDataEvent("annotationClicked", e.ctrlKey); - e.stopPropagation(); - }, this); - representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); - representation.on("dragmove", () => this.fireEvent("annotationMoving")); - representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); + if (representation.isSVG) { + osparc.wrapper.Svg.makeDraggable(representation); + representation.node.addEventListener("click", e => { + this.fireDataEvent("annotationClicked", e.ctrlKey); + e.stopPropagation(); + }, this); + representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); + representation.on("dragmove", () => this.fireEvent("annotationMoving")); + representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); + } else { + representation.addListener("tap", e => { + this.fireDataEvent("annotationClicked", e.ctrlKey); + e.stopPropagation(); + }, this); + // OM: handle drag events for non-SVG representations + } this.setRepresentation(representation); } }, From a7405b7ed057aa721d45e97cd5ef3bfe796a7a9b Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 09:35:02 +0200 Subject: [PATCH 26/63] unused --- .../class/osparc/desktop/ControlsBar.js | 104 ------------------ .../source/class/osparc/desktop/MainPanel.js | 85 -------------- .../class/osparc/workbench/BaseNodeUI.js | 2 - 3 files changed, 191 deletions(-) delete mode 100644 services/static-webserver/client/source/class/osparc/desktop/ControlsBar.js delete mode 100644 services/static-webserver/client/source/class/osparc/desktop/MainPanel.js diff --git a/services/static-webserver/client/source/class/osparc/desktop/ControlsBar.js b/services/static-webserver/client/source/class/osparc/desktop/ControlsBar.js deleted file mode 100644 index 9c4c9fe9ffe9..000000000000 --- a/services/static-webserver/client/source/class/osparc/desktop/ControlsBar.js +++ /dev/null @@ -1,104 +0,0 @@ -/* ************************************************************************ - - osparc - the simcore frontend - - https://osparc.io - - Copyright: - 2018 IT'IS Foundation, https://itis.swiss - - License: - MIT: https://opensource.org/licenses/MIT - - Authors: - * Odei Maiz (odeimaiz) - -************************************************************************ */ - -/** - * Widget that shows the play/stop study button. - * - * *Example* - * - * Here is a little example of how to use the widget. - * - *
- *   let controlsBar = new osparc.desktop.ControlsBar();
- *   this.getRoot().add(controlsBar);
- * 
- */ - -qx.Class.define("osparc.desktop.ControlsBar", { - extend: qx.ui.toolbar.ToolBar, - - construct: function() { - this.base(arguments); - - this.setSpacing(10); - - this.__initDefault(); - this.__attachEventHandlers(); - }, - - events: { - "showWorkbench": "qx.event.type.Event", - "showSettings": "qx.event.type.Event", - "groupSelection": "qx.event.type.Event", - "ungroupSelection": "qx.event.type.Event" - }, - - members: { - __serviceFilters: null, - __viewCtrls: null, - __workbenchViewButton: null, - __settingsViewButton: null, - __iterationCtrls: null, - __parametersButton: null, - - setWorkbenchVisibility: function(isWorkbenchContext) { - this.__serviceFilters.setVisibility(isWorkbenchContext ? "visible" : "excluded"); - }, - - setExtraViewVisibility: function(hasExtraView) { - this.__viewCtrls.setVisibility(hasExtraView ? "visible" : "excluded"); - }, - - __initDefault: function() { - const filterCtrls = new qx.ui.toolbar.Part(); - const serviceFilters = this.__serviceFilters = new osparc.filter.group.ServiceFilterGroup("workbench"); - osparc.filter.UIFilterController.getInstance().registerContainer("workbench", serviceFilters); - filterCtrls.add(serviceFilters); - this.add(filterCtrls); - - this.addSpacer(); - - const viewCtrls = this.__viewCtrls = new qx.ui.toolbar.Part(); - const workbenchViewButton = this.__workbenchViewButton = this.__createWorkbenchButton(); - const settingsViewButton = this.__settingsViewButton = this.__createSettingsButton(); - viewCtrls.add(workbenchViewButton); - viewCtrls.add(settingsViewButton); - this.add(viewCtrls); - const viewRadioGroup = new qx.ui.form.RadioGroup(); - viewRadioGroup.add(workbenchViewButton, settingsViewButton); - }, - - __createWorkbenchButton: function() { - const workbenchButton = this.__createRadioButton(this.tr("Workbench view"), "vector-square", "workbenchViewBtn", "showWorkbench"); - return workbenchButton; - }, - - __createSettingsButton: function() { - const settingsButton = this.__createRadioButton(this.tr("Node view"), "list", "settingsViewBtn", "showSettings"); - return settingsButton; - }, - - __createRadioButton: function(label, icon, widgetId, singalName) { - const button = new qx.ui.toolbar.RadioButton(label); - osparc.utils.Utils.setIdToWidget(button, widgetId); - button.addListener("execute", () => { - this.fireEvent(singalName); - }, this); - return button; - } - } -}); diff --git a/services/static-webserver/client/source/class/osparc/desktop/MainPanel.js b/services/static-webserver/client/source/class/osparc/desktop/MainPanel.js deleted file mode 100644 index 06161e10d7c4..000000000000 --- a/services/static-webserver/client/source/class/osparc/desktop/MainPanel.js +++ /dev/null @@ -1,85 +0,0 @@ -/* ************************************************************************ - - osparc - the simcore frontend - - https://osparc.io - - Copyright: - 2018 IT'IS Foundation, https://itis.swiss - - License: - MIT: https://opensource.org/licenses/MIT - - Authors: - * Odei Maiz (odeimaiz) - -************************************************************************ */ - -/* eslint no-underscore-dangle: 0 */ - -/** - * Widget containing a Vertical Box with a MainView and ControlsBar. - * Used as Main View in the study editor. - * - * *Example* - * - * Here is a little example of how to use the widget. - * - *
- *   let mainPanel = this.__mainPanel = new osparc.desktop.MainPanel();
- *   mainPanel.setMainView(widget);
- *   this.getRoot().add(mainPanel);
- * 
- */ - -qx.Class.define("osparc.desktop.MainPanel", { - extend: qx.ui.core.Widget, - - construct: function() { - this.base(arguments); - - this._setLayout(new qx.ui.layout.VBox()); - - const wbToolbar = this.__wbToolbar = new osparc.desktop.WorkbenchToolbar(); - this._add(wbToolbar); - - const hBox = this.__mainView = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({ - allowGrowY: true - }); - this._add(hBox, { - flex: 1 - }); - - const controlsBar = this.__controlsBar = new osparc.desktop.ControlsBar(); - this._add(controlsBar); - }, - - properties: { - mainView: { - nullable: false, - check : "qx.ui.core.Widget", - apply : "__applyMainView" - } - }, - - members: { - __wbToolbar: null, - __mainView: null, - __controlsBar: null, - - __applyMainView: function(newWidget) { - this.__mainView.removeAll(); - this.__mainView.add(newWidget, { - flex: 1 - }); - }, - - getToolbar: function() { - return this.__wbToolbar; - }, - - getControls: function() { - return this.__controlsBar; - } - } -}); diff --git a/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js b/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js index 5d1d971a93ab..6ea4228772cd 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/BaseNodeUI.js @@ -41,8 +41,6 @@ qx.Class.define("osparc.workbench.BaseNodeUI", { "border-radius": "4px" }); - this.subscribeToFilterGroup("workbench"); - const captionBar = this.getChildControl("captionbar"); captionBar.set({ cursor: "move", From d8eff20ce01eb89585c1197227d3acc9620c2589 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 10:05:48 +0200 Subject: [PATCH 27/63] more progress --- .../class/osparc/workbench/Annotation.js | 14 +++++--- .../class/osparc/workbench/ConversationUI.js | 36 +++++++++++++++++++ .../class/osparc/workbench/WorkbenchUI.js | 6 +--- 3 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js 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 eed69b2a0610..ae0c26732c70 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -101,7 +101,7 @@ qx.Class.define("osparc.workbench.Annotation", { members: { __svgLayer: null, - __drawAnnotation: async function(attrs) { + __drawAnnotation: function(attrs) { if (this.__svgLayer === null) { return; } @@ -124,7 +124,13 @@ qx.Class.define("osparc.workbench.Annotation", { break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; - representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, text, "#00FF00", 12); + const conversationData = { + conversationId: attrs.conversationId, + title: attrs.text || text, + } + representation = new osparc.workbench.ConversationUI(conversationData); + // OM: Add it to the svgLayer or something + representation.moveTo(attrs.x, attrs.y); representation.isSVG = false; break; } @@ -241,9 +247,7 @@ qx.Class.define("osparc.workbench.Annotation", { type, attributes: this.getAttributes(), } - if (type !== this.self().TYPES.CONVERSATION) { - data.color = this.getColor(); - } + data.color = this.getColor(); return data; } } diff --git a/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js b/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js new file mode 100644 index 000000000000..f2b97c078deb --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js @@ -0,0 +1,36 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2025 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + + +qx.Class.define("osparc.workbench.ConversationUI", { + extend: osparc.workbench.BaseNodeUI, + + construct: function(conversationData) { + this.base(arguments); + + this.__conversationData = conversationData; + + const captionTitle = this.getChildControl("title"); + captionTitle.set({ + value: conversationData.title || this.tr("Conversation"), + }); + }, + + members: { + __conversationData: null, + }, +}); 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 5406ad67ebf0..386b5e743369 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1976,16 +1976,12 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { break; } case annotationTypes.CONVERSATION: { - const annotation = this.__addAnnotation(serializeData); const conversationTitle = `${initPos.x}, ${initPos.y}`; osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) .then(conversationData => { serializeData.attributes.conversationId = conversationData["conversationId"]; + this.__addAnnotation(serializeData); osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); - }) - .catch(() => { - // remove annotation if conversation creation fails - this.__removeAnnotation(annotation.getId()); }); break; } From acd592a8d5f4a048fab396cf858b8d15e71b43c2 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 30 Jun 2025 10:32:14 +0200 Subject: [PATCH 28/63] drawAnnotationConversation --- .../class/osparc/workbench/Annotation.js | 10 +--- .../class/osparc/workbench/ConversationUI.js | 36 ------------ .../class/osparc/workbench/SvgWidget.js | 4 ++ .../client/source/class/osparc/wrapper/Svg.js | 55 +++++++++++++++++++ 4 files changed, 61 insertions(+), 44 deletions(-) delete mode 100644 services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js 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 ae0c26732c70..ef0e4741919a 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -124,14 +124,8 @@ qx.Class.define("osparc.workbench.Annotation", { break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; - const conversationData = { - conversationId: attrs.conversationId, - title: attrs.text || text, - } - representation = new osparc.workbench.ConversationUI(conversationData); - // OM: Add it to the svgLayer or something - representation.moveTo(attrs.x, attrs.y); - representation.isSVG = false; + representation = this.__svgLayer.drawAnnotationConversation(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); + representation.isSVG = true; break; } } diff --git a/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js b/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js deleted file mode 100644 index f2b97c078deb..000000000000 --- a/services/static-webserver/client/source/class/osparc/workbench/ConversationUI.js +++ /dev/null @@ -1,36 +0,0 @@ -/* ************************************************************************ - - osparc - the simcore frontend - - https://osparc.io - - Copyright: - 2025 IT'IS Foundation, https://itis.swiss - - License: - MIT: https://opensource.org/licenses/MIT - - Authors: - * Odei Maiz (odeimaiz) - -************************************************************************ */ - - -qx.Class.define("osparc.workbench.ConversationUI", { - extend: osparc.workbench.BaseNodeUI, - - construct: function(conversationData) { - this.base(arguments); - - this.__conversationData = conversationData; - - const captionTitle = this.getChildControl("title"); - captionTitle.set({ - value: conversationData.title || this.tr("Conversation"), - }); - }, - - members: { - __conversationData: null, - }, -}); diff --git a/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js b/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js index ba8af4fc2f67..48a39f0a15e0 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js +++ b/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js @@ -105,6 +105,10 @@ qx.Class.define("osparc.workbench.SvgWidget", { return osparc.wrapper.Svg.drawAnnotationRect(this.__canvas, width, height, x, y, color); }, + drawAnnotationConversation: function(x, y, color) { + return osparc.wrapper.Svg.drawAnnotationConversation(this.__canvas, x, y, color); + }, + drawDashedRect: function(width, height, x = 0, y = 0) { return osparc.wrapper.Svg.drawDashedRect(this.__canvas, width, height, x, y); }, diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index 7177f74480c7..d6c8c66eaa78 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -274,6 +274,61 @@ qx.Class.define("osparc.wrapper.Svg", { return rect; }, + drawAnnotationConversation: function(draw, x, y, color) { + // Group to keep all elements together + const bubble = draw.group(); + + // Rounded rectangle as the base + const rect = draw.rect(280, 60) + .radius(15) + .fill("none") + .stroke({ + width: 2, + color, + }); + bubble.add(rect); + + // Icon (simple speech bubble using path or text) + const icon = draw.text('💬') + .font({ size: 24 }) + .move(10, 18); + bubble.add(icon); + + // Title text + const title = draw.text('Hello') + .font({ + size: 16, + anchor: 'start' + }) + .move(50, 22); + bubble.add(title); + + // Button (small circle with i or icon) + const button = draw.circle(24) + .fill('#ccc') + .move(250, 18); + const btnText = draw.text('➤') + .font({ + size: 14, + anchor: 'middle', + leading: '1' + }) + .move(250 + 12 - 7, 18 + 12 - 10); // center text in circle + + bubble.add(button); + bubble.add(btnText); + + // Add a click event to the button + button.click(function () { + alert('Popup or conversation panel here!'); + }); + btnText.click(function () { + alert('Popup or conversation panel here!'); + }); + + return bubble; + }, + updateText: function(representation, label) { if (representation.type === "text") { representation.text(label); From cea2448b56149782cee0764f793c2677da11cc18 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 13:54:33 +0200 Subject: [PATCH 29/63] pass conversationId --- .../client/source/class/osparc/study/Conversations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3946b8e813d9..dd760c8fcc02 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -53,7 +53,7 @@ qx.Class.define("osparc.study.Conversations", { }, popUpInWindow: function(studyData, openConversationId = null) { - const conversations = new osparc.study.Conversations(studyData); + const conversations = new osparc.study.Conversations(studyData, openConversationId); const title = qx.locale.Manager.tr("Conversations"); const viewWidth = 600; const viewHeight = 700; From 0480b49fa385c26717b75577cb1a4166e1307cc1 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 14:17:38 +0200 Subject: [PATCH 30/63] prettify conversation --- .../client/source/class/osparc/wrapper/Svg.js | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index d6c8c66eaa78..b395ca323c4f 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -274,55 +274,53 @@ qx.Class.define("osparc.wrapper.Svg", { return rect; }, - drawAnnotationConversation: function(draw, x, y, color) { + drawAnnotationConversation: function(draw, x, y) { + const color = qx.theme.manager.Color.getInstance().getTheme().colors["text"]; + const bubbleWidth = 150; + const bubbleHeight = 30; + const padding = 6; + // Group to keep all elements together const bubble = draw.group(); + bubble.move(x, y); // Rounded rectangle as the base - const rect = draw.rect(280, 60) - .radius(15) + const rect = draw.rect(bubbleWidth, bubbleHeight) + .radius(4) .fill("none") .stroke({ - width: 2, color, + width: 1.5, }); bubble.add(rect); // Icon (simple speech bubble using path or text) + const iconSize = 16; const icon = draw.text('💬') - .font({ size: 24 }) - .move(10, 18); + .font({ + size: iconSize + }) + .move(padding, (bubbleHeight - iconSize) / 2) + .attr({ + cursor: "pointer" + }); bubble.add(icon); // Title text + const titleFontSize = 12; + const defaultFont = osparc.utils.Utils.getDefaultFont(); const title = draw.text('Hello') .font({ - size: 16, + fill: color, + size: titleFontSize, + family: defaultFont["family"], anchor: 'start' }) - .move(50, 22); + .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); bubble.add(title); - // Button (small circle with i or icon) - const button = draw.circle(24) - .fill('#ccc') - .move(250, 18); - const btnText = draw.text('➤') - .font({ - size: 14, - anchor: 'middle', - leading: '1' - }) - .move(250 + 12 - 7, 18 + 12 - 10); // center text in circle - - bubble.add(button); - bubble.add(btnText); - // Add a click event to the button - button.click(function () { - alert('Popup or conversation panel here!'); - }); - btnText.click(function () { + icon.click(() => { alert('Popup or conversation panel here!'); }); From d54549ba24138e87e9b0d53f4a2ddee0a64c6264 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 14:19:06 +0200 Subject: [PATCH 31/63] correctly placed --- .../client/source/class/osparc/workbench/Annotation.js | 2 +- .../static-webserver/client/source/class/osparc/wrapper/Svg.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 ef0e4741919a..9b1ac1e6f0a8 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -124,7 +124,7 @@ qx.Class.define("osparc.workbench.Annotation", { break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; - representation = this.__svgLayer.drawAnnotationConversation(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); + representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, text); representation.isSVG = true; break; } diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index b395ca323c4f..b48b318c416f 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -274,7 +274,7 @@ qx.Class.define("osparc.wrapper.Svg", { return rect; }, - drawAnnotationConversation: function(draw, x, y) { + drawAnnotationConversation: function(draw, x = 50, y = 50) { const color = qx.theme.manager.Color.getInstance().getTheme().colors["text"]; const bubbleWidth = 150; const bubbleHeight = 30; From 49a011f1c08471d2c0a51740f5c7130cf1aa3d7d Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 14:26:39 +0200 Subject: [PATCH 32/63] simpler --- .../class/osparc/workbench/Annotation.js | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) 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 9b1ac1e6f0a8..37a5e2af64d6 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -111,41 +111,29 @@ qx.Class.define("osparc.workbench.Annotation", { case this.self().TYPES.NOTE: { const user = osparc.store.Groups.getInstance().getUserByGroupId(attrs.recipientGid); representation = this.__svgLayer.drawAnnotationNote(attrs.x, attrs.y, user ? user.getLabel() : "", attrs.text); - representation.isSVG = true; break; } case this.self().TYPES.RECT: representation = this.__svgLayer.drawAnnotationRect(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); - representation.isSVG = true; break; case this.self().TYPES.TEXT: representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); - representation.isSVG = true; break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, text); - representation.isSVG = true; break; } } if (representation) { - if (representation.isSVG) { - osparc.wrapper.Svg.makeDraggable(representation); - representation.node.addEventListener("click", e => { - this.fireDataEvent("annotationClicked", e.ctrlKey); - e.stopPropagation(); - }, this); - representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); - representation.on("dragmove", () => this.fireEvent("annotationMoving")); - representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); - } else { - representation.addListener("tap", e => { - this.fireDataEvent("annotationClicked", e.ctrlKey); - e.stopPropagation(); - }, this); - // OM: handle drag events for non-SVG representations - } + osparc.wrapper.Svg.makeDraggable(representation); + representation.node.addEventListener("click", e => { + this.fireDataEvent("annotationClicked", e.ctrlKey); + e.stopPropagation(); + }, this); + representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); + representation.on("dragmove", () => this.fireEvent("annotationMoving")); + representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); this.setRepresentation(representation); } }, From d1b13533fd64b27412f89534f82805e121efcb16 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 14:28:36 +0200 Subject: [PATCH 33/63] less --- .../client/source/class/osparc/workbench/Annotation.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) 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 37a5e2af64d6..bf5ac27986e5 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -224,13 +224,11 @@ qx.Class.define("osparc.workbench.Annotation", { }, serialize: function() { - const type = this.getType(); - const data = { - type, + return { + type: this.getType(), attributes: this.getAttributes(), - } - data.color = this.getColor(); - return data; + color: this.getColor(), + }; } } }); From 60140589cc49702decf6c2926a2dff5e1c857f66 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 14:37:14 +0200 Subject: [PATCH 34/63] propagate --- .../client/source/class/osparc/workbench/Annotation.js | 2 +- .../client/source/class/osparc/workbench/WorkbenchUI.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 bf5ac27986e5..80e92838c26f 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -121,7 +121,7 @@ qx.Class.define("osparc.workbench.Annotation", { break; case this.self().TYPES.CONVERSATION: { const text = `${attrs.x}, ${attrs.y}`; - representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, text); + representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.title); break; } } 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 386b5e743369..4ad4bbeb0218 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1977,9 +1977,10 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } case annotationTypes.CONVERSATION: { const conversationTitle = `${initPos.x}, ${initPos.y}`; - osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.PROJECT_ANNOTATION) + osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.TYPES.PROJECT_ANNOTATION) .then(conversationData => { serializeData.attributes.conversationId = conversationData["conversationId"]; + serializeData.attributes.title = conversationData["name"]; this.__addAnnotation(serializeData); osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); }); From 53894dc89e71d786abe5ac4228488e352659c3ff Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:08:01 +0200 Subject: [PATCH 35/63] defaults --- .../client/source/class/osparc/workbench/SvgWidget.js | 4 ++-- .../client/source/class/osparc/wrapper/Svg.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js b/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js index 48a39f0a15e0..b99cb59cd6fa 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js +++ b/services/static-webserver/client/source/class/osparc/workbench/SvgWidget.js @@ -105,8 +105,8 @@ qx.Class.define("osparc.workbench.SvgWidget", { return osparc.wrapper.Svg.drawAnnotationRect(this.__canvas, width, height, x, y, color); }, - drawAnnotationConversation: function(x, y, color) { - return osparc.wrapper.Svg.drawAnnotationConversation(this.__canvas, x, y, color); + drawAnnotationConversation: function(x, y, title) { + return osparc.wrapper.Svg.drawAnnotationConversation(this.__canvas, x, y, title); }, drawDashedRect: function(width, height, x = 0, y = 0) { diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index b48b318c416f..e3125b6f9b8d 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -274,7 +274,7 @@ qx.Class.define("osparc.wrapper.Svg", { return rect; }, - drawAnnotationConversation: function(draw, x = 50, y = 50) { + drawAnnotationConversation: function(draw, x = 50, y = 50, title = "Conversation") { const color = qx.theme.manager.Color.getInstance().getTheme().colors["text"]; const bubbleWidth = 150; const bubbleHeight = 30; @@ -309,7 +309,7 @@ qx.Class.define("osparc.wrapper.Svg", { // Title text const titleFontSize = 12; const defaultFont = osparc.utils.Utils.getDefaultFont(); - const title = draw.text('Hello') + const title = draw.text(title) .font({ fill: color, size: titleFontSize, From 7e692fc225596a916172fc133ad64fac914873ef Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:14:05 +0200 Subject: [PATCH 36/63] minor --- .../client/source/class/osparc/workbench/WorkbenchUI.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) 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 4ad4bbeb0218..a7c1af04ad18 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1185,11 +1185,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { const initData = studyUI.getAnnotationsInitData(); const annotations = initData ? initData : studyUI.getAnnotations(); Object.entries(annotations).forEach(([annotationId, annotation]) => { - if (annotation instanceof osparc.workbench.Annotation) { - this.__addAnnotation(annotation.serialize(), annotationId); - } else { - this.__addAnnotation(annotation, annotationId); - } + const annotationData = annotation instanceof osparc.workbench.Annotation ? annotation.serialize() : annotation; + this.__addAnnotation(annotationData, annotationId); }); if (initData) { studyUI.nullAnnotationsInitData(); @@ -1997,7 +1994,6 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__addAnnotationListeners(annotation); this.__annotations[annotation.getId()] = annotation; this.getStudy().getUi().addAnnotation(annotation); - return annotation; }, __removeAnnotation: function(id) { From d2fb93bf5651f91253328d0c12cd8f0a4cf0b2b8 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:23:09 +0200 Subject: [PATCH 37/63] minor --- .../src/models_library/api_schemas_webserver/projects_ui.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py index 94b8371e3880..28dde4d9b98e 100644 --- a/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py +++ b/packages/models-library/src/models_library/api_schemas_webserver/projects_ui.py @@ -74,9 +74,10 @@ def _update_json_schema_extra(schema: JsonDict) -> None: { "type": "conversation", "attributes": { + "conversationId": 2, "x": 415, "y": 100, - "conversationId": 2, + "title": "My chat", }, }, ] @@ -180,9 +181,10 @@ def _update_json_schema_extra(schema: JsonDict) -> None: "cf94f068-259c-4192-89f9-b2a56d51249d": { "type": "conversation", "attributes": { + "conversationId": 2, "x": 119, "y": 223, - "conversation": 2, + "title": "My chat", }, }, }, From c625191d870cca94c839adb335a871f5ff5131f4 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:39:41 +0200 Subject: [PATCH 38/63] open conversations on click --- .../class/osparc/study/Conversations.js | 4 +-- .../class/osparc/workbench/Annotation.js | 1 - .../class/osparc/workbench/WorkbenchUI.js | 34 +++++++++++++------ .../client/source/class/osparc/wrapper/Svg.js | 5 --- 4 files changed, 26 insertions(+), 18 deletions(-) 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 dd760c8fcc02..89764cf0ab77 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -261,8 +261,8 @@ qx.Class.define("osparc.study.Conversations", { osparc.data.Resources.fetch("conversations", "getConversationsPage", params) .then(conversations => { if (conversations.length) { - // Sort conversations by created date, newest first - conversations.sort((a, b) => new Date(b["created"]) - new Date(a["created"])); + // Sort conversations by created date, oldest first (the new ones will be next to the plus button) + conversations.sort((a, b) => new Date(a["created"]) - new Date(b["created"])); conversations.forEach(conversation => this.__addConversationPage(conversation)); if (this.__openConversationId) { const conversationsLayout = this.getChildControl("conversations-layout"); 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 80e92838c26f..99cc51f86126 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -120,7 +120,6 @@ qx.Class.define("osparc.workbench.Annotation", { representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; case this.self().TYPES.CONVERSATION: { - const text = `${attrs.x}, ${attrs.y}`; representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.title); break; } 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 a7c1af04ad18..311b9ccacfb0 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1211,16 +1211,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { edge.setSelected(true); } else if (this.__isSelectedItemAnAnnotation()) { const annotation = this.__getAnnotation(newID); - this.__setSelectedAnnotations([annotation]); - const annotationEditor = this.__getAnnotationEditorView(); - annotationEditor.setAnnotation(annotation); - annotationEditor.makeItModal(); - annotationEditor.addListener("deleteAnnotation", () => { - annotationEditor.exclude(); - this.__removeAnnotation(annotation.getId()); - this.resetSelection(); - }, this); - annotation.addListener("changeColor", e => this.__annotationLastColor = e.getData()); + this.__annotationSelected(annotation); } else { this.fireDataEvent("changeSelectedNode", newID); } @@ -1242,6 +1233,29 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { return this.__isSelectedItemAnAnnotation() ? this.__annotations[this.__selectedItemId] : null; }, + __annotationSelected: function(annotation) { + this.__setSelectedAnnotations([annotation]); + switch (annotation.getType()) { + case osparc.workbench.Annotation.TYPES.CONVERSATION: { + const studyData = this.getStudy().serialize(); + osparc.study.Conversations.popUpInWindow(studyData, annotation.getAttributes()["conversationId"]); + break; + } + default: { + const annotationEditor = this.__getAnnotationEditorView(); + annotationEditor.setAnnotation(annotation); + annotationEditor.makeItModal(); + annotationEditor.addListener("deleteAnnotation", () => { + annotationEditor.exclude(); + this.__removeAnnotation(annotation.getId()); + this.resetSelection(); + }, this); + annotation.addListener("changeColor", e => this.__annotationLastColor = e.getData()); + break; + } + } + }, + __scaleCoordinates: function(x, y) { return { x: parseInt(x / this.getScale()), diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index e3125b6f9b8d..10504ebc3675 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -319,11 +319,6 @@ qx.Class.define("osparc.wrapper.Svg", { .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); bubble.add(title); - // Add a click event to the button - icon.click(() => { - alert('Popup or conversation panel here!'); - }); - return bubble; }, From 75a054af01da57e54ff95707f0127098934bbb6f Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:44:15 +0200 Subject: [PATCH 39/63] fix --- .../client/source/class/osparc/wrapper/Svg.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index 10504ebc3675..dd24066a39d0 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -309,7 +309,7 @@ qx.Class.define("osparc.wrapper.Svg", { // Title text const titleFontSize = 12; const defaultFont = osparc.utils.Utils.getDefaultFont(); - const title = draw.text(title) + const label = draw.text(title) .font({ fill: color, size: titleFontSize, @@ -317,7 +317,7 @@ qx.Class.define("osparc.wrapper.Svg", { anchor: 'start' }) .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); - bubble.add(title); + bubble.add(label); return bubble; }, From 4020c3a0048d955aa6d9f5ee3174bae6337673ec Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:49:04 +0200 Subject: [PATCH 40/63] truncate text with ellipsis --- .../client/source/class/osparc/wrapper/Svg.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index dd24066a39d0..27f16a1153b8 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -319,6 +319,42 @@ qx.Class.define("osparc.wrapper.Svg", { .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); bubble.add(label); + // Compute available width for text + const availableWidth = bubbleWidth - padding * 2 - iconSize - 8; + + // Helper: truncate text with ellipsis + const fitTextWithEllipsis = (fullText, maxWidth) => { + let text = fullText; + label.text(text); + if (label.bbox().width <= maxWidth) { + return text + }; + + const ellipsis = '…'; + let low = 0; + let high = text.length; + + // Binary search for the max fitting length + while (low < high) { + let mid = Math.floor((low + high) / 2); + label.text(text.slice(0, mid) + ellipsis); + if (label.bbox().width <= maxWidth) { + low = mid + 1; + } else { + high = mid; + } + } + + return text.slice(0, low - 1) + ellipsis; + } + + // Truncate if needed + const fittedText = fitTextWithEllipsis(title, availableWidth); + label.text(fittedText); + + // Move label to proper position + label.move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); + return bubble; }, From 19c984d31c26ebbad444371af60c924cf5d7197f Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 15:50:30 +0200 Subject: [PATCH 41/63] minor --- .../client/source/class/osparc/wrapper/Svg.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index 27f16a1153b8..c003e4584b23 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -333,10 +333,9 @@ qx.Class.define("osparc.wrapper.Svg", { const ellipsis = '…'; let low = 0; let high = text.length; - // Binary search for the max fitting length while (low < high) { - let mid = Math.floor((low + high) / 2); + const mid = Math.floor((low + high) / 2); label.text(text.slice(0, mid) + ellipsis); if (label.bbox().width <= maxWidth) { low = mid + 1; @@ -344,7 +343,6 @@ qx.Class.define("osparc.wrapper.Svg", { high = mid; } } - return text.slice(0, low - 1) + ellipsis; } From 6457169da06e3806907795fdfe2e141168986bac Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Tue, 1 Jul 2025 17:14:07 +0200 Subject: [PATCH 42/63] minor --- .../static-webserver/client/source/class/osparc/wrapper/Svg.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index c003e4584b23..3247ecd2fa12 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -353,6 +353,8 @@ qx.Class.define("osparc.wrapper.Svg", { // Move label to proper position label.move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); + bubble.back(); + return bubble; }, From 682102255859ebba590723c1e596931dafd91a85 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 09:28:33 +0200 Subject: [PATCH 43/63] getRepresentationPosition bubble --- .../class/osparc/workbench/Annotation.js | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) 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 99cc51f86126..69ff9b4f3eaf 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -154,11 +154,25 @@ qx.Class.define("osparc.workbench.Annotation", { getRepresentationPosition: function() { const representation = this.getRepresentation(); if (representation) { - const attrs = osparc.wrapper.Svg.getRectAttributes(representation); - return { - x: parseInt(attrs.x), - y: parseInt(attrs.y) - }; + switch (this.getType()) { + case this.self().TYPES.RECT: + case this.self().TYPES.TEXT: + case this.self().TYPES.NOTE: { + const attrs = osparc.wrapper.Svg.getRectAttributes(representation); + return { + x: parseInt(attrs.x), + y: parseInt(attrs.y), + }; + } + case this.self().TYPES.CONVERSATION: { + const x = representation.transform().x; + const y = representation.transform().y; + return { + x, + y, + }; + } + } } return null; }, From 8799e63139b3d62a57cda7d0dabc8625da96226e Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 09:47:16 +0200 Subject: [PATCH 44/63] move conversations --- .../source/class/osparc/workbench/Annotation.js | 16 ++++++++++++---- .../source/class/osparc/workbench/WorkbenchUI.js | 8 +++++++- .../client/source/class/osparc/wrapper/Svg.js | 7 +++++-- 3 files changed, 24 insertions(+), 7 deletions(-) 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 69ff9b4f3eaf..e984993f79b8 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -125,11 +125,19 @@ qx.Class.define("osparc.workbench.Annotation", { } } if (representation) { + switch (this.getType()) { + case this.self().TYPES.NOTE: + case this.self().TYPES.RECT: + case this.self().TYPES.TEXT: + representation.node.addEventListener("click", e => { + this.fireDataEvent("annotationClicked", e.ctrlKey); + e.stopPropagation(); + }, this); + break; + case this.self().TYPES.CONVERSATION: + break; + } osparc.wrapper.Svg.makeDraggable(representation); - representation.node.addEventListener("click", e => { - this.fireDataEvent("annotationClicked", e.ctrlKey); - e.stopPropagation(); - }, this); representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); representation.on("dragmove", () => this.fireEvent("annotationMoving")); representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); 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 311b9ccacfb0..a933786343fd 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -523,7 +523,13 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { __addAnnotationListeners: function(annotation) { annotation.addListener("annotationStartedMoving", () => { - this.__selectAnnotation(annotation); + if ([ + osparc.workbench.Annotation.TYPES.NOTE, + osparc.workbench.Annotation.TYPES.RECT, + osparc.workbench.Annotation.TYPES.TEXT, + ].includes(annotation.getType())) { + this.__selectAnnotation(annotation); + } this.__itemStartedMoving(); }, this); diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index 3247ecd2fa12..f62f9642dff3 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -300,10 +300,10 @@ qx.Class.define("osparc.wrapper.Svg", { .font({ size: iconSize }) - .move(padding, (bubbleHeight - iconSize) / 2) .attr({ cursor: "pointer" - }); + }) + .move(padding, (bubbleHeight - iconSize) / 2); bubble.add(icon); // Title text @@ -316,6 +316,9 @@ qx.Class.define("osparc.wrapper.Svg", { family: defaultFont["family"], anchor: 'start' }) + .attr({ + cursor: "pointer" + }) .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); bubble.add(label); From 7bebb3c003a7074e047db4a063e1cd04249a4e5b Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 10:03:18 +0200 Subject: [PATCH 45/63] click on conversation working --- .../client/source/class/osparc/workbench/Annotation.js | 5 +++++ .../client/source/class/osparc/wrapper/Svg.js | 2 ++ 2 files changed, 7 insertions(+) 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 e984993f79b8..00b988373f2d 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -135,6 +135,11 @@ qx.Class.define("osparc.workbench.Annotation", { }, this); break; case this.self().TYPES.CONVERSATION: + representation["clickables"].forEach(clickable => { + clickable.click(() => { + this.fireDataEvent("annotationClicked", false); + }, this); + }); break; } osparc.wrapper.Svg.makeDraggable(representation); diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index f62f9642dff3..78aa96589693 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -358,6 +358,8 @@ qx.Class.define("osparc.wrapper.Svg", { bubble.back(); + bubble["clickables"] = [icon, label]; + return bubble; }, From 98a3d79fbe10ba3ff7a658b027356eda477490a6 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 10:17:22 +0200 Subject: [PATCH 46/63] minor --- .../client/source/class/osparc/workbench/Annotation.js | 5 +++++ 1 file changed, 5 insertions(+) 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 00b988373f2d..925dcb4077cb 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -124,7 +124,9 @@ qx.Class.define("osparc.workbench.Annotation", { break; } } + if (representation) { + // handle click events switch (this.getType()) { case this.self().TYPES.NOTE: case this.self().TYPES.RECT: @@ -142,10 +144,13 @@ qx.Class.define("osparc.workbench.Annotation", { }); break; } + + // handle moving events osparc.wrapper.Svg.makeDraggable(representation); representation.on("dragstart", () => this.fireEvent("annotationStartedMoving")); representation.on("dragmove", () => this.fireEvent("annotationMoving")); representation.on("dragend", () => this.fireEvent("annotationStoppedMoving")); + this.setRepresentation(representation); } }, From e963e6b08389292ec9dbca89309d574aaba11355 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 10:30:42 +0200 Subject: [PATCH 47/63] Conversations store --- .../class/osparc/conversation/AddMessage.js | 10 +- .../class/osparc/conversation/Conversation.js | 6 +- .../class/osparc/conversation/MessageUI.js | 2 +- .../class/osparc/store/Conversations.js | 166 ++++++++++++++++++ .../class/osparc/study/Conversations.js | 98 +---------- .../class/osparc/workbench/WorkbenchUI.js | 2 +- 6 files changed, 177 insertions(+), 107 deletions(-) create mode 100644 services/static-webserver/client/source/class/osparc/store/Conversations.js diff --git a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js index ddaba210ed95..d061753b80c1 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js +++ b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js @@ -146,7 +146,7 @@ qx.Class.define("osparc.conversation.AddMessage", { this.__postMessage(); } else { // create new conversation first - osparc.study.Conversations.addConversation(this.__studyData["uuid"]) + osparc.store.Conversations.getInstance().addConversation(this.__studyData["uuid"]) .then(data => { this.__conversationId = data["conversationId"]; this.__postMessage(); @@ -213,7 +213,7 @@ qx.Class.define("osparc.conversation.AddMessage", { this.__postNotify(userGid); } else { // create new conversation first - osparc.study.Conversations.addConversation(this.__studyData["uuid"]) + osparc.store.Conversations.getInstance().addConversation(this.__studyData["uuid"]) .then(data => { this.__conversationId = data["conversationId"]; this.__postNotify(userGid); @@ -225,7 +225,7 @@ qx.Class.define("osparc.conversation.AddMessage", { const commentField = this.getChildControl("comment-field"); const content = commentField.getChildControl("text-area").getValue(); if (content) { - osparc.study.Conversations.addMessage(this.__studyData["uuid"], this.__conversationId, content) + osparc.store.Conversations.getInstance().addMessage(this.__studyData["uuid"], this.__conversationId, content) .then(data => { this.fireDataEvent("messageAdded", data); commentField.getChildControl("text-area").setValue(""); @@ -237,7 +237,7 @@ qx.Class.define("osparc.conversation.AddMessage", { const commentField = this.getChildControl("comment-field"); const content = commentField.getChildControl("text-area").getValue(); if (content) { - osparc.study.Conversations.editMessage(this.__studyData["uuid"], this.__conversationId, this.__message["messageId"], content) + osparc.store.Conversations.getInstance().editMessage(this.__studyData["uuid"], this.__conversationId, this.__message["messageId"], content) .then(data => { this.fireDataEvent("messageUpdated", data); commentField.getChildControl("text-area").setValue(""); @@ -247,7 +247,7 @@ qx.Class.define("osparc.conversation.AddMessage", { __postNotify: function(userGid) { if (userGid) { - osparc.study.Conversations.notifyUser(this.__studyData["uuid"], this.__conversationId, userGid) + osparc.store.Conversations.getInstance().notifyUser(this.__studyData["uuid"], this.__conversationId, userGid) .then(data => { this.fireDataEvent("messageAdded", data); const potentialCollaborators = osparc.store.Groups.getInstance().getPotentialCollaborators(); 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 62d90f54db04..8c71753cfff4 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -90,11 +90,11 @@ qx.Class.define("osparc.conversation.Conversation", { titleEditor.close(); const newLabel = e.getData()["newLabel"]; if (this.getConversationId()) { - osparc.study.Conversations.renameConversation(this.__studyData["uuid"], this.getConversationId(), newLabel) + osparc.store.Conversations.getInstance().renameConversation(this.__studyData["uuid"], this.getConversationId(), newLabel) .then(() => this.renameConversation(newLabel)); } else { // create new conversation first - osparc.study.Conversations.addConversation(this.__studyData["uuid"], newLabel) + osparc.store.Conversations.getInstance().addConversation(this.__studyData["uuid"], newLabel) .then(data => { this.setConversationId(data["conversationId"]); this.getChildControl("button").setLabel(newLabel); @@ -117,7 +117,7 @@ qx.Class.define("osparc.conversation.Conversation", { }); closeButton.addListener("execute", () => { const deleteConversation = () => { - osparc.study.Conversations.deleteConversation(this.__studyData["uuid"], this.getConversationId()) + osparc.store.Conversations.getInstance().deleteConversation(this.__studyData["uuid"], this.getConversationId()) .then(() => this.fireEvent("conversationDeleted")); } if (this.__messagesList.getChildren().length === 0) { diff --git a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js index 399dfad55d72..8d909d84a8f1 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -227,7 +227,7 @@ qx.Class.define("osparc.conversation.MessageUI", { win.open(); win.addListener("close", () => { if (win.getConfirmed()) { - osparc.study.Conversations.deleteMessage(message) + osparc.store.Conversations.getInstance().deleteMessage(message) .then(() => this.fireDataEvent("messageDeleted", message)) .catch(err => osparc.FlashMessenger.logError(err)); } diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js new file mode 100644 index 000000000000..7155b30fd14d --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -0,0 +1,166 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2024 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.store.Conversations", { + extend: qx.core.Object, + type: "singleton", + + construct: function() { + this.base(arguments); + + this.__pricingPlansCached = []; + }, + + members: { + __pricingPlansCached: null, + + addConversation: function(studyId, name = "new 1", type = this.TYPES.PROJECT_STATIC) { + const params = { + url: { + studyId, + }, + data: { + name, + type, + } + }; + return osparc.data.Resources.fetch("conversations", "addConversation", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + deleteConversation: function(studyId, conversationId) { + const params = { + url: { + studyId, + conversationId, + }, + }; + return osparc.data.Resources.fetch("conversations", "deleteConversation", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + renameConversation: function(studyId, conversationId, name) { + const params = { + url: { + studyId, + conversationId, + }, + data: { + name, + } + }; + return osparc.data.Resources.fetch("conversations", "renameConversation", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + addMessage: function(studyId, conversationId, message) { + const params = { + url: { + studyId, + conversationId, + }, + data: { + "content": message, + "type": "MESSAGE", + } + }; + return osparc.data.Resources.fetch("conversations", "addMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + editMessage: function(studyId, conversationId, messageId, message) { + const params = { + url: { + studyId, + conversationId, + messageId, + }, + data: { + "content": message, + }, + }; + return osparc.data.Resources.fetch("conversations", "editMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + deleteMessage: function(message) { + const params = { + url: { + studyId: message["projectId"], + conversationId: message["conversationId"], + messageId: message["messageId"], + }, + }; + return osparc.data.Resources.fetch("conversations", "deleteMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + notifyUser: function(studyId, conversationId, userGroupId) { + const params = { + url: { + studyId, + conversationId, + }, + data: { + "content": userGroupId.toString(), // eventually the backend will accept integers + "type": "NOTIFICATION", + } + }; + return osparc.data.Resources.fetch("conversations", "addMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + + __addToCache: function(pricingPlanData) { + let pricingPlan = this.__pricingPlansCached.find(f => f.getPricingPlanId() === pricingPlanData["pricingPlanId"]); + if (pricingPlan) { + // put + pricingPlan.set({ + pricingPlanKey: pricingPlanData["pricingPlanKey"], + name: pricingPlanData["displayName"], + description: pricingPlanData["description"], + classification: pricingPlanData["classification"], + isActive: pricingPlanData["isActive"], + }); + } else { + // get and post + pricingPlan = new osparc.data.model.PricingPlan(pricingPlanData); + this.__pricingPlansCached.unshift(pricingPlan); + } + return pricingPlan; + }, + + __addPricingUnitToCache: function(pricingPlan, pricingUnitData) { + const pricingUnits = pricingPlan.getPricingUnits(); + let pricingUnit = pricingUnits ? pricingUnits.find(unit => ("getPricingUnitId" in unit) && unit.getPricingUnitId() === pricingUnitData["pricingUnitId"]) : null; + if (pricingUnit) { + const props = Object.keys(qx.util.PropertyUtil.getProperties(osparc.data.model.PricingPlan)); + // put + Object.keys(pricingUnitData).forEach(key => { + if (props.includes(key)) { + pricingPlan.set(key, pricingUnitData[key]); + } + }); + } else { + // get and post + pricingUnit = new osparc.data.model.PricingUnit(pricingUnitData); + pricingPlan.bind("classification", pricingUnit, "classification"); + pricingUnits.push(pricingUnit); + } + return pricingUnit; + }, + } +}); 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 89764cf0ab77..db8f6748d0b6 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -63,102 +63,6 @@ qx.Class.define("osparc.study.Conversations", { }, this); return win; }, - - addConversation: function(studyId, name = "new 1", type = this.TYPES.PROJECT_STATIC) { - const params = { - url: { - studyId, - }, - data: { - name, - type, - } - }; - return osparc.data.Resources.fetch("conversations", "addConversation", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - deleteConversation: function(studyId, conversationId) { - const params = { - url: { - studyId, - conversationId, - }, - }; - return osparc.data.Resources.fetch("conversations", "deleteConversation", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - renameConversation: function(studyId, conversationId, name) { - const params = { - url: { - studyId, - conversationId, - }, - data: { - name, - } - }; - return osparc.data.Resources.fetch("conversations", "renameConversation", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - addMessage: function(studyId, conversationId, message) { - const params = { - url: { - studyId, - conversationId, - }, - data: { - "content": message, - "type": "MESSAGE", - } - }; - return osparc.data.Resources.fetch("conversations", "addMessage", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - editMessage: function(studyId, conversationId, messageId, message) { - const params = { - url: { - studyId, - conversationId, - messageId, - }, - data: { - "content": message, - }, - }; - return osparc.data.Resources.fetch("conversations", "editMessage", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - deleteMessage: function(message) { - const params = { - url: { - studyId: message["projectId"], - conversationId: message["conversationId"], - messageId: message["messageId"], - }, - }; - return osparc.data.Resources.fetch("conversations", "deleteMessage", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, - - notifyUser: function(studyId, conversationId, userGroupId) { - const params = { - url: { - studyId, - conversationId, - }, - data: { - "content": userGroupId.toString(), // eventually the backend will accept integers - "type": "NOTIFICATION", - } - }; - return osparc.data.Resources.fetch("conversations", "addMessage", params) - .catch(err => osparc.FlashMessenger.logError(err)); - }, }, members: { @@ -335,7 +239,7 @@ qx.Class.define("osparc.study.Conversations", { enabled: osparc.data.model.Study.canIWrite(studyData["accessRights"]), }); newConversationButton.addListener("execute", () => { - osparc.study.Conversations.addConversation(studyData["uuid"], "new " + (this.__conversations.length + 1)) + osparc.store.Conversations.getInstance().addConversation(studyData["uuid"], "new " + (this.__conversations.length + 1)) .then(conversationDt => { this.__addConversationPage(conversationDt); const newConversationPage = this.__getConversation(conversationDt["conversationId"]); 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 a933786343fd..d7cec6c5008b 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1994,7 +1994,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } case annotationTypes.CONVERSATION: { const conversationTitle = `${initPos.x}, ${initPos.y}`; - osparc.study.Conversations.addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.TYPES.PROJECT_ANNOTATION) + osparc.store.Conversations.getInstance().addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.TYPES.PROJECT_ANNOTATION) .then(conversationData => { serializeData.attributes.conversationId = conversationData["conversationId"]; serializeData.attributes.title = conversationData["name"]; From 965339939a967886f0a3fc4c9cd9abc969c27154 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 10:31:24 +0200 Subject: [PATCH 48/63] minor --- .../client/source/class/osparc/data/Resources.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index 6d69b0a04562..dd957b312281 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -310,7 +310,7 @@ qx.Class.define("osparc.data.Resources", { } }, "conversations": { - useCache: false, + useCache: false, // It has its own cache handler endpoints: { addConversation: { method: "POST", From 45b1e2748f79769ab46428b0d319cffcbb726ea8 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Wed, 2 Jul 2025 16:06:33 +0200 Subject: [PATCH 49/63] getConversations to store --- .../class/osparc/store/Conversations.js | 25 +++++++++++++++++-- .../class/osparc/study/Conversations.js | 12 +-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index 7155b30fd14d..cd856b0b3d69 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -22,11 +22,31 @@ qx.Class.define("osparc.store.Conversations", { construct: function() { this.base(arguments); - this.__pricingPlansCached = []; + this.__projectConversations = {}; }, members: { - __pricingPlansCached: null, + __projectConversations: null, + + getConversations: function(studyId) { + const params = { + url: { + studyId, + offset: 0, + limit: 42, + } + }; + return osparc.data.Resources.fetch("conversations", "getConversationsPage", params) + .then(conversations => { + if (conversations.length) { + // Sort conversations by created date, oldest first (the new ones will be next to the plus button) + conversations.sort((a, b) => new Date(a["created"]) - new Date(b["created"])); + } + // OM add to cache + return conversations; + }) + .catch(err => osparc.FlashMessenger.logError(err)); + }, addConversation: function(studyId, name = "new 1", type = this.TYPES.PROJECT_STATIC) { const params = { @@ -39,6 +59,7 @@ qx.Class.define("osparc.store.Conversations", { } }; return osparc.data.Resources.fetch("conversations", "addConversation", params) + .then .catch(err => osparc.FlashMessenger.logError(err)); }, 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 db8f6748d0b6..ef0d681ea3e5 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -155,18 +155,9 @@ qx.Class.define("osparc.study.Conversations", { const loadMoreButton = this.getChildControl("loading-button"); loadMoreButton.setFetching(true); - const params = { - url: { - studyId: studyData["uuid"], - offset: 0, - limit: 42, - } - }; - osparc.data.Resources.fetch("conversations", "getConversationsPage", params) + osparc.store.Conversations.getInstance().getConversations(studyData["uuid"]) .then(conversations => { if (conversations.length) { - // Sort conversations by created date, oldest first (the new ones will be next to the plus button) - conversations.sort((a, b) => new Date(a["created"]) - new Date(b["created"])); conversations.forEach(conversation => this.__addConversationPage(conversation)); if (this.__openConversationId) { const conversationsLayout = this.getChildControl("conversations-layout"); @@ -180,7 +171,6 @@ qx.Class.define("osparc.study.Conversations", { this.__addTempConversationPage(); } }) - .catch(err => osparc.FlashMessenger.logError(err)) .finally(() => { loadMoreButton.setFetching(false); loadMoreButton.exclude(); From 3d49266abf3d3465a29c629d9ef92ecf23096b19 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:21:11 +0200 Subject: [PATCH 50/63] Renaming working --- .../class/osparc/store/Conversations.js | 16 +++++++++++++- .../class/osparc/workbench/Annotation.js | 22 ++++++++++++++----- .../class/osparc/workbench/WorkbenchUI.js | 2 +- .../client/source/class/osparc/wrapper/Svg.js | 10 ++++++--- 4 files changed, 39 insertions(+), 11 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index cd856b0b3d69..fbea434ce371 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -25,6 +25,10 @@ qx.Class.define("osparc.store.Conversations", { this.__projectConversations = {}; }, + events: { + "conversationUpdated": "qx.event.type.Data", + }, + members: { __projectConversations: null, @@ -59,7 +63,10 @@ qx.Class.define("osparc.store.Conversations", { } }; return osparc.data.Resources.fetch("conversations", "addConversation", params) - .then + .then(conversation => { + // OM add to cache + return conversation; + }) .catch(err => osparc.FlashMessenger.logError(err)); }, @@ -85,6 +92,13 @@ qx.Class.define("osparc.store.Conversations", { } }; return osparc.data.Resources.fetch("conversations", "renameConversation", params) + .then(() => { + this.fireDataEvent("conversationUpdated", { + studyId, + conversationId, + name, + }); + }) .catch(err => osparc.FlashMessenger.logError(err)); }, 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 925dcb4077cb..15285f0fee0a 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -39,9 +39,9 @@ qx.Class.define("osparc.workbench.Annotation", { } this.set({ id, - type: data.type, color, - attributes: data.attributes + attributes: data.attributes, + type: data.type, }); }, @@ -69,7 +69,8 @@ qx.Class.define("osparc.workbench.Annotation", { "text", // osparc.workbench.Annotation.TYPES.TEXT "conversation", // osparc.workbench.Annotation.TYPES.CONVERSATION ], - nullable: false + nullable: false, + apply: "__drawAnnotation" }, color: { @@ -83,7 +84,6 @@ qx.Class.define("osparc.workbench.Annotation", { attributes: { check: "Object", nullable: false, - apply: "__drawAnnotation" }, representation: { @@ -101,11 +101,12 @@ qx.Class.define("osparc.workbench.Annotation", { members: { __svgLayer: null, - __drawAnnotation: function(attrs) { + __drawAnnotation: function() { if (this.__svgLayer === null) { return; } + const attrs = this.getAttributes(); let representation = null; switch (this.getType()) { case this.self().TYPES.NOTE: { @@ -120,7 +121,16 @@ qx.Class.define("osparc.workbench.Annotation", { representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; case this.self().TYPES.CONVERSATION: { - representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.title); + representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.text); + const conversationId = attrs.conversationId; + if (conversationId) { + osparc.store.Conversations.getInstance().addListener("conversationUpdated", e => { + const data = e.getData(); + if (data.conversationId === conversationId) { + this.setText(data.name); + } + }, this); + } break; } } 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 d7cec6c5008b..175430f20391 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1997,7 +1997,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { osparc.store.Conversations.getInstance().addConversation(this.getStudy().getUuid(), conversationTitle, osparc.study.Conversations.TYPES.PROJECT_ANNOTATION) .then(conversationData => { serializeData.attributes.conversationId = conversationData["conversationId"]; - serializeData.attributes.title = conversationData["name"]; + serializeData.attributes.text = conversationData["name"]; this.__addAnnotation(serializeData); osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); }); diff --git a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js index 78aa96589693..0cecafe73440 100644 --- a/services/static-webserver/client/source/class/osparc/wrapper/Svg.js +++ b/services/static-webserver/client/source/class/osparc/wrapper/Svg.js @@ -321,6 +321,7 @@ qx.Class.define("osparc.wrapper.Svg", { }) .move(padding + iconSize + 8, ((bubbleHeight - titleFontSize) / 2) - 3); bubble.add(label); + bubble.label = label; // store reference for renaming // Compute available width for text const availableWidth = bubbleWidth - padding * 2 - iconSize - 8; @@ -363,12 +364,15 @@ qx.Class.define("osparc.wrapper.Svg", { return bubble; }, - updateText: function(representation, label) { + updateText: function(representation, newText) { if (representation.type === "text") { - representation.text(label); + representation.text(newText); } else if (representation.type === "svg") { // nested - representation["textChild"].innerText = label; + representation["textChild"].innerText = newText; + } else if (representation.type === "g") { + // group + representation.label.text(newText); } }, From f8a904c955d40764b303420a59b2c7ba8250dd23 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:24:17 +0200 Subject: [PATCH 51/63] conversationDeleted --- .../client/source/class/osparc/store/Conversations.js | 11 +++++++++-- .../source/class/osparc/workbench/Annotation.js | 8 +++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index fbea434ce371..2dbf491fa308 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -26,7 +26,8 @@ qx.Class.define("osparc.store.Conversations", { }, events: { - "conversationUpdated": "qx.event.type.Data", + "conversationRenamed": "qx.event.type.Data", + "conversationDeleted": "qx.event.type.Data", }, members: { @@ -78,6 +79,12 @@ qx.Class.define("osparc.store.Conversations", { }, }; return osparc.data.Resources.fetch("conversations", "deleteConversation", params) + .then(() => { + this.fireDataEvent("conversationDeleted", { + studyId, + conversationId, + }) + }) .catch(err => osparc.FlashMessenger.logError(err)); }, @@ -93,7 +100,7 @@ qx.Class.define("osparc.store.Conversations", { }; return osparc.data.Resources.fetch("conversations", "renameConversation", params) .then(() => { - this.fireDataEvent("conversationUpdated", { + this.fireDataEvent("conversationRenamed", { studyId, conversationId, name, 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 15285f0fee0a..5e533bd37507 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -124,12 +124,18 @@ qx.Class.define("osparc.workbench.Annotation", { representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.text); const conversationId = attrs.conversationId; if (conversationId) { - osparc.store.Conversations.getInstance().addListener("conversationUpdated", e => { + osparc.store.Conversations.getInstance().addListener("conversationRenamed", e => { const data = e.getData(); if (data.conversationId === conversationId) { this.setText(data.name); } }, this); + osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { + const data = e.getData(); + if (data.conversationId === conversationId) { + osparc.wrapper.Svg.removeItem(representation); + } + }, this); } break; } From 642232f63ed94ef669dd788eb69bcd768d8d8a5d Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:25:29 +0200 Subject: [PATCH 52/63] no caching --- .../source/class/osparc/store/Conversations.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index 2dbf491fa308..8f1fa7d26081 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -19,20 +19,12 @@ qx.Class.define("osparc.store.Conversations", { extend: qx.core.Object, type: "singleton", - construct: function() { - this.base(arguments); - - this.__projectConversations = {}; - }, - events: { "conversationRenamed": "qx.event.type.Data", "conversationDeleted": "qx.event.type.Data", }, members: { - __projectConversations: null, - getConversations: function(studyId) { const params = { url: { @@ -47,7 +39,6 @@ qx.Class.define("osparc.store.Conversations", { // Sort conversations by created date, oldest first (the new ones will be next to the plus button) conversations.sort((a, b) => new Date(a["created"]) - new Date(b["created"])); } - // OM add to cache return conversations; }) .catch(err => osparc.FlashMessenger.logError(err)); @@ -64,10 +55,6 @@ qx.Class.define("osparc.store.Conversations", { } }; return osparc.data.Resources.fetch("conversations", "addConversation", params) - .then(conversation => { - // OM add to cache - return conversation; - }) .catch(err => osparc.FlashMessenger.logError(err)); }, From a8c5ee6af33021bc641959caa13ec15b1edcfe24 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:27:11 +0200 Subject: [PATCH 53/63] minor --- .../client/source/class/osparc/store/Conversations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index 8f1fa7d26081..3f945dc06bfc 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -44,7 +44,7 @@ qx.Class.define("osparc.store.Conversations", { .catch(err => osparc.FlashMessenger.logError(err)); }, - addConversation: function(studyId, name = "new 1", type = this.TYPES.PROJECT_STATIC) { + addConversation: function(studyId, name = "new 1", type = osparc.study.Conversations.TYPES.PROJECT_STATIC) { const params = { url: { studyId, From cce8c8ba606c8566d5d744eef7cd29de0be2da9e Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:34:33 +0200 Subject: [PATCH 54/63] removeAnnotation --- .../client/source/class/osparc/workbench/Annotation.js | 6 ------ .../client/source/class/osparc/workbench/WorkbenchUI.js | 9 +++++++++ 2 files changed, 9 insertions(+), 6 deletions(-) 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 5e533bd37507..267123fe934b 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -130,12 +130,6 @@ qx.Class.define("osparc.workbench.Annotation", { this.setText(data.name); } }, this); - osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { - const data = e.getData(); - if (data.conversationId === conversationId) { - osparc.wrapper.Svg.removeItem(representation); - } - }, this); } break; } 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 175430f20391..3924087b5084 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -2014,6 +2014,15 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__addAnnotationListeners(annotation); this.__annotations[annotation.getId()] = annotation; this.getStudy().getUi().addAnnotation(annotation); + + if (annotation.getType() === osparc.workbench.Annotation.TYPES.CONVERSATION) { + osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { + const data = e.getData(); + if (data.getAttributes()["conversationId"] === conversationId) { + this.__removeAnnotation(annotation.getId()); + } + }, this); + } }, __removeAnnotation: function(id) { From af3dc50ddbc710642b41b981907ab45a023c5a3c Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 11:40:40 +0200 Subject: [PATCH 55/63] conversationDeleted --- .../client/source/class/osparc/workbench/Annotation.js | 2 +- .../client/source/class/osparc/workbench/WorkbenchUI.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 267123fe934b..ed7bc654f33d 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -126,7 +126,7 @@ qx.Class.define("osparc.workbench.Annotation", { if (conversationId) { osparc.store.Conversations.getInstance().addListener("conversationRenamed", e => { const data = e.getData(); - if (data.conversationId === conversationId) { + if (conversationId === data["conversationId"]) { this.setText(data.name); } }, this); 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 3924087b5084..4e04a1450606 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -2018,7 +2018,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { if (annotation.getType() === osparc.workbench.Annotation.TYPES.CONVERSATION) { osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { const data = e.getData(); - if (data.getAttributes()["conversationId"] === conversationId) { + if (annotation.getAttributes()["conversationId"] === data["conversationId"]) { this.__removeAnnotation(annotation.getId()); } }, this); From 14b79541d06e83095fa431049f09184a76437cfc Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 12:31:28 +0200 Subject: [PATCH 56/63] Rely on Store --- .../source/class/osparc/conversation/Conversation.js | 8 ++------ .../client/source/class/osparc/study/Conversations.js | 7 ++++++- 2 files changed, 8 insertions(+), 7 deletions(-) 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 8c71753cfff4..743f9b12ad5b 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -116,12 +116,8 @@ qx.Class.define("osparc.conversation.Conversation", { visibility: osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]) ? "visible" : "excluded", }); closeButton.addListener("execute", () => { - const deleteConversation = () => { - osparc.store.Conversations.getInstance().deleteConversation(this.__studyData["uuid"], this.getConversationId()) - .then(() => this.fireEvent("conversationDeleted")); - } if (this.__messagesList.getChildren().length === 0) { - deleteConversation(); + osparc.store.Conversations.getInstance().deleteConversation(this.__studyData["uuid"], this.getConversationId()); } else { const msg = this.tr("Are you sure you want to delete the conversation?"); const confirmationWin = new osparc.ui.window.Confirmation(msg).set({ @@ -132,7 +128,7 @@ qx.Class.define("osparc.conversation.Conversation", { confirmationWin.open(); confirmationWin.addListener("close", () => { if (confirmationWin.getConfirmed()) { - deleteConversation(); + osparc.store.Conversations.getInstance().deleteConversation(this.__studyData["uuid"], this.getConversationId()); } }, this); } 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 ef0d681ea3e5..e8620cd7b87a 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -184,7 +184,12 @@ qx.Class.define("osparc.study.Conversations", { const conversationId = conversationData["conversationId"]; conversationPage = new osparc.conversation.Conversation(studyData, conversationId); conversationPage.setLabel(conversationData["name"]); - conversationPage.addListener("conversationDeleted", () => this.__removeConversationPage(conversationData, true)); + osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { + const data = e.getData(); + if (conversationId === data["conversationId"]) { + this.__removeConversationPage(conversationData, true); + } + }); } else { // create a temporary conversation conversationPage = new osparc.conversation.Conversation(studyData); From f8c6b865d5a2b28cd6c7222fdf8e13a455b959b2 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 13:17:41 +0200 Subject: [PATCH 57/63] minor --- .../client/source/class/osparc/study/Conversations.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 e8620cd7b87a..e70a62133c1c 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -109,7 +109,7 @@ qx.Class.define("osparc.study.Conversations", { this.__updateConversationName(conversation); break; case "conversation:deleted": - this.__removeConversationPage(conversation); + this.__removeConversationPage(conversation["conversationId"]); break; } } @@ -187,7 +187,7 @@ qx.Class.define("osparc.study.Conversations", { osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { const data = e.getData(); if (conversationId === data["conversationId"]) { - this.__removeConversationPage(conversationData, true); + this.__removeConversationPage(conversationId, true); } }); } else { @@ -250,8 +250,7 @@ qx.Class.define("osparc.study.Conversations", { conversationsLayout.getChildControl("bar").add(this.__newConversationButton); }, - __removeConversationPage: function(conversationData, changeSelection = false) { - const conversationId = conversationData["conversationId"]; + __removeConversationPage: function(conversationId, changeSelection = false) { const conversation = this.__getConversation(conversationId); if (conversation) { const conversationsLayout = this.getChildControl("conversations-layout"); From 23e74b9dab9202889a6b6b02fec1b73ecfbdfc4d Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 13:45:59 +0200 Subject: [PATCH 58/63] minor --- .../client/source/class/osparc/data/model/Study.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 f95c17a80493..1a0ab260ef91 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 @@ -70,8 +70,8 @@ qx.Class.define("osparc.data.model.Study", { this.setWorkbench(workbench); workbench.setStudy(this); - const workbenchUi = new osparc.data.model.StudyUI(studyData.ui); - this.setUi(workbenchUi); + const studyUI = new osparc.data.model.StudyUI(studyData.ui); + this.setUi(studyUI); this.getWorkbench().buildWorkbench(); }, From 400a13c556d50f2e46b6b047d7d58f094f917973 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 13:47:23 +0200 Subject: [PATCH 59/63] refactor --- .../class/osparc/workbench/Annotation.js | 48 +++++++++++-------- .../class/osparc/workbench/WorkbenchUI.js | 5 +- 2 files changed, 32 insertions(+), 21 deletions(-) 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 ed7bc654f33d..746e5d176dd0 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/Annotation.js +++ b/services/static-webserver/client/source/class/osparc/workbench/Annotation.js @@ -19,17 +19,12 @@ qx.Class.define("osparc.workbench.Annotation", { extend: qx.core.Object, /** - * @param svgLayer {Object} SVG canvas * @param data {Object} data containing type, color, attributes and (optional) id * @param id {String} data */ - construct: function(svgLayer, data, id) { + construct: function(data, id) { this.base(); - if (svgLayer) { - this.__svgLayer = svgLayer; - } - if (id === undefined) { id = osparc.utils.Utils.uuidV4(); } @@ -70,7 +65,6 @@ qx.Class.define("osparc.workbench.Annotation", { "conversation", // osparc.workbench.Annotation.TYPES.CONVERSATION ], nullable: false, - apply: "__drawAnnotation" }, color: { @@ -86,9 +80,15 @@ qx.Class.define("osparc.workbench.Annotation", { nullable: false, }, + svgCanvas: { + init: null, + nullable: false, + apply: "__drawAnnotation", + }, + representation: { init: null - } + }, }, events: { @@ -99,10 +99,8 @@ qx.Class.define("osparc.workbench.Annotation", { }, members: { - __svgLayer: null, - - __drawAnnotation: function() { - if (this.__svgLayer === null) { + __drawAnnotation: function(svgLayer) { + if (svgLayer === null) { return; } @@ -111,17 +109,17 @@ qx.Class.define("osparc.workbench.Annotation", { switch (this.getType()) { case this.self().TYPES.NOTE: { const user = osparc.store.Groups.getInstance().getUserByGroupId(attrs.recipientGid); - representation = this.__svgLayer.drawAnnotationNote(attrs.x, attrs.y, user ? user.getLabel() : "", attrs.text); + representation = svgLayer.drawAnnotationNote(attrs.x, attrs.y, user ? user.getLabel() : "", attrs.text); break; } case this.self().TYPES.RECT: - representation = this.__svgLayer.drawAnnotationRect(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); + representation = svgLayer.drawAnnotationRect(attrs.width, attrs.height, attrs.x, attrs.y, this.getColor()); break; case this.self().TYPES.TEXT: - representation = this.__svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); + representation = svgLayer.drawAnnotationText(attrs.x, attrs.y, attrs.text, this.getColor(), attrs.fontSize); break; case this.self().TYPES.CONVERSATION: { - representation = this.__svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.text); + representation = svgLayer.drawAnnotationConversation(attrs.x, attrs.y, attrs.text); const conversationId = attrs.conversationId; if (conversationId) { osparc.store.Conversations.getInstance().addListener("conversationRenamed", e => { @@ -244,6 +242,11 @@ qx.Class.define("osparc.workbench.Annotation", { }, setSelected: function(selected) { + const svgCanvas = this.getSvgCanvas(); + if (svgCanvas === null) { + return; + }; + const representation = this.getRepresentation(); if (representation) { switch (this.getType()) { @@ -251,7 +254,7 @@ qx.Class.define("osparc.workbench.Annotation", { case this.self().TYPES.TEXT: { if (selected) { if (!("bBox" in representation.node)) { - const bBox = this.__svgLayer.drawBoundingBox(this); + const bBox = svgCanvas.drawBoundingBox(this); representation.node["bBox"] = bBox; } } else if ("bBox" in representation.node) { @@ -265,11 +268,18 @@ qx.Class.define("osparc.workbench.Annotation", { }, serialize: function() { - return { + const serializeData = { type: this.getType(), attributes: this.getAttributes(), - color: this.getColor(), }; + 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 4e04a1450606..760d6f36a691 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1960,7 +1960,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { break; } case annotationTypes.TEXT: { - const tempAnnotation = new osparc.workbench.Annotation(null, { + const tempAnnotation = new osparc.workbench.Annotation({ type: annotationTypes.TEXT, color, attributes: { @@ -2010,7 +2010,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }, __addAnnotation: function(data, id) { - const annotation = new osparc.workbench.Annotation(this.__svgLayer, data, id); + const annotation = new osparc.workbench.Annotation(data, id); + annotation.setSvgCanvas(this.__svgLayer); this.__addAnnotationListeners(annotation); this.__annotations[annotation.getId()] = annotation; this.getStudy().getUi().addAnnotation(annotation); From cc6f50570ada5ddc70a31f221f87f09177b0f5c5 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 14:01:43 +0200 Subject: [PATCH 60/63] more refactoring! --- .../source/class/osparc/data/model/StudyUI.js | 15 ++++-------- .../class/osparc/workbench/WorkbenchUI.js | 23 ++++++++++--------- 2 files changed, 16 insertions(+), 22 deletions(-) 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 7bf1d260e76f..812dc4a1e62b 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 @@ -38,7 +38,10 @@ qx.Class.define("osparc.data.model.StudyUI", { }); if ("annotations" in studyDataUI) { - this.__annotationsInitData = studyDataUI["annotations"]; + Object.entries(studyDataUI["annotations"]).forEach(([annotationId, annotationData]) => { + const annotation = new osparc.workbench.Annotation(annotationData, annotationId); + this.addAnnotation(annotation); + }); } }, @@ -99,22 +102,12 @@ qx.Class.define("osparc.data.model.StudyUI", { }, members: { - __annotationsInitData: null, - __applyMode: function(mode) { if (mode === "guided") { this.setMode("app"); } }, - getAnnotationsInitData: function() { - return this.__annotationsInitData; - }, - - nullAnnotationsInitData: function() { - this.__annotationsInitData = null; - }, - addAnnotation: function(annotation) { this.getAnnotations()[annotation.getId()] = annotation; }, 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 760d6f36a691..d36130d8eadc 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1188,15 +1188,10 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { }, __renderAnnotations: function(studyUI) { - const initData = studyUI.getAnnotationsInitData(); - const annotations = initData ? initData : studyUI.getAnnotations(); - Object.entries(annotations).forEach(([annotationId, annotation]) => { - const annotationData = annotation instanceof osparc.workbench.Annotation ? annotation.serialize() : annotation; - this.__addAnnotation(annotationData, annotationId); + const annotations = studyUI.getAnnotations(); + Object.values(annotations).forEach(annotation => { + this.__renderAnnotation(annotation); }); - if (initData) { - studyUI.nullAnnotationsInitData(); - } }, __setSelectedItem: function(newID) { @@ -2009,12 +2004,18 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__toolHint.setValue(null); }, - __addAnnotation: function(data, id) { - const annotation = new osparc.workbench.Annotation(data, id); + __addAnnotation: function(annotationData, id) { + const annotation = new osparc.workbench.Annotation(annotationData, id); + this.getStudy().getUi().addAnnotation(annotation); + + this.__renderAnnotation(annotation); + }, + + __renderAnnotation: function(annotation) { annotation.setSvgCanvas(this.__svgLayer); + this.__addAnnotationListeners(annotation); this.__annotations[annotation.getId()] = annotation; - this.getStudy().getUi().addAnnotation(annotation); if (annotation.getType() === osparc.workbench.Annotation.TYPES.CONVERSATION) { osparc.store.Conversations.getInstance().addListener("conversationDeleted", e => { From 6283e3463adc18f45b05a9da73e7ac177f8a6131 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 14:38:16 +0200 Subject: [PATCH 61/63] not needed --- .../client/source/class/osparc/conversation/Conversation.js | 4 ---- 1 file changed, 4 deletions(-) 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 743f9b12ad5b..d29bf773c1c6 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -59,10 +59,6 @@ qx.Class.define("osparc.conversation.Conversation", { }, }, - events: { - "conversationDeleted": "qx.event.type.Event", - }, - members: { __studyData: null, __messages: null, From 2c1c051a6e4d38252b8faaf03ed263cab6c87b33 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 15:12:41 +0200 Subject: [PATCH 62/63] refactor --- .../client/source/class/osparc/store/Conversations.js | 11 +++++++++++ .../source/class/osparc/workbench/WorkbenchUI.js | 9 ++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index 3f945dc06bfc..8143d2bde053 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -44,6 +44,17 @@ qx.Class.define("osparc.store.Conversations", { .catch(err => osparc.FlashMessenger.logError(err)); }, + getConversation: function(studyId, conversationId) { + const params = { + url: { + studyId, + conversationId, + } + }; + return osparc.data.Resources.fetch("conversations", "getConversation", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + addConversation: function(studyId, name = "new 1", type = osparc.study.Conversations.TYPES.PROJECT_STATIC) { const params = { url: { 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 d36130d8eadc..b0fc9924b77e 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1238,8 +1238,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__setSelectedAnnotations([annotation]); switch (annotation.getType()) { case osparc.workbench.Annotation.TYPES.CONVERSATION: { - const studyData = this.getStudy().serialize(); - osparc.study.Conversations.popUpInWindow(studyData, annotation.getAttributes()["conversationId"]); + this.__popUpConversation(annotation.getAttributes()["conversationId"]); break; } default: { @@ -1994,7 +1993,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { serializeData.attributes.conversationId = conversationData["conversationId"]; serializeData.attributes.text = conversationData["name"]; this.__addAnnotation(serializeData); - osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationData["conversationId"]); + this.__popUpConversation(conversationData["conversationId"]); }); break; } @@ -2035,6 +2034,10 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } }, + __popUpConversation: function(conversationId) { + osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationId); + }, + __dropFile: async function(e) { this.__draggingFile(e, false); From 21b900967da66d7ab64bdfadb8a62e4fbf1112a5 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Thu, 3 Jul 2025 15:27:14 +0200 Subject: [PATCH 63/63] Check if conversation still exists, if not, ask to remove annotation --- .../source/class/osparc/data/Resources.js | 4 +++ .../class/osparc/store/Conversations.js | 3 +- .../class/osparc/workbench/WorkbenchUI.js | 28 ++++++++++++++++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/data/Resources.js b/services/static-webserver/client/source/class/osparc/data/Resources.js index dd957b312281..781f672feced 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -320,6 +320,10 @@ qx.Class.define("osparc.data.Resources", { method: "GET", url: statics.API + "/projects/{studyId}/conversations?offset={offset}&limit={limit}" }, + getConversation: { + method: "GET", + url: statics.API + "/projects/{studyId}/conversations/{conversationId}" + }, renameConversation: { method: "PUT", url: statics.API + "/projects/{studyId}/conversations/{conversationId}" diff --git a/services/static-webserver/client/source/class/osparc/store/Conversations.js b/services/static-webserver/client/source/class/osparc/store/Conversations.js index 8143d2bde053..0a75ab2acd88 100644 --- a/services/static-webserver/client/source/class/osparc/store/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/store/Conversations.js @@ -51,8 +51,7 @@ qx.Class.define("osparc.store.Conversations", { conversationId, } }; - return osparc.data.Resources.fetch("conversations", "getConversation", params) - .catch(err => osparc.FlashMessenger.logError(err)); + return osparc.data.Resources.fetch("conversations", "getConversation", params); }, addConversation: function(studyId, name = "new 1", type = osparc.study.Conversations.TYPES.PROJECT_STATIC) { 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 b0fc9924b77e..367f470b1d84 100644 --- a/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js +++ b/services/static-webserver/client/source/class/osparc/workbench/WorkbenchUI.js @@ -1238,7 +1238,7 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.__setSelectedAnnotations([annotation]); switch (annotation.getType()) { case osparc.workbench.Annotation.TYPES.CONVERSATION: { - this.__popUpConversation(annotation.getAttributes()["conversationId"]); + this.__popUpConversation(annotation.getAttributes()["conversationId"], annotation.getId()); break; } default: { @@ -1992,8 +1992,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { .then(conversationData => { serializeData.attributes.conversationId = conversationData["conversationId"]; serializeData.attributes.text = conversationData["name"]; - this.__addAnnotation(serializeData); - this.__popUpConversation(conversationData["conversationId"]); + const annotation = this.__addAnnotation(serializeData); + this.__popUpConversation(conversationData["conversationId"], annotation.getId()); }); break; } @@ -2008,6 +2008,8 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { this.getStudy().getUi().addAnnotation(annotation); this.__renderAnnotation(annotation); + + return annotation; }, __renderAnnotation: function(annotation) { @@ -2034,8 +2036,26 @@ qx.Class.define("osparc.workbench.WorkbenchUI", { } }, - __popUpConversation: function(conversationId) { + __popUpConversation: function(conversationId, annotationId) { osparc.study.Conversations.popUpInWindow(this.getStudy().serialize(), conversationId); + + // Check if conversation still exists, if not, ask to remove annotation + osparc.store.Conversations.getInstance().getConversation(this.getStudy().getUuid(), conversationId) + .catch(err => { + if ("status" in err && err.status === 404) { + const win = new osparc.ui.window.Confirmation(this.tr("Do you want to remove the annotation?")).set({ + caption: this.tr("Conversation not found"), + confirmText: this.tr("Delete"), + confirmAction: "delete", + }); + win.open(); + win.addListener("close", () => { + if (win.getConfirmed()) { + this.__removeAnnotation(annotationId); + } + }); + } + }); }, __dropFile: async function(e) {