Skip to content

Commit 57bf22a

Browse files
authored
🎨 [Frontend] Enh: Show who is collaborating (#8144)
1 parent ba45277 commit 57bf22a

File tree

15 files changed

+244
-162
lines changed

15 files changed

+244
-162
lines changed

services/static-webserver/client/source/class/osparc/dashboard/CardBase.js

Lines changed: 64 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ qx.Class.define("osparc.dashboard.CardBase", {
2424
construct: function() {
2525
this.base(arguments);
2626

27-
if (osparc.utils.DisabledPlugins.isSimultaneousAccessEnabled()) {
27+
if (osparc.utils.DisabledPlugins.isRTCEnabled()) {
2828
// "IN_USE" is not a blocker anymore
2929
const inUseIdx = qx.util.PropertyUtil.getProperties(osparc.dashboard.CardBase).blocked.check.indexOf("IN_USE");
3030
if (inUseIdx > -1) {
@@ -804,34 +804,26 @@ qx.Class.define("osparc.dashboard.CardBase", {
804804
},
805805

806806
__applyState: function(state) {
807-
let projectInUse = false;
808-
if ("shareState" in state && "locked" in state["shareState"]) {
809-
projectInUse = state["shareState"]["locked"];
810-
}
807+
const projectLocked = osparc.study.Utils.state.isProjectLocked(state);
808+
const currentUserGroupIds = osparc.study.Utils.state.getCurrentGroupIds(state);
809+
const pipelineState = osparc.study.Utils.state.getPipelineState(state);
811810

812-
if (osparc.utils.DisabledPlugins.isSimultaneousAccessEnabled()) {
813-
if (projectInUse && state["shareState"]["status"] === "OPENED") {
814-
this.__showWhoIsIn(state["shareState"]["currentUserGroupids"]);
815-
} else {
816-
this.__showWhoIsIn(null);
817-
}
818-
} else {
819-
this.setBlocked(projectInUse ? "IN_USE" : false);
820-
if (projectInUse) {
821-
this.__showBlockedCardFromStatus("IN_USE", state["shareState"]);
822-
}
811+
this.__showCurrentUserGroupIds(currentUserGroupIds);
812+
813+
this.setBlocked(projectLocked ? "IN_USE" : false);
814+
if (projectLocked) {
815+
this.__showBlockedCardFromStatus("IN_USE", state["shareState"]);
823816
}
824817

825-
const pipelineState = ("state" in state) ? state["state"]["value"] : undefined;
826818
if (pipelineState) {
827-
this.__applyPipelineState(state["state"]["value"]);
819+
this.__applyPipelineState(pipelineState);
828820
}
829821
},
830822

831823
__applyDebt: function(debt) {
832824
this.setBlocked(debt ? "IN_DEBT" : false);
833825
if (debt) {
834-
this.__showBlockedCardFromStatus("IN_DEBT", debt);
826+
this.__showBlockedCardFromStatus("IN_DEBT");
835827
}
836828
},
837829

@@ -899,73 +891,70 @@ qx.Class.define("osparc.dashboard.CardBase", {
899891
});
900892
},
901893

902-
__showWhoIsIn: function(whoIsIn) {
903-
let users = [];
904-
if (whoIsIn) {
905-
// replace this once the backend returns a list of group__ids
906-
const allUsers = [
907-
{ name: "Alice", avatar: "https://i.pravatar.cc/150?img=1" },
908-
{ name: "Bob", avatar: "https://i.pravatar.cc/150?img=2" },
909-
{ name: "Charlie", avatar: "https://i.pravatar.cc/150?img=3" },
910-
{ name: "Dana", avatar: "https://i.pravatar.cc/150?img=4" },
911-
{ name: "Eve", avatar: "https://i.pravatar.cc/150?img=5" },
912-
{ name: "Frank", avatar: "https://i.pravatar.cc/150?img=6" },
913-
];
914-
// Random number of users between 1 and 6
915-
const randomCount = Math.floor(Math.random() * 6) + 1;
916-
// Shuffle the array and take the first randomCount users
917-
const shuffled = allUsers.sort(() => 0.5 - Math.random());
918-
users = shuffled.slice(0, randomCount);
919-
}
920-
if (osparc.utils.DisabledPlugins.isSimultaneousAccessEnabled() && this.getResourceType() === "study") {
921-
const avatarGroup = this.getChildControl("avatar-group");
922-
avatarGroup.setUsers(users);
923-
}
894+
__showCurrentUserGroupIds: function(currentUserGroupIds) {
895+
const avatarGroup = this.getChildControl("avatar-group");
896+
avatarGroup.setUserGroupIds(currentUserGroupIds);
924897
},
925898

926-
__showBlockedCardFromStatus: function(reason, moreInfo) {
899+
__showBlockedCardFromStatus: function(reason, shareState) {
927900
switch (reason) {
928901
case "IN_USE":
929-
this.__blockedInUse(moreInfo);
902+
this.__blockedInUse(shareState);
930903
break;
931904
case "IN_DEBT":
932-
this.__blockedInDebt(moreInfo);
905+
this.__blockedInDebt();
933906
break;
934907
}
935908
},
936909

937-
__blockedInUse: function(lockedStatus) {
938-
const status = lockedStatus["status"];
939-
const userGroupIDs = lockedStatus["currentUserGroupids"];
940-
let toolTip = userGroupIDs[0]
941-
// osparc.utils.Utils.firstsUp(userGroupIDs[0]["first_name"] || this.tr("A user"), userGroupIDs[0]["last_name"] || ""); // it will be replaced by "userName"
910+
__blockedInUse: function(shareState) {
911+
const status = shareState["status"];
912+
const currentUserGroupIds = shareState["currentUserGroupids"];
913+
const usersStore = osparc.store.Users.getInstance();
914+
const userPromises = currentUserGroupIds.map(userGroupId => usersStore.getUser(userGroupId));
915+
const usernames = [];
916+
let toolTip = "";
942917
let image = null;
943-
switch (status) {
944-
case "CLOSING":
945-
image = "@FontAwesome5Solid/key/";
946-
toolTip += this.tr(" is closing it...");
947-
break;
948-
case "CLONING":
949-
image = "@FontAwesome5Solid/clone/";
950-
toolTip += this.tr(" is cloning it...");
951-
break;
952-
case "EXPORTING":
953-
image = osparc.task.Export.ICON+"/";
954-
toolTip += this.tr(" is exporting it...");
955-
break;
956-
case "OPENING":
957-
image = "@FontAwesome5Solid/key/";
958-
toolTip += this.tr(" is opening it...");
959-
break;
960-
case "OPENED":
961-
image = "@FontAwesome5Solid/lock/";
962-
toolTip += this.tr(" is using it.");
963-
break;
964-
default:
965-
image = "@FontAwesome5Solid/lock/";
966-
break;
967-
}
968-
this.__showBlockedCard(image, toolTip);
918+
Promise.all(userPromises)
919+
.then(usersResult => {
920+
usersResult.forEach(user => {
921+
usernames.push(user.getUsername());
922+
});
923+
})
924+
.catch(error => {
925+
console.error("Failed to fetch user data for avatars:", error);
926+
})
927+
.finally(() => {
928+
switch (status) {
929+
case "CLOSING":
930+
image = "@FontAwesome5Solid/key/";
931+
toolTip += this.tr("Closing...");
932+
break;
933+
case "CLONING":
934+
image = "@FontAwesome5Solid/clone/";
935+
toolTip += this.tr("Cloning...");
936+
break;
937+
case "EXPORTING":
938+
image = osparc.task.Export.ICON+"/";
939+
toolTip += this.tr("Exporting...");
940+
break;
941+
case "OPENING":
942+
image = "@FontAwesome5Solid/key/";
943+
toolTip += this.tr("Opening...");
944+
break;
945+
case "OPENED":
946+
image = "@FontAwesome5Solid/lock/";
947+
toolTip += this.tr("In use...");
948+
break;
949+
default:
950+
image = "@FontAwesome5Solid/lock/";
951+
break;
952+
}
953+
usernames.forEach(username => {
954+
toolTip += "<br>" + username;
955+
});
956+
this.__showBlockedCard(image, toolTip);
957+
});
969958
},
970959

971960
__blockedInDebt: function() {

services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,9 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
410410

411411
resourcesList.forEach(study => {
412412
const state = study["state"];
413-
if (state && "shareState" in state && state["shareState"]["locked"] && state["shareState"]["status"] === "CLOSING") {
413+
const projectLocked = osparc.study.Utils.state.isProjectLocked(state);
414+
const projectStatus = osparc.study.Utils.state.getProjectStatus(state);
415+
if (projectLocked && projectStatus === "CLOSING") {
414416
// websocket might have already notified that the state was closed.
415417
// But the /projects calls response got after the ws message. Ask again to make sure
416418
const delay = 2000;

services/static-webserver/client/source/class/osparc/data/model/Study.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,8 +551,8 @@ qx.Class.define("osparc.data.model.Study", {
551551
},
552552

553553
isLocked: function() {
554-
if (this.getState() && "shareState" in this.getState()) {
555-
return this.getState()["shareState"]["locked"];
554+
if (this.getState()) {
555+
return osparc.study.Utils.state.isProjectLocked(this.getState());
556556
}
557557
return false;
558558
},

services/static-webserver/client/source/class/osparc/desktop/MainPageHandler.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,15 @@ qx.Class.define("osparc.desktop.MainPageHandler", {
8383
const studyAlias = osparc.product.Utils.getStudyAlias({firstUpperCase: true});
8484
// check if it's locked
8585
let locked = false;
86-
let lockedBy = false;
87-
if ("state" in studyData && "shareState" in studyData["state"]) {
88-
locked = studyData["state"]["shareState"]["locked"];
89-
lockedBy = studyData["state"]["shareState"]["currentUserGroupids"];
86+
let lockedBy = [];
87+
if ("state" in studyData) {
88+
const state = studyData["state"];
89+
locked = osparc.study.Utils.state.isProjectLocked(state);
90+
const currentUserGroupIds = osparc.study.Utils.state.getCurrentGroupIds(state);
91+
lockedBy = currentUserGroupIds.filter(gid => gid !== osparc.store.Groups.getInstance().getMyGroupId());
9092
}
91-
if (locked && lockedBy["user_id"] !== osparc.auth.Data.getInstance().getUserId()) {
92-
const msg = `${studyAlias} ${qx.locale.Manager.tr("is already open by")} ${ // it will be replaced "userName"
93-
"first_name" in lockedBy && lockedBy["first_name"] != null ?
94-
lockedBy["first_name"] :
95-
qx.locale.Manager.tr("another user.")
96-
}`;
93+
if (locked && lockedBy.length) {
94+
const msg = `${studyAlias} ${qx.locale.Manager.tr("is already open by another user.")}`;
9795
throw new Error(msg);
9896
}
9997

services/static-webserver/client/source/class/osparc/desktop/StudyEditor.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -625,17 +625,6 @@ qx.Class.define("osparc.desktop.StudyEditor", {
625625
this.__reloadSnapshotsAndIterations();
626626
}
627627
this.getStudyLogger().info(null, "Pipeline started");
628-
/* If no projectStateUpdated comes in 60 seconds, client must
629-
check state of pipeline and update button accordingly. */
630-
const timer = setTimeout(() => {
631-
osparc.store.Study.getInstance().getStudyState(pipelineId);
632-
}, 60000);
633-
const socket = osparc.wrapper.WebSocket.getInstance();
634-
socket.getSocket().once("projectStateUpdated", ({ "project_uuid": projectUuid }) => {
635-
if (projectUuid === pipelineId) {
636-
clearTimeout(timer);
637-
}
638-
});
639628
}
640629
},
641630

services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ qx.Class.define("osparc.desktop.credits.CreditsIndicatorButton", {
2323

2424
osparc.utils.Utils.setIdToWidget(this, "creditsIndicatorButton");
2525

26-
this.set({
27-
cursor: "pointer",
28-
padding: [3, 8]
29-
});
30-
3126
this.getChildControl("image").set({
3227
width: 24,
3328
height: 24

services/static-webserver/client/source/class/osparc/jobs/JobsButton.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,6 @@ qx.Class.define("osparc.jobs.JobsButton", {
2626
osparc.utils.Utils.setIdToWidget(this, "jobsButton");
2727

2828
this.set({
29-
width: 30,
30-
alignX: "center",
31-
cursor: "pointer",
3229
toolTipText: this.tr("Activity Center"),
3330
});
3431

@@ -53,12 +50,12 @@ qx.Class.define("osparc.jobs.JobsButton", {
5350
switch (id) {
5451
case "icon": {
5552
control = new qx.ui.basic.Image("@FontAwesome5Solid/tasks/22");
56-
5753
const logoContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox().set({
5854
alignY: "middle"
59-
}));
55+
})).set({
56+
paddingLeft: 5,
57+
});
6058
logoContainer.add(control);
61-
6259
this._add(logoContainer, {
6360
height: "100%"
6461
});

0 commit comments

Comments
 (0)