From b8e95015f00e24805f477428ce0b67cdaf8f96c0 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 13:32:59 +0200 Subject: [PATCH 1/8] edit-options-menu-button --- .../class/osparc/conversation/MessageUI.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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 55a5cbec23dc..9220d9e368f6 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -109,6 +109,25 @@ qx.Class.define("osparc.conversation.MessageUI", { column: isMyMessage ? 0 : 2, }); break; + case "edit-options-menu-button": { + const buttonSize = 22; + control = new qx.ui.form.MenuButton().set({ + width: buttonSize, + height: buttonSize, + allowGrowX: false, + allowGrowY: false, + marginTop: 4, + alignY: "top", + icon: "@FontAwesome5Solid/ellipsis-v/14", + focusable: false + }); + this._add(control, { + row: 0, + column: 3, + rowSpan: 2, + }); + break; + } } return control || this.base(arguments, id); @@ -143,6 +162,10 @@ qx.Class.define("osparc.conversation.MessageUI", { }); this.getChildControl("spacer"); + + if (this.self().isMyMessage(this.__message)) { + this.getChildControl("edit-options-menu-button"); + } } } }); From 7694180e81d9f5309fb2c4e2921aa9976e278ff5 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 13:51:28 +0200 Subject: [PATCH 2/8] deleteMessage --- .../class/osparc/conversation/MessageUI.js | 48 +++++++++++++++++-- .../source/class/osparc/data/Resources.js | 8 ++++ .../class/osparc/study/Conversations.js | 12 +++++ 3 files changed, 65 insertions(+), 3 deletions(-) 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 9220d9e368f6..9718cd905956 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -109,7 +109,7 @@ qx.Class.define("osparc.conversation.MessageUI", { column: isMyMessage ? 0 : 2, }); break; - case "edit-options-menu-button": { + case "menu-button": { const buttonSize = 22; control = new qx.ui.form.MenuButton().set({ width: buttonSize, @@ -164,8 +164,50 @@ qx.Class.define("osparc.conversation.MessageUI", { this.getChildControl("spacer"); if (this.self().isMyMessage(this.__message)) { - this.getChildControl("edit-options-menu-button"); + const menuButton = this.getChildControl("menu-button"); + + const menu = new qx.ui.menu.Menu().set({ + position: "bottom-right", + }); + menuButton.setMenu(menu); + + const editButton = new qx.ui.menu.Button(this.tr("Edit...")); + editButton.addListener("execute", () => this.__editMessage(), this); + menu.add(editButton); + + const deleteButton = new qx.ui.menu.Button(this.tr("Delete...")); + deleteButton.addListener("execute", () => this.__deleteMessage(), this); + menu.add(deleteButton); } - } + }, + + __editMessage: function() { + const messageContent = this.getChildControl("message-content"); + const editDialog = new osparc.ui.dialog.EditMessageDialog(this.__message, messageContent.getValue()); + editDialog.addListener("messageEdited", e => { + messageContent.setValue(e.getData()); + this.fireDataEvent("messageEdited", e.getData()); + }); + editDialog.open(); + }, + + __deleteMessage: function() { + const win = new osparc.ui.window.Confirmation(this.tr("Delete message?")).set({ + caption: this.tr("Delete"), + confirmText: this.tr("Delete"), + confirmAction: "delete", + }); + win.open(); + win.addListener("close", () => { + if (win.getConfirmed()) { + console.log(this.__message); + osparc.study.Conversations.deleteMessage(this.__message["studyId"], this.__message["conversationId"], this.__message["messageId"]) + .then(data => { + this.fireDataEvent("commentAdded", data); + osparc.FlashMessenger.logAs(this.tr("Message deleted"), "INFO"); + }); + } + }); + }, } }); 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 42167faec112..43bfa27e892b 100644 --- a/services/static-webserver/client/source/class/osparc/data/Resources.js +++ b/services/static-webserver/client/source/class/osparc/data/Resources.js @@ -332,6 +332,14 @@ qx.Class.define("osparc.data.Resources", { method: "POST", url: statics.API + "/projects/{studyId}/conversations/{conversationId}/messages" }, + editMessage: { + method: "PUT", + url: statics.API + "/projects/{studyId}/conversations/{conversationId}/messages/{messageId}" + }, + deleteMessage: { + method: "DELETE", + url: statics.API + "/projects/{studyId}/conversations/{conversationId}/messages/{messageId}" + }, getMessagesPage: { method: "GET", url: statics.API + "/projects/{studyId}/conversations/{conversationId}/messages?offset={offset}&limit={limit}" 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 720b00f7c999..879bd2304513 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -94,6 +94,18 @@ qx.Class.define("osparc.study.Conversations", { .catch(err => osparc.FlashMessenger.logError(err)); }, + deleteMessage: function(studyId, conversationId, messageId) { + const params = { + url: { + studyId, + conversationId, + messageId, + }, + }; + return osparc.data.Resources.fetch("conversations", "deleteMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + notifyUser: function(studyId, conversationId, userGroupId) { const params = { url: { From 24dc564b2c258ff1995cdc38d807bc89109d71ae Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 14:08:31 +0200 Subject: [PATCH 3/8] attach studyId --- .../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 d61f56200984..145c3ae1ac06 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -195,6 +195,8 @@ qx.Class.define("osparc.conversation.Conversation", { this.__getNextRequest() .then(resp => { const messages = resp["data"]; + // it's not provided by the backend + messages.forEach(message => message["studyId"] = this.__studyData["uuid"]); this.__addMessages(messages); this.__nextRequestParams = resp["_links"]["next"]; if (this.__nextRequestParams === null) { From f6e25c16c5053c1676d26678d9d1b448b3a4da98 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 14:13:27 +0200 Subject: [PATCH 4/8] delete message --- .../source/class/osparc/conversation/AddMessage.js | 2 +- .../source/class/osparc/conversation/Conversation.js | 2 ++ .../client/source/class/osparc/conversation/MessageUI.js | 9 +++++++-- 3 files changed, 10 insertions(+), 3 deletions(-) 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 7a0cf26f871e..6c4cfaf7896a 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js +++ b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js @@ -35,7 +35,7 @@ qx.Class.define("osparc.conversation.AddMessage", { }, events: { - "commentAdded": "qx.event.type.Event" + "commentAdded": "qx.event.type.Data", }, members: { 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 145c3ae1ac06..108d46061ab5 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -239,6 +239,8 @@ qx.Class.define("osparc.conversation.Conversation", { switch (message["type"]) { case "MESSAGE": control = new osparc.conversation.MessageUI(message); + control.addListener("messageEdited", () => this.fetchMessages()); + control.addListener("messageDeleted", () => this.fetchMessages()); break; case "NOTIFICATION": control = new osparc.conversation.NotificationUI(message); 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 9718cd905956..a4f9ce11093a 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -43,6 +43,11 @@ qx.Class.define("osparc.conversation.MessageUI", { } }, + events: { + "messageEdited": "qx.event.type.Event", + "messageDeleted": "qx.event.type.Event", + }, + members: { __message: null, @@ -202,8 +207,8 @@ qx.Class.define("osparc.conversation.MessageUI", { if (win.getConfirmed()) { console.log(this.__message); osparc.study.Conversations.deleteMessage(this.__message["studyId"], this.__message["conversationId"], this.__message["messageId"]) - .then(data => { - this.fireDataEvent("commentAdded", data); + .then(() => { + this.fireEvent("messageDeleted"); osparc.FlashMessenger.logAs(this.tr("Message deleted"), "INFO"); }); } From c8ed06c1d13039627cfadb983c60aaff33e96769 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 14:58:53 +0200 Subject: [PATCH 5/8] progress on edit message --- .../class/osparc/conversation/AddMessage.js | 41 +++++++++++++++---- .../class/osparc/conversation/Conversation.js | 2 +- .../class/osparc/conversation/MessageUI.js | 22 +++++----- .../class/osparc/study/Conversations.js | 16 ++++++++ 4 files changed, 60 insertions(+), 21 deletions(-) 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 6c4cfaf7896a..0917b472996f 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js +++ b/services/static-webserver/client/source/class/osparc/conversation/AddMessage.js @@ -23,11 +23,12 @@ qx.Class.define("osparc.conversation.AddMessage", { * @param studyData {Object} serialized Study Data * @param conversationId {String} Conversation Id */ - construct: function(studyData, conversationId = null) { + construct: function(studyData, conversationId = null, message = null) { this.base(arguments); this.__studyData = studyData; this.__conversationId = conversationId; + this.__message = message; this._setLayout(new qx.ui.layout.VBox(5)); @@ -36,11 +37,13 @@ qx.Class.define("osparc.conversation.AddMessage", { events: { "commentAdded": "qx.event.type.Data", + "messageEdited": "qx.event.type.Data", }, members: { __studyData: null, __conversationId: null, + __message: null, _createChildControlImpl: function(id) { let control; @@ -120,13 +123,22 @@ qx.Class.define("osparc.conversation.AddMessage", { __buildLayout: function() { this.getChildControl("thumbnail"); - this.getChildControl("comment-field"); + const commentField = this.getChildControl("comment-field"); const addMessageButton = this.getChildControl("add-comment-button"); - addMessageButton.addListener("execute", () => this.__addComment()); + if (this.__message) { + // edit mode + addMessageButton.setLabel(this.tr("Edit message")); + addMessageButton.addListener("execute", () => this.__editComment()); + + commentField.setText(this.__message["content"]); + } else { + // new message + addMessageButton.addListener("execute", () => this.__addComment()); - const notifyUserButton = this.getChildControl("notify-user-button"); - notifyUserButton.addListener("execute", () => this.__notifyUserTapped()); + const notifyUserButton = this.getChildControl("notify-user-button"); + notifyUserButton.addListener("execute", () => this.__notifyUserTapped()); + } }, __addComment: function() { @@ -211,13 +223,24 @@ qx.Class.define("osparc.conversation.AddMessage", { __postMessage: function() { const commentField = this.getChildControl("comment-field"); - const comment = commentField.getChildControl("text-area").getValue(); - if (comment) { - osparc.study.Conversations.addMessage(this.__studyData["uuid"], this.__conversationId, comment) + const content = commentField.getChildControl("text-area").getValue(); + if (content) { + osparc.study.Conversations.addMessage(this.__studyData["uuid"], this.__conversationId, content) .then(data => { this.fireDataEvent("commentAdded", data); commentField.getChildControl("text-area").setValue(""); - osparc.FlashMessenger.logAs(this.tr("Message added"), "INFO"); + }); + } + }, + + __editComment: function() { + 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) + .then(data => { + this.fireDataEvent("messageEdited", data); + commentField.getChildControl("text-area").setValue(""); }); } }, 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 108d46061ab5..ed897b011a2f 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/conversation/Conversation.js @@ -238,7 +238,7 @@ qx.Class.define("osparc.conversation.Conversation", { let control = null; switch (message["type"]) { case "MESSAGE": - control = new osparc.conversation.MessageUI(message); + control = new osparc.conversation.MessageUI(message, this.__studyData); control.addListener("messageEdited", () => this.fetchMessages()); control.addListener("messageDeleted", () => this.fetchMessages()); break; 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 a4f9ce11093a..3219c6b6f246 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -21,11 +21,13 @@ qx.Class.define("osparc.conversation.MessageUI", { /** * @param message {Object} message + * @param studyData {Object?null} serialized Study Data */ - construct: function(message) { + construct: function(message, studyData = null) { this.base(arguments); this.__message = message; + this.__studyData = studyData; const isMyMessage = this.self().isMyMessage(this.__message); const layout = new qx.ui.layout.Grid(12, 4); @@ -187,13 +189,14 @@ qx.Class.define("osparc.conversation.MessageUI", { }, __editMessage: function() { - const messageContent = this.getChildControl("message-content"); - const editDialog = new osparc.ui.dialog.EditMessageDialog(this.__message, messageContent.getValue()); - editDialog.addListener("messageEdited", e => { - messageContent.setValue(e.getData()); - this.fireDataEvent("messageEdited", e.getData()); + const addMessage = new osparc.conversation.AddMessage(this.__studyData, this.__message["conversationId"], this.__message); + addMessage.addListener("messageEdited", () => this.fireDataEvent("messageEdited")); + const title = this.tr("Edit message"); + osparc.ui.window.Window.popUpInWindow(addMessage, title, 550, 135).set({ + clickAwayClose: false, + resizable: true, + showClose: true, }); - editDialog.open(); }, __deleteMessage: function() { @@ -207,10 +210,7 @@ qx.Class.define("osparc.conversation.MessageUI", { if (win.getConfirmed()) { console.log(this.__message); osparc.study.Conversations.deleteMessage(this.__message["studyId"], this.__message["conversationId"], this.__message["messageId"]) - .then(() => { - this.fireEvent("messageDeleted"); - osparc.FlashMessenger.logAs(this.tr("Message deleted"), "INFO"); - }); + .then(() => this.fireEvent("messageDeleted")); } }); }, 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 879bd2304513..a4185ebeac52 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -94,6 +94,22 @@ qx.Class.define("osparc.study.Conversations", { .catch(err => osparc.FlashMessenger.logError(err)); }, + editMessage: function(studyId, conversationId, messageId, message) { + const params = { + url: { + studyId, + conversationId, + messageId, + }, + data: { + "content": message, + "type": "MESSAGE", + }, + }; + return osparc.data.Resources.fetch("conversations", "editMessage", params) + .catch(err => osparc.FlashMessenger.logError(err)); + }, + deleteMessage: function(studyId, conversationId, messageId) { const params = { url: { From fa7971881785f28017b31e4379f9d097d13757f8 Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 15:02:15 +0200 Subject: [PATCH 6/8] minor --- .../client/source/class/osparc/conversation/MessageUI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 3219c6b6f246..e612158db44b 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -192,7 +192,7 @@ qx.Class.define("osparc.conversation.MessageUI", { const addMessage = new osparc.conversation.AddMessage(this.__studyData, this.__message["conversationId"], this.__message); addMessage.addListener("messageEdited", () => this.fireDataEvent("messageEdited")); const title = this.tr("Edit message"); - osparc.ui.window.Window.popUpInWindow(addMessage, title, 550, 135).set({ + osparc.ui.window.Window.popUpInWindow(addMessage, title, 570, 135).set({ clickAwayClose: false, resizable: true, showClose: true, From f8fcea3e3cdc3c58eaa74a16ff2cbe81c70eedcc Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 15:18:50 +0200 Subject: [PATCH 7/8] last touches --- .../client/source/class/osparc/conversation/MessageUI.js | 7 +++++-- .../client/source/class/osparc/study/Conversations.js | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) 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 e612158db44b..a84000c34b9e 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -190,13 +190,16 @@ qx.Class.define("osparc.conversation.MessageUI", { __editMessage: function() { const addMessage = new osparc.conversation.AddMessage(this.__studyData, this.__message["conversationId"], this.__message); - addMessage.addListener("messageEdited", () => this.fireDataEvent("messageEdited")); const title = this.tr("Edit message"); - osparc.ui.window.Window.popUpInWindow(addMessage, title, 570, 135).set({ + const win = osparc.ui.window.Window.popUpInWindow(addMessage, title, 570, 135).set({ clickAwayClose: false, resizable: true, showClose: true, }); + addMessage.addListener("messageEdited", () => { + win.close(); + this.fireDataEvent("messageEdited"); + }); }, __deleteMessage: 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 a4185ebeac52..0dc5a8b40c12 100644 --- a/services/static-webserver/client/source/class/osparc/study/Conversations.js +++ b/services/static-webserver/client/source/class/osparc/study/Conversations.js @@ -103,7 +103,6 @@ qx.Class.define("osparc.study.Conversations", { }, data: { "content": message, - "type": "MESSAGE", }, }; return osparc.data.Resources.fetch("conversations", "editMessage", params) From 6ec4a6df2aed601fcd75c7995635bf5f69a24a4f Mon Sep 17 00:00:00 2001 From: odeimaiz Date: Mon, 23 Jun 2025 16:17:55 +0200 Subject: [PATCH 8/8] minor --- .../client/source/class/osparc/conversation/MessageUI.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a84000c34b9e..d5bc94db512d 100644 --- a/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js +++ b/services/static-webserver/client/source/class/osparc/conversation/MessageUI.js @@ -211,9 +211,9 @@ qx.Class.define("osparc.conversation.MessageUI", { win.open(); win.addListener("close", () => { if (win.getConfirmed()) { - console.log(this.__message); osparc.study.Conversations.deleteMessage(this.__message["studyId"], this.__message["conversationId"], this.__message["messageId"]) - .then(() => this.fireEvent("messageDeleted")); + .then(() => this.fireEvent("messageDeleted")) + .catch(err => osparc.FlashMessenger.logError(err)); } }); },