From eb35a48b5cbb1f1840e1582c40c2d38f00dd40ac Mon Sep 17 00:00:00 2001 From: Odei Maiz <33152403+odeimaiz@users.noreply.github.com> Date: Mon, 20 Jan 2025 12:09:44 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20[Frontend]=20Show=20``trashedAt`?= =?UTF-8?q?`=20and=20``trashedBy``=20on=20Bin=20cards=20(#7030)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../source/class/osparc/dashboard/CardBase.js | 48 ++++++-- .../osparc/dashboard/FolderButtonItem.js | 53 +++++++-- .../class/osparc/dashboard/GridButtonBase.js | 11 +- .../class/osparc/dashboard/GridButtonItem.js | 34 +++++- .../class/osparc/dashboard/ListButtonItem.js | 36 +++++- .../osparc/dashboard/WorkspaceButtonBase.js | 2 +- .../osparc/dashboard/WorkspaceButtonItem.js | 58 +++++++--- .../source/class/osparc/data/model/Folder.js | 9 ++ .../source/class/osparc/data/model/Study.js | 8 ++ .../class/osparc/data/model/Workspace.js | 2 + .../source/class/osparc/info/StudyUtils.js | 2 +- .../class/osparc/navigation/NavigationBar.js | 4 +- .../source/class/osparc/ui/basic/DateAndBy.js | 106 ++++++++++++++++++ 13 files changed, 321 insertions(+), 52 deletions(-) create mode 100644 services/static-webserver/client/source/class/osparc/ui/basic/DateAndBy.js diff --git a/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js b/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js index 02794308916..e18ad26b552 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/CardBase.js @@ -151,27 +151,27 @@ qx.Class.define("osparc.dashboard.CardBase", { populateShareIcon: function(shareIcon, accessRights) { const gids = Object.keys(accessRights).map(key => parseInt(key)); - const groupsStore = osparc.store.Groups.getInstance(); - // Icon + const groupsStore = osparc.store.Groups.getInstance(); const groupEveryone = groupsStore.getEveryoneGroup(); const groupProductEveryone = groupsStore.getEveryoneProductGroup(); const organizations = groupsStore.getOrganizations(); + const myGroupId = groupsStore.getMyGroupId(); + const organizationIds = Object.keys(organizations).map(key => parseInt(key)); if (gids.includes(groupEveryone.getGroupId()) || gids.includes(groupProductEveryone.getGroupId())) { shareIcon.setSource(osparc.dashboard.CardBase.SHARED_ALL); } else if (organizationIds.filter(value => gids.includes(value)).length) { // find intersection shareIcon.setSource(osparc.dashboard.CardBase.SHARED_ORGS); - } else if (gids.length === 1) { + } else if (gids.length === 1 && gids[0] === myGroupId) { shareIcon.setSource(osparc.dashboard.CardBase.SHARE_ICON); } else { shareIcon.setSource(osparc.dashboard.CardBase.SHARED_USER); } // Tooltip - const canIWrite = osparc.data.model.Study.canIWrite(accessRights); - const myGroupId = groupsStore.getMyGroupId(); if (gids.length === 0 || (gids.length === 1 && gids[0] === myGroupId)) { + const canIWrite = osparc.data.model.Study.canIWrite(accessRights); if (canIWrite) { shareIcon.set({ toolTipText: qx.locale.Manager.tr("Share") @@ -180,6 +180,16 @@ qx.Class.define("osparc.dashboard.CardBase", { return; } + this.addHintFromGids(shareIcon, gids); + }, + + addHintFromGids: function(icon, gids) { + const groupsStore = osparc.store.Groups.getInstance(); + const groupEveryone = groupsStore.getEveryoneGroup(); + const groupProductEveryone = groupsStore.getEveryoneProductGroup(); + const organizations = groupsStore.getOrganizations(); + const myGroupId = groupsStore.getMyGroupId(); + const sharedGrps = []; const groups = []; groups.push(groupEveryone); @@ -193,8 +203,8 @@ qx.Class.define("osparc.dashboard.CardBase", { } }); - const hint = new osparc.ui.hint.Hint(shareIcon); - shareIcon.addListener("mouseover", async () => { + const hint = new osparc.ui.hint.Hint(icon); + icon.addListener("mouseover", async () => { hint.show(); // lazy load tooltip, this can be an expensive call @@ -230,7 +240,7 @@ qx.Class.define("osparc.dashboard.CardBase", { } } }, this); - shareIcon.addListener("mouseout", () => hint.exclude(), this); + icon.addListener("mouseout", () => hint.exclude(), this); }, }, @@ -308,6 +318,18 @@ qx.Class.define("osparc.dashboard.CardBase", { nullable: true }, + trashedAt: { + check: "Date", + apply: "_applyTrasehdAt", + nullable: true + }, + + trashedBy: { + check: "Number", + apply: "_applyTrashedBy", + nullable: true + }, + classifiers: { check: "Array" }, @@ -457,6 +479,8 @@ qx.Class.define("osparc.dashboard.CardBase", { owner, accessRights: resourceData.accessRights ? resourceData.accessRights : {}, lastChangeDate: resourceData.lastChangeDate ? new Date(resourceData.lastChangeDate) : null, + trashedAt: resourceData.trashedAt ? new Date(resourceData.trashedAt) : null, + trashedBy: resourceData.trashedBy || null, icon: resourceData.thumbnail || this.self().PRODUCT_ICON, state: resourceData.state ? resourceData.state : {}, classifiers: resourceData.classifiers && resourceData.classifiers ? resourceData.classifiers : [], @@ -523,6 +547,14 @@ qx.Class.define("osparc.dashboard.CardBase", { throw new Error("Abstract method called!"); }, + _applyTrasehdAt: function(value, old) { + throw new Error("Abstract method called!"); + }, + + _applyTrashedBy: function(value, old) { + throw new Error("Abstract method called!"); + }, + _applyAccessRights: function(value, old) { throw new Error("Abstract method called!"); }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/FolderButtonItem.js b/services/static-webserver/client/source/class/osparc/dashboard/FolderButtonItem.js index bfbdc147fc5..8631fa112c9 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/FolderButtonItem.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/FolderButtonItem.js @@ -90,6 +90,18 @@ qx.Class.define("osparc.dashboard.FolderButtonItem", { nullable: true, apply: "__applyLastModified" }, + + trashedAt: { + check: "Date", + nullable: true, + apply: "__applyTrashedAt" + }, + + trashedBy: { + check: "Number", + nullable: true, + apply: "__applyTrashedBy" + }, }, members: { @@ -107,16 +119,12 @@ qx.Class.define("osparc.dashboard.FolderButtonItem", { } case "title": control = new qx.ui.basic.Label().set({ - anonymous: true, font: "text-14", }); this._add(control, osparc.dashboard.FolderButtonBase.POS.TITLE); break; - case "last-modified": - control = new qx.ui.basic.Label().set({ - anonymous: true, - font: "text-12", - }); + case "date-by": + control = new osparc.ui.basic.DateAndBy(); this._add(control, osparc.dashboard.FolderButtonBase.POS.SUBTITLE); break; case "menu-button": { @@ -150,6 +158,8 @@ qx.Class.define("osparc.dashboard.FolderButtonItem", { folder.bind("parentFolderId", this, "parentFolderId"); folder.bind("name", this, "title"); folder.bind("lastModified", this, "lastModified"); + folder.bind("trashedAt", this, "trashedAt"); + folder.bind("trashedBy", this, "trashedBy"); osparc.utils.Utils.setIdToWidget(this, "folderItem_" + folder.getFolderId()); @@ -222,15 +232,36 @@ qx.Class.define("osparc.dashboard.FolderButtonItem", { __applyTitle: function(value) { const label = this.getChildControl("title"); - label.setValue(value); - - this.setToolTipText(value); + label.set({ + value, + toolTipText: value, + }); }, __applyLastModified: function(value) { if (value) { - const label = this.getChildControl("last-modified"); - label.setValue(osparc.utils.Utils.formatDateAndTime(value)); + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Last modified"), + }) + } + }, + + __applyTrashedAt: function(value) { + if (value && value.getTime() !== new Date(0).getTime()) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Moved to the bin"), + }); + } + }, + + __applyTrashedBy: function(gid) { + if (gid) { + const dateBy = this.getChildControl("date-by"); + dateBy.setGroupid(gid); } }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js index e1b7c72ff71..ebda818baf0 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js @@ -251,15 +251,8 @@ qx.Class.define("osparc.dashboard.GridButtonBase", { layout.add(control, {flex: 1}); break; } - case "modified-text": - control = new qx.ui.basic.Label().set({ - textColor: "contrasted-text-dark", - alignY: "middle", - rich: true, - anonymous: true, - font: "text-12", - allowGrowY: false - }); + case "date-by": + control = new osparc.ui.basic.DateAndBy(); layout = this.getChildControl("footer"); layout.add(control, this.self().FPOS.MODIFIED); break; diff --git a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js index 003648f7629..13879b4f0a4 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonItem.js @@ -176,9 +176,37 @@ qx.Class.define("osparc.dashboard.GridButtonItem", { // overridden _applyLastChangeDate: function(value, old) { - if (value && (this.isResourceType("study") || this.isResourceType("template"))) { - const label = this.getChildControl("modified-text"); - label.setValue(osparc.utils.Utils.formatDateAndTime(value)); + if (value) { + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Last modified"), + }); + } + } + }, + + // overridden + _applyTrasehdAt: function(value) { + if (value && value.getTime() !== new Date(0).getTime()) { + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Moved to the bin"), + }); + } + } + }, + + // overridden + _applyTrashedBy: function(gid) { + if (gid) { + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.setGroupId(gid); + } } }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js b/services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js index 5a80947d803..049e22f9930 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/ListButtonItem.js @@ -68,9 +68,8 @@ qx.Class.define("osparc.dashboard.ListButtonItem", { column: osparc.dashboard.ListButtonBase.POS.SHARED }); break; - case "last-change": + case "date-text": control = new qx.ui.basic.Label().set({ - anonymous: true, font: "text-13", allowGrowY: false, minWidth: 120, @@ -191,10 +190,39 @@ qx.Class.define("osparc.dashboard.ListButtonItem", { return control || this.base(arguments, id); }, + // overridden _applyLastChangeDate: function(value, old) { if (value) { - const label = this.getChildControl("last-change"); - label.setValue(osparc.utils.Utils.formatDateAndTime(value)); + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Last modified"), + }); + } + } + }, + + // overridden + _applyTrasehdAt: function(value) { + if (value && value.getTime() !== new Date(0).getTime()) { + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Moved to the bin"), + }); + } + } + }, + + // overridden + _applyTrashedBy: function(gid) { + if (gid) { + if (this.isResourceType("study") || this.isResourceType("template")) { + const dateBy = this.getChildControl("date-by"); + dateBy.setGroupId(gid); + } } }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonBase.js b/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonBase.js index a6fb451fc2d..a712666f7fd 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonBase.js @@ -90,7 +90,7 @@ qx.Class.define("osparc.dashboard.WorkspaceButtonBase", { MENU: 2, }, FPOS: { - MODIFIED: 0 + DATE: 0, } }, diff --git a/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonItem.js b/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonItem.js index 7b720ee09f1..e2a5ab98086 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonItem.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/WorkspaceButtonItem.js @@ -91,7 +91,19 @@ qx.Class.define("osparc.dashboard.WorkspaceButtonItem", { check: "Date", nullable: true, apply: "__applyModifiedAt" - } + }, + + trashedAt: { + check: "Date", + nullable: true, + apply: "__applyTrashedAt" + }, + + trashedBy: { + check: "Number", + nullable: true, + apply: "__applyTrashedBy" + }, }, statics: { @@ -133,17 +145,10 @@ qx.Class.define("osparc.dashboard.WorkspaceButtonItem", { layout = this.getChildControl("header"); layout.addAt(control, osparc.dashboard.WorkspaceButtonBase.HPOS.MENU); break; - case "modified-text": - control = new qx.ui.basic.Label().set({ - textColor: "contrasted-text-dark", - alignY: "middle", - rich: true, - anonymous: true, - font: "text-12", - allowGrowY: false - }); + case "date-by": + control = new osparc.ui.basic.DateAndBy(); layout = this.getChildControl("footer"); - layout.addAt(control, osparc.dashboard.WorkspaceButtonBase.FPOS.MODIFIED); + layout.addAt(control, osparc.dashboard.WorkspaceButtonBase.FPOS.DATE); break; } return control || this.base(arguments, id); @@ -161,6 +166,8 @@ qx.Class.define("osparc.dashboard.WorkspaceButtonItem", { }); workspace.bind("accessRights", this, "accessRights"); workspace.bind("modifiedAt", this, "modifiedAt"); + workspace.bind("trashedAt", this, "trashedAt"); + workspace.bind("trashedBy", this, "trashedBy"); workspace.bind("myAccessRights", this, "myAccessRights"); osparc.utils.Utils.setIdToWidget(this, "workspaceItem_" + workspace.getWorkspaceId()); @@ -242,13 +249,36 @@ qx.Class.define("osparc.dashboard.WorkspaceButtonItem", { }, __applyModifiedAt: function(value) { - const label = this.getChildControl("modified-text"); - label.setValue(osparc.utils.Utils.formatDateAndTime(value)); + if (value) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Last modified"), + }) + } + }, + + __applyTrashedAt: function(value) { + if (value && value.getTime() !== new Date(0).getTime()) { + const dateBy = this.getChildControl("date-by"); + dateBy.set({ + date: value, + toolTipText: this.tr("Moved to the bin"), + }); + } + }, + + __applyTrashedBy: function(gid) { + if (gid) { + const dateBy = this.getChildControl("date-by"); + dateBy.setGroupId(gid); + } }, __updateTooltip: function() { const toolTipText = this.getTitle() + (this.getDescription() ? "
" + this.getDescription() : ""); - this.set({ + const title = this.getChildControl("title"); + title.set({ toolTipText }) }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/Folder.js b/services/static-webserver/client/source/class/osparc/data/model/Folder.js index 6a255a45dc5..096cdd777da 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Folder.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Folder.js @@ -38,6 +38,7 @@ qx.Class.define("osparc.data.model.Folder", { createdAt: new Date(folderData.createdAt), lastModified: new Date(folderData.modifiedAt), trashedAt: folderData.trashedAt ? new Date(folderData.trashedAt) : null, + trashedBy: folderData.trashedBy || null, }); }, @@ -102,6 +103,14 @@ qx.Class.define("osparc.data.model.Folder", { check: "Date", nullable: true, init: null, + event: "changeTrashedAt" + }, + + trashedBy: { + check: "Number", + nullable: true, + init: null, + event: "changeTrashedBy", }, }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/Study.js b/services/static-webserver/client/source/class/osparc/data/model/Study.js index f03a01ff741..6a511f726b7 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Study.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Study.js @@ -60,6 +60,7 @@ qx.Class.define("osparc.data.model.Study", { permalink: studyData.permalink || this.getPermalink(), dev: studyData.dev || this.getDev(), trashedAt: studyData.trashedAt ? new Date(studyData.trashedAt) : this.getTrashedAt(), + trashedBy: studyData.trashedBy || null, }); const wbData = studyData.workbench || this.getWorkbench(); @@ -217,6 +218,13 @@ qx.Class.define("osparc.data.model.Study", { nullable: true, init: null, }, + + trashedBy: { + check: "Number", + nullable: true, + init: null, + event: "changeTrashedBy", + }, // ------ ignore for serializing ------ }, diff --git a/services/static-webserver/client/source/class/osparc/data/model/Workspace.js b/services/static-webserver/client/source/class/osparc/data/model/Workspace.js index 65592fb1789..93f257abc6d 100644 --- a/services/static-webserver/client/source/class/osparc/data/model/Workspace.js +++ b/services/static-webserver/client/source/class/osparc/data/model/Workspace.js @@ -103,12 +103,14 @@ qx.Class.define("osparc.data.model.Workspace", { check: "Date", nullable: true, init: null, + event: "changeTrashedAt", }, trashedBy: { check: "Number", nullable: true, init: null, + event: "changeTrashedBy", }, }, diff --git a/services/static-webserver/client/source/class/osparc/info/StudyUtils.js b/services/static-webserver/client/source/class/osparc/info/StudyUtils.js index 1604be1805c..b143f127a05 100644 --- a/services/static-webserver/client/source/class/osparc/info/StudyUtils.js +++ b/services/static-webserver/client/source/class/osparc/info/StudyUtils.js @@ -511,6 +511,6 @@ qx.Class.define("osparc.info.StudyUtils", { studyData["lastChangeDate"] = new Date().toISOString(); }) .catch(err => osparc.FlashMessenger.logAs(err.message, "ERROR")); - } + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js index 9397aed32e8..f6e2688ae05 100644 --- a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js +++ b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js @@ -97,8 +97,10 @@ qx.Class.define("osparc.navigation.NavigationBar", { }, __buildLayout: function() { + const colorStr = qx.theme.manager.Color.getInstance().resolve("background-main-1"); + const color = qx.util.ColorUtil.stringToRgb(colorStr); this.getContentElement().setStyles({ - "background": "linear-gradient(0deg, rgba(1, 18, 26, 0.1) 0%, rgba(229, 229, 229, 0.1) 5%)" + "background": `linear-gradient(0deg, rgba(1, 18, 26, 0.1) 0%, ${qx.util.ColorUtil.rgbToRgbString(color)} 4%)` }); this.getChildControl("left-items"); this.getChildControl("center-items"); diff --git a/services/static-webserver/client/source/class/osparc/ui/basic/DateAndBy.js b/services/static-webserver/client/source/class/osparc/ui/basic/DateAndBy.js new file mode 100644 index 00000000000..abc819dc8d9 --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/ui/basic/DateAndBy.js @@ -0,0 +1,106 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2020 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +/** + * Widget that shows a date followed by "by (user_icon)" + */ +qx.Class.define("osparc.ui.basic.DateAndBy", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.HBox(5)); + + this.set({ + alignY: "middle", + }); + }, + + properties: { + date: { + check: "Date", + nullable: true, + apply: "__applyDate", + }, + + groupId: { + check: "Number", + nullable: true, + apply: "__applyGroupId", + }, + }, + + members: { + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "date-text": + control = new qx.ui.basic.Label().set({ + textColor: "contrasted-text-dark", + alignY: "middle", + rich: true, + font: "text-12", + allowGrowY: false + }); + this._addAt(control, 0); + break; + case "last-touching": + control = new qx.ui.basic.Atom().set({ + alignY: "middle", + allowGrowX: false, + allowShrinkX: false, + label: "by", + font: "text-12", + icon: osparc.dashboard.CardBase.SHARED_USER, + iconPosition: "right", + }); + this._addAt(control, 1); + break; + } + return control || this.base(arguments, id); + }, + + __applyDate: function(value) { + if (value) { + const label = this.getChildControl("date-text"); + const today = new Date(); + const yesterday = new Date(); + if (today.toDateString() === value.toDateString()) { + label.setValue(osparc.utils.Utils.formatDateAndTime(value)); // show date and time + } else if (yesterday.toDateString() === value.toDateString()) { + label.setValue(osparc.utils.Utils.formatDateAndTime(value)); // show date and time + } else { + label.setValue(osparc.utils.Utils.formatDate(value)); // show date only + } + } + }, + + __applyGroupId: function(groupId) { + if (groupId) { + const atom = this.getChildControl("last-touching"); + const myGroupId = osparc.auth.Data.getInstance().getGroupId(); + if (groupId === myGroupId) { + atom.setLabel("by me"); + } else { + atom.setLabel("by"); + osparc.dashboard.CardBase.addHintFromGids(atom, [groupId]); + } + } + }, + } +});