diff --git a/services/static-webserver/client/source/class/osparc/theme/Appearance.js b/services/static-webserver/client/source/class/osparc/theme/Appearance.js index 39b9ff80aed6..e89ba3e03d38 100644 --- a/services/static-webserver/client/source/class/osparc/theme/Appearance.js +++ b/services/static-webserver/client/source/class/osparc/theme/Appearance.js @@ -1066,8 +1066,8 @@ qx.Theme.define("osparc.theme.Appearance", { include: "form-button", style: state => ({ decorator: state.hovered || state.focused ? "form-button-danger-hover" : "form-button-danger", - backgroundColor: state.hovered || state.focused ? "default-button-hover-background" : "error", - textColor: "black", + backgroundColor: state.hovered || state.focused || state.disabled ? "default-button-hover-background" : "error", + textColor: state.disabled ? "text": "black", }) }, diff --git a/services/static-webserver/client/source/class/osparc/ui/basic/UserThumbnail.js b/services/static-webserver/client/source/class/osparc/ui/basic/UserThumbnail.js index a9e0e4cb15aa..b323cb8a867d 100644 --- a/services/static-webserver/client/source/class/osparc/ui/basic/UserThumbnail.js +++ b/services/static-webserver/client/source/class/osparc/ui/basic/UserThumbnail.js @@ -49,9 +49,7 @@ qx.Class.define("osparc.ui.basic.UserThumbnail", { __openUserDetails: function() { if (this.getUser()) { - const userDetails = new osparc.user.UserDetails(this.getUser().getGroupId()); - userDetails.center(); - userDetails.open(); + osparc.user.UserAccountWindow.openWindow(this.getUser().getGroupId()); } }, } diff --git a/services/static-webserver/client/source/class/osparc/user/UserAccount.js b/services/static-webserver/client/source/class/osparc/user/UserAccount.js new file mode 100644 index 000000000000..7b2bd228d4a8 --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/user/UserAccount.js @@ -0,0 +1,127 @@ +/* ************************************************************************ + + 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.user.UserAccount", { + extend: osparc.ui.window.TabbedView, + + construct: function(userGroupId) { + this.base(arguments); + + this.set({ + padding: 10, + }); + + this.getChildControl("thumbnail"); + const profilePage = this.getChildControl("profile-page"); + const extras = this.getChildControl("extras-page"); + this.bind("user", profilePage, "user"); + this.bind("extras", extras, "extras"); + + this.setUserGroupId(userGroupId); + }, + + properties: { + userGroupId: { + check: "Number", + init: null, + nullable: false, + apply: "__applyUserGroupId", + }, + + user: { + check: "osparc.data.model.User", + init: null, + nullable: false, + event: "changeUser", + }, + + extras: { + check: "Object", + init: null, + nullable: false, + event: "changeExtras", + }, + }, + + events: { + "updateCaption": "qx.event.type.Data", + "closeWindow": "qx.event.type.Event", + }, + + statics: { + THUMBNAIL_SIZE: 90, + }, + + members: { + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "thumbnail": + control = new osparc.ui.basic.Thumbnail(null, this.self().THUMBNAIL_SIZE, this.self().THUMBNAIL_SIZE).set({ + width: this.self().THUMBNAIL_SIZE, + height: this.self().THUMBNAIL_SIZE, + marginBottom: 10, + }); + control.getChildControl("image").set({ + anonymous: true, + decorator: "rounded", + }); + this.addWidgetToTabs(control); + break; + case "profile-page": + control = new osparc.user.UserProfile(); + this.addTab("Profile", "", control); + break; + case "extras-page": + control = new osparc.user.UserExtras(); + this.addTab("Extras", "", control); + break; + } + return control || this.base(arguments, id); + }, + + __applyUserGroupId: function(userGroupId) { + const params = { + url: { + gId: userGroupId + } + }; + osparc.data.Resources.fetch("poUsers", "searchByGroupId", params) + .then(usersData => { + if (usersData.length === 1) { + const userData = usersData[0]; + + const user = new osparc.data.model.User(userData); + user.setContactData(userData); + // remove the displayed properties from the contact info + Object.keys(qx.util.PropertyUtil.getProperties(osparc.data.model.User)).forEach(prop => delete userData[prop]); + const extras = osparc.utils.Utils.convertKeysToTitles(userData); + + this.fireDataEvent("updateCaption", user.getUserName()); + this.getChildControl("thumbnail").setSource(user.createThumbnail(this.self().THUMBNAIL_SIZE)); + this.setUser(user); + this.setExtras(extras); + } + }) + .catch(err => { + osparc.FlashMessenger.logError(err); + console.error(err); + this.fireEvent("closeWindow"); + }); + }, + } +}); diff --git a/services/static-webserver/client/source/class/osparc/user/UserAccountWindow.js b/services/static-webserver/client/source/class/osparc/user/UserAccountWindow.js new file mode 100644 index 000000000000..373286639135 --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/user/UserAccountWindow.js @@ -0,0 +1,46 @@ +/* ************************************************************************ + + 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.user.UserAccountWindow", { + extend: osparc.ui.window.TabbedWindow, + + construct: function(userGroupId) { + this.base(arguments, "user-account-"+userGroupId, this.tr("User Account")); + + this.set({ + width: osparc.user.UserAccountWindow.WIDTH, + height: osparc.user.UserAccountWindow.HEIGHT, + }); + + const userAccount = new osparc.user.UserAccount(userGroupId); + userAccount.addListener("updateCaption", e => this.setCaption(e.getData())); + userAccount.addListener("closeWindow", () => this.close(), this); + this._setTabbedView(userAccount); + }, + + statics: { + WIDTH: 500, + HEIGHT: 500, + + openWindow: function(userGroupId) { + const userAccountWindow = new osparc.user.UserAccountWindow(userGroupId); + userAccountWindow.center(); + userAccountWindow.open(); + return userAccountWindow; + }, + }, +}); diff --git a/services/static-webserver/client/source/class/osparc/user/UserExtras.js b/services/static-webserver/client/source/class/osparc/user/UserExtras.js new file mode 100644 index 000000000000..7b017a8b2373 --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/user/UserExtras.js @@ -0,0 +1,58 @@ +/* ************************************************************************ + + 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.user.UserExtras", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.VBox(10)); + }, + + properties: { + extras: { + check: "Object", + init: null, + nullable: true, + event: "changeExtras", + apply: "__applyExtras", + } + }, + + members: { + __applyExtras: function(extras) { + if (!extras) { + return; + } + + for (const key in extras) { + const value = extras[key]; + if (osparc.utils.Utils.isDateLike(value)) { + extras[key] = osparc.utils.Utils.formatDateAndTime(new Date(value)); + } + } + + const jsonViewer = new osparc.widget.JsonFormatterWidget(extras); + const scroll = new qx.ui.container.Scroll(); + scroll.add(jsonViewer); + this._add(scroll, { + flex: 1 + }); + }, + } +}); diff --git a/services/static-webserver/client/source/class/osparc/user/UserDetails.js b/services/static-webserver/client/source/class/osparc/user/UserProfile.js similarity index 72% rename from services/static-webserver/client/source/class/osparc/user/UserDetails.js rename to services/static-webserver/client/source/class/osparc/user/UserProfile.js index fa1163cb9ff3..3767cd4e1d50 100644 --- a/services/static-webserver/client/source/class/osparc/user/UserDetails.js +++ b/services/static-webserver/client/source/class/osparc/user/UserProfile.js @@ -15,31 +15,16 @@ ************************************************************************ */ -qx.Class.define("osparc.user.UserDetails", { - extend: osparc.ui.window.Window, +qx.Class.define("osparc.user.UserProfile", { + extend: qx.ui.core.Widget, - construct: function(userGroupId) { + construct: function() { this.base(arguments); - this.set({ - layout: new qx.ui.layout.VBox(10), - autoDestroy: true, - showMaximize: false, - showMinimize: false, - clickAwayClose: true, - contentPadding: 10, - width: this.self().WIDTH, - height: this.self().HEIGHT, - }); - - this.setUserGroupId(userGroupId); + this._setLayout(new qx.ui.layout.VBox(10)); }, statics: { - WIDTH: 400, - HEIGHT: 600, - THUMBNAIL_SIZE: 110, - TOP_GRID: { USERNAME: 0, FULLNAME: 1, @@ -60,52 +45,26 @@ qx.Class.define("osparc.user.UserDetails", { }, properties: { - userGroupId: { - check: "Number", - init: null, - nullable: false, - apply: "__applyUserGroupId", - }, - user: { check: "osparc.data.model.User", init: null, - nullable: false, + nullable: true, event: "changeUser", apply: "__applyUser", } }, members: { - __remainingUserData: null, - _createChildControlImpl: function(id) { let control; switch (id) { - case "top-layout": - control = new qx.ui.container.Composite(new qx.ui.layout.HBox(30)); - this.add(control); - break; - case "thumbnail": - control = new osparc.ui.basic.Thumbnail(null, this.self().THUMBNAIL_SIZE, this.self().THUMBNAIL_SIZE).set({ - width: this.self().THUMBNAIL_SIZE, - height: this.self().THUMBNAIL_SIZE, - }); - control.getChildControl("image").set({ - anonymous: true, - decorator: "rounded", - }); - this.getChildControl("top-layout").add(control); - break; case "top-info": { const grid = new qx.ui.layout.Grid(10, 6); grid.setColumnWidth(0, 80); grid.setColumnFlex(1, 1); grid.setColumnAlign(0, "right", "middle"); control = new qx.ui.container.Composite(grid); - this.getChildControl("top-layout").add(control, { - flex: 1 - }); + this._add(control); break; } case "middle-info": { @@ -114,7 +73,7 @@ qx.Class.define("osparc.user.UserDetails", { grid.setColumnFlex(1, 1); grid.setColumnAlign(0, "right", "middle"); control = new qx.ui.container.Composite(grid); - this.add(control); + this._add(control); break; } case "userName": { @@ -259,36 +218,10 @@ qx.Class.define("osparc.user.UserDetails", { return control || this.base(arguments, id); }, - __applyUserGroupId: function(userGroupId) { - const params = { - url: { - gId: userGroupId - } - }; - osparc.data.Resources.fetch("poUsers", "searchByGroupId", params) - .then(usersData => { - if (usersData.length === 1) { - const userData = usersData[0]; - // curate data - userData["groupId"] = userGroupId; - userData["userId"] = -1; // fix this - userData["userName"] = "userName"; // fix this - const user = new osparc.data.model.User(userData); - user.setContactData(userData); - // remove the displayed properties from the contact info - Object.keys(qx.util.PropertyUtil.getProperties(osparc.data.model.User)).forEach(prop => delete userData[prop]); - this.__remainingUserData = osparc.utils.Utils.convertKeysToTitles(userData); - this.setUser(user); - } - }) - .catch(err => { - console.error(err); - this.close(); - }); - }, - __applyUser: function(user) { - this.setCaption(user.getUserName()); + if (!user) { + return; + } // top grid this.getChildControl("userName").setValue(user.getUserName()); @@ -298,7 +231,7 @@ qx.Class.define("osparc.user.UserDetails", { this.getChildControl("user-id").setValue(String(user.getUserId())); this.getChildControl("group-id").setValue(String(user.getGroupId())); - this.getChildControl("thumbnail").setSource(user.createThumbnail(this.self().THUMBNAIL_SIZE)); + // this.getChildControl("thumbnail").setSource(user.createThumbnail(this.self().THUMBNAIL_SIZE)); // middle grid this.getChildControl("institution").setValue(user.getInstitution() || "-"); @@ -307,14 +240,6 @@ qx.Class.define("osparc.user.UserDetails", { this.getChildControl("state").setValue(user.getState() || "-"); this.getChildControl("country").setValue(user.getCountry() || "-"); this.getChildControl("postal-code").setValue(user.getPostalCode() || "-"); - - // remaining data - const jsonViewer = new osparc.widget.JsonFormatterWidget(this.__remainingUserData); - const scroll = new qx.ui.container.Scroll(); - scroll.add(jsonViewer); - this.add(scroll, { - flex: 1 - }); }, } }); diff --git a/services/static-webserver/client/source/class/osparc/utils/Utils.js b/services/static-webserver/client/source/class/osparc/utils/Utils.js index 5d60bb63c84a..be585a044cc7 100644 --- a/services/static-webserver/client/source/class/osparc/utils/Utils.js +++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js @@ -572,6 +572,11 @@ qx.Class.define("osparc.utils.Utils", { return button; }, + isDateLike: function(v) { + if (typeof v === "string") return !isNaN(new Date(v)); + return false; + }, + /** * @param date {Date Object} Date Object */