Skip to content
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6391704
notify-user-button
odeimaiz Jun 17, 2025
c22c488
notifyUser in store
odeimaiz Jun 17, 2025
4574e36
minor
odeimaiz Jun 17, 2025
c90ed7c
Show notification in conversation
odeimaiz Jun 17, 2025
321a9fb
was notified
odeimaiz Jun 17, 2025
42de8d1
bell
odeimaiz Jun 17, 2025
cfc3b95
minor
odeimaiz Jun 17, 2025
85b96d1
pass userGid
odeimaiz Jun 17, 2025
9311ee8
accept only one
odeimaiz Jun 17, 2025
abd1572
minor
odeimaiz Jun 17, 2025
a15bc60
notify works
odeimaiz Jun 17, 2025
049dde1
stack button
odeimaiz Jun 17, 2025
40e63c8
TODOs
odeimaiz Jun 17, 2025
534cbc2
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 18, 2025
d4ef75a
first share project
odeimaiz Jun 18, 2025
873b8e0
minor
odeimaiz Jun 18, 2025
932b218
feedback to user
odeimaiz Jun 18, 2025
338ce59
share study
odeimaiz Jun 18, 2025
f5a9cae
refactor
odeimaiz Jun 18, 2025
172a4eb
refactor
odeimaiz Jun 18, 2025
ea40cc8
minor
odeimaiz Jun 18, 2025
59cc658
improved workflow
odeimaiz Jun 18, 2025
372c55b
renaming
odeimaiz Jun 18, 2025
0ad220d
renaming
odeimaiz Jun 18, 2025
7da1d4c
CONVERSATION_NOTIFICATION
odeimaiz Jun 18, 2025
3271998
minor
odeimaiz Jun 18, 2025
329d3d4
redis notification handling
odeimaiz Jun 18, 2025
98eeca5
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 18, 2025
7ad4728
refactor
odeimaiz Jun 18, 2025
a8f0d57
fixes
odeimaiz Jun 18, 2025
3632a67
remove default
odeimaiz Jun 18, 2025
f94b968
notification ui
odeimaiz Jun 18, 2025
62d695a
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 18, 2025
72f5e42
only make the needed calls
odeimaiz Jun 18, 2025
84597f0
refactor
odeimaiz Jun 18, 2025
d99dac0
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 19, 2025
7482971
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 19, 2025
099551f
rename
odeimaiz Jun 20, 2025
6d03649
conversation folder
odeimaiz Jun 20, 2025
e95c9b9
NotificationUI
odeimaiz Jun 20, 2025
296e40b
aesthetics
odeimaiz Jun 20, 2025
6e96949
scroll messages
odeimaiz Jun 20, 2025
692a6db
last fix
odeimaiz Jun 20, 2025
7c9b5c5
openConversations
odeimaiz Jun 20, 2025
7443e2d
minor
odeimaiz Jun 20, 2025
ff2b2bc
Merge branch 'master' into feature/notify-in-conversations
odeimaiz Jun 20, 2025
1b974e8
not needed
odeimaiz Jun 20, 2025
3affc7f
minor
odeimaiz Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
/* ************************************************************************

osparc - the simcore frontend

https://osparc.io

Copyright:
2023 IT'IS Foundation, https://itis.swiss

License:
MIT: https://opensource.org/licenses/MIT

Authors:
* Odei Maiz (odeimaiz)

************************************************************************ */


qx.Class.define("osparc.conversation.AddMessage", {
extend: qx.ui.core.Widget,

/**
* @param studyData {Object} serialized Study Data
* @param conversationId {String} Conversation Id
*/
construct: function(studyData, conversationId = null) {
this.base(arguments);

this.__studyData = studyData;
this.__conversationId = conversationId;

this._setLayout(new qx.ui.layout.VBox(5));

this.__buildLayout();
},

events: {
"commentAdded": "qx.event.type.Event"
},

members: {
__studyData: null,
__conversationId: null,

_createChildControlImpl: function(id) {
let control;
switch (id) {
case "add-comment-label":
control = new qx.ui.basic.Label().set({
value: this.tr("Add comment")
});
this._add(control);
break;
case "add-comment-layout": {
const grid = new qx.ui.layout.Grid(8, 5);
grid.setColumnWidth(0, 32);
grid.setColumnFlex(1, 1);
control = new qx.ui.container.Composite(grid);
this._add(control, {
flex: 1
});
break;
}
case "thumbnail": {
control = new qx.ui.basic.Image().set({
alignY: "middle",
scale: true,
allowGrowX: true,
allowGrowY: true,
allowShrinkX: true,
allowShrinkY: true,
maxWidth: 32,
maxHeight: 32,
decorator: "rounded",
});
const authData = osparc.auth.Data.getInstance();
const myUsername = authData.getUsername();
const myEmail = authData.getEmail();
control.set({
source: osparc.utils.Avatar.emailToThumbnail(myEmail, myUsername, 32)
});
const layout = this.getChildControl("add-comment-layout");
layout.add(control, {
row: 0,
column: 0
});
break;
}
case "comment-field":
control = new osparc.editor.MarkdownEditor();
control.getChildControl("buttons").exclude();
const layout = this.getChildControl("add-comment-layout");
layout.add(control, {
row: 0,
column: 1
});
break;
case "add-comment-button":
control = new qx.ui.form.Button(this.tr("Add message")).set({
appearance: "form-button",
allowGrowX: false,
alignX: "right"
});
control.setEnabled(osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]));
this._add(control);
break;
case "notify-user-button":
control = new qx.ui.form.Button("🔔 " + this.tr("Notify user")).set({
appearance: "form-button",
allowGrowX: false,
alignX: "right"
});
control.setEnabled(osparc.data.model.Study.canIWrite(this.__studyData["accessRights"]));
this._add(control);
break;
}

return control || this.base(arguments, id);
},

__buildLayout: function() {
this.getChildControl("thumbnail");
this.getChildControl("comment-field");

const addMessageButton = this.getChildControl("add-comment-button");
addMessageButton.addListener("execute", () => this.__addComment());

const notifyUserButton = this.getChildControl("notify-user-button");
notifyUserButton.addListener("execute", () => this.__notifyUserTapped());
},

__addComment: function() {
if (this.__conversationId) {
this.__postMessage();
} else {
// create new conversation first
osparc.study.Conversations.addConversation(this.__studyData["uuid"])
.then(data => {
this.__conversationId = data["conversationId"];
this.__postMessage();
})
}
},

__notifyUserTapped: function() {
const showOrganizations = false;
const showAccessRights = false;
const userManager = new osparc.share.NewCollaboratorsManager(this.__studyData, showOrganizations, showAccessRights).set({
acceptOnlyOne: true,
});
userManager.setCaption(this.tr("Notify user"));
userManager.getActionButton().setLabel(this.tr("Notify"));
userManager.addListener("addCollaborators", e => {
userManager.close();
const data = e.getData();
const userGids = data["selectedGids"];
if (userGids && userGids.length) {
const userGid = parseInt(userGids[0]);
this.__notifyUser(userGid);
}
});
},

__notifyUser: function(userGid) {
// Note!
// This check only works if the project is directly shared with the user.
// If it's shared through a group, it might be a bit confusing
if (userGid in this.__studyData["accessRights"]) {
this.__addNotify(userGid);
} else {
const msg = this.tr("This user has no access to the project. Do you want to share it?");
const win = new osparc.ui.window.Confirmation(msg).set({
caption: this.tr("Share"),
confirmText: this.tr("Share"),
confirmAction: "create"
});
win.center();
win.open();
win.addListener("close", () => {
if (win.getConfirmed()) {
const newCollaborators = {
[userGid]: osparc.data.Roles.STUDY["write"].accessRights
};
osparc.store.Study.addCollaborators(this.__studyData, newCollaborators)
.then(() => {
this.__addNotify(userGid);
const potentialCollaborators = osparc.store.Groups.getInstance().getPotentialCollaborators()
if (userGid in potentialCollaborators && "getUserId" in potentialCollaborators[userGid]) {
const uid = potentialCollaborators[userGid].getUserId();
osparc.notification.Notifications.pushStudyShared(uid, this.__studyData["uuid"]);
}
})
.catch(err => osparc.FlashMessenger.logError(err));
}
}, this);
}
},

__addNotify: function(userGid) {
if (this.__conversationId) {
this.__postNotify(userGid);
} else {
// create new conversation first
osparc.study.Conversations.addConversation(this.__studyData["uuid"])
.then(data => {
this.__conversationId = data["conversationId"];
this.__postNotify(userGid);
});
}
},

__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)
.then(data => {
this.fireDataEvent("commentAdded", data);
commentField.getChildControl("text-area").setValue("");
osparc.FlashMessenger.logAs(this.tr("Message added"), "INFO");
});
}
},

__postNotify: function(userGid) {
if (userGid) {
osparc.study.Conversations.notifyUser(this.__studyData["uuid"], this.__conversationId, userGid)
.then(data => {
this.fireDataEvent("commentAdded", data);
const potentialCollaborators = osparc.store.Groups.getInstance().getPotentialCollaborators();
if (userGid in potentialCollaborators) {
if ("getUserId" in potentialCollaborators[userGid]) {
const uid = potentialCollaborators[userGid].getUserId();
osparc.notification.Notifications.pushConversationNotification(uid, this.__studyData["uuid"]);
}
const msg = "getLabel" in potentialCollaborators[userGid] ? potentialCollaborators[userGid].getLabel() + this.tr(" was notified") : this.tr("Notification sent");
osparc.FlashMessenger.logAs(msg, "INFO");
}
});
}
},
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
************************************************************************ */


qx.Class.define("osparc.info.Conversation", {
qx.Class.define("osparc.conversation.Conversation", {
extend: qx.ui.tabview.Page,

/**
Expand All @@ -32,7 +32,7 @@ qx.Class.define("osparc.info.Conversation", {
this.setConversationId(conversationId);
}

this._setLayout(new qx.ui.layout.VBox(10));
this._setLayout(new qx.ui.layout.VBox(5));

this.set({
padding: 10,
Expand Down Expand Up @@ -152,7 +152,9 @@ qx.Class.define("osparc.info.Conversation", {
this.__messagesList = new qx.ui.container.Composite(new qx.ui.layout.VBox(5)).set({
alignY: "middle"
});
this._add(this.__messagesList, {
const scrollView = new qx.ui.container.Scroll();
scrollView.add(this.__messagesList);
this._add(scrollView, {
flex: 1
});

Expand All @@ -161,7 +163,7 @@ qx.Class.define("osparc.info.Conversation", {
this._add(this.__loadMoreMessages);

if (osparc.data.model.Study.canIWrite(this.__studyData["accessRights"])) {
const addMessages = new osparc.info.CommentAdd(this.__studyData["uuid"], this.getConversationId());
const addMessages = new osparc.conversation.AddMessage(this.__studyData, this.getConversationId());
addMessages.setPaddingLeft(10);
addMessages.addListener("commentAdded", e => {
const data = e.getData();
Expand Down Expand Up @@ -223,15 +225,24 @@ qx.Class.define("osparc.info.Conversation", {
},

__addMessages: function(messages) {
if (messages.length === 1) {
const nMessages = messages.filter(msg => msg["type"] === "MESSAGE").length;
if (nMessages === 1) {
this.__messagesTitle.setValue(this.tr("1 Message"));
} else if (messages.length > 1) {
this.__messagesTitle.setValue(messages.length + this.tr(" Messages"));
} else if (nMessages > 1) {
this.__messagesTitle.setValue(nMessages + this.tr(" Messages"));
}

messages.forEach(message => {
const messageUi = new osparc.info.CommentUI(message);
this.__messagesList.add(messageUi);
let control = null;
switch (message["type"]) {
case "MESSAGE":
control = new osparc.conversation.MessageUI(message);
break;
case "NOTIFICATION":
control = new osparc.conversation.NotificationUI(message);
break;
}
this.__messagesList.add(control);
});
},
}
Expand Down
Loading
Loading