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..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)); @@ -35,12 +36,14 @@ qx.Class.define("osparc.conversation.AddMessage", { }, events: { - "commentAdded": "qx.event.type.Event" + "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 d61f56200984..ed897b011a2f 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) { @@ -236,7 +238,9 @@ 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; 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 55a5cbec23dc..d5bc94db512d 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); @@ -43,6 +45,11 @@ qx.Class.define("osparc.conversation.MessageUI", { } }, + events: { + "messageEdited": "qx.event.type.Event", + "messageDeleted": "qx.event.type.Event", + }, + members: { __message: null, @@ -109,6 +116,25 @@ qx.Class.define("osparc.conversation.MessageUI", { column: isMyMessage ? 0 : 2, }); break; + case "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 +169,53 @@ qx.Class.define("osparc.conversation.MessageUI", { }); this.getChildControl("spacer"); - } + + if (this.self().isMyMessage(this.__message)) { + 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 addMessage = new osparc.conversation.AddMessage(this.__studyData, this.__message["conversationId"], this.__message); + const title = this.tr("Edit message"); + 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() { + 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()) { + osparc.study.Conversations.deleteMessage(this.__message["studyId"], this.__message["conversationId"], this.__message["messageId"]) + .then(() => this.fireEvent("messageDeleted")) + .catch(err => osparc.FlashMessenger.logError(err)); + } + }); + }, } }); 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..0dc5a8b40c12 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,33 @@ 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, + }, + }; + return osparc.data.Resources.fetch("conversations", "editMessage", params) + .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: {