Skip to content

Commit

Permalink
🎨 Frontend: Improvements to tagging functionality (#4052)
Browse files Browse the repository at this point in the history
  • Loading branch information
odeimaiz authored Apr 5, 2023
1 parent 3467d78 commit 1e7a0af
Show file tree
Hide file tree
Showing 16 changed files with 170 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ qx.Class.define("osparc.MaintenanceTracker", {

statics: {
CHECK_INTERVAL: 15*60*1000, // Check every 15'
CLOSABLE_WARN_IN_ADVANCE: 12*60*60*1000, // Show Ribbon Closable Message 12h in advance
CLOSABLE_WARN_IN_ADVANCE: 24*60*60*1000, // Show Ribbon Closable Message 24h in advance
PERMANENT_WARN_IN_ADVANCE: 30*60*1000 // Show Ribbon Permament Message 30' in advance
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@
*/
qx.Class.define("osparc.component.form.tag.TagItem", {
extend: qx.ui.core.Widget,

construct: function() {
this.base(arguments);
this._setLayout(new qx.ui.layout.HBox(5));
this.__validationManager = new qx.ui.form.validation.Manager();
this.__renderLayout();
},

statics: {
modes: {
DISPLAY: "display",
EDIT: "edit"
}
},

properties: {
id: {
check: "Integer"
Expand Down Expand Up @@ -59,10 +62,13 @@ qx.Class.define("osparc.component.form.tag.TagItem", {
refine: true
}
},

events: {
"tagSaved": "qx.event.type.Event",
"cancelNewTag": "qx.event.type.Event",
"deleteTag": "qx.event.type.Event"
},

members: {
__tag: null,
__description: null,
Expand Down Expand Up @@ -236,10 +242,14 @@ qx.Class.define("osparc.component.form.tag.TagItem", {
__tagItemEditButtons: function() {
const buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox());
const saveButton = new osparc.ui.form.FetchButton(null, "@FontAwesome5Solid/check/12").set({
appearance: "link-button"
appearance: "link-button",
paddingTop: 15, // avoid buddy text
alignY: "middle"
});
const cancelButton = new qx.ui.form.Button(null, "@FontAwesome5Solid/times/12").set({
appearance: "link-button"
appearance: "link-button",
paddingTop: 15, // avoid buddy text
alignY: "middle"
});
buttonContainer.add(saveButton);
buttonContainer.add(cancelButton);
Expand All @@ -263,6 +273,7 @@ qx.Class.define("osparc.component.form.tag.TagItem", {
.then(tag => this.set(tag))
.catch(console.error)
.finally(() => {
this.fireEvent("tagSaved");
this.setMode(this.self().modes.DISPLAY);
saveButton.setFetching(false);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,18 @@
* Tag manager server to manage one resource's related tags.
*/
qx.Class.define("osparc.component.form.tag.TagManager", {
extend: osparc.ui.window.SingletonWindow,
construct: function(studyData, attachment, resourceName, resourceId) {
this.base(arguments, "tagManager", this.tr("Apply Tags"));
this.set({
layout: new qx.ui.layout.VBox(),
allowMinimize: false,
allowMaximize: false,
showMinimize: false,
showMaximize: false,
autoDestroy: true,
movable: false,
resizable: false,
modal: true,
width: 262,
clickAwayClose: true
});
this.__attachment = attachment;
this.__resourceName = resourceName;
this.__resourceId = resourceId;
this.__studyData = studyData;
this.__selectedTags = new qx.data.Array(studyData["tags"]);
extend: qx.ui.core.Widget,

construct: function(studyData) {
this.base(arguments);

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

this.__selectedTags = new qx.data.Array();
this.__renderLayout();
this.__attachEventHandlers();
this.open();

this.setStudydata(studyData);
},

events: {
Expand All @@ -45,79 +33,94 @@ qx.Class.define("osparc.component.form.tag.TagManager", {
liveUpdate: {
check: "Boolean",
event: "changeLiveUpdate",
init: true
init: false
}
},

statics: {
popUpInWindow: function(tagManager, title) {
if (!title) {
title = qx.locale.Manager.tr("Apply Tags");
}
return osparc.ui.window.Window.popUpInWindow(tagManager, title, 280, null).set({
allowMinimize: false,
allowMaximize: false,
showMinimize: false,
showMaximize: false,
clickAwayClose: true,
movable: true,
resizable: true,
showClose: true
});
}
},

members: {
__studyData: null,
__attachment: null,
__resourceName: null,
__resourceId: null,
__selectedTags: null,
__tagsContainer: null,
__addTagButton: null,

__renderLayout: function() {
const filter = new osparc.component.filter.TextFilter("name", "studyBrowserTagManager").set({
allowStretchX: true,
margin: [0, 10, 5, 10]
});
this.add(filter);
this._add(filter);

const buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.VBox());
this.add(buttonContainer, {
const tagsContainer = this.__tagsContainer = new qx.ui.container.Composite(new qx.ui.layout.VBox());
this._add(tagsContainer, {
flex: 1
});
osparc.store.Store.getInstance().getTags().forEach(tag => buttonContainer.add(this.__tagButton(tag)));
if (buttonContainer.getChildren().length === 0) {
buttonContainer.add(new qx.ui.basic.Label().set({
value: this.tr("Add your first tag in Preferences/Tags"),
font: "title-16",
textColor: "service-window-hint",
rich: true,
padding: 10,
textAlign: "center"
}));
}

const addTagButton = this.__addTagButton = new qx.ui.form.Button().set({
appearance: "strong-button",
label: this.tr("New Tag"),
icon: "@FontAwesome5Solid/plus/14",
alignX: "center",
allowGrowX: false
});
addTagButton.addListener("execute", () => {
const newItem = new osparc.component.form.tag.TagItem().set({
mode: osparc.component.form.tag.TagItem.modes.EDIT
});
newItem.addListener("tagSaved", () => this.__repopulateTags(), this);
newItem.addListener("cancelNewTag", e => tagsContainer.remove(e.getTarget()), this);
newItem.addListener("deleteTag", e => tagsContainer.remove(e.getTarget()), this);
this.__repopulateTags();
tagsContainer.add(newItem);
});
this._add(addTagButton);

const buttons = new qx.ui.container.Composite(new qx.ui.layout.HBox().set({
alignX: "right"
}));
const saveButton = new osparc.ui.form.FetchButton(this.tr("Save"));
saveButton.set({
appearance: "strong-button"
});
osparc.utils.Utils.setIdToWidget(saveButton, "saveTagsBtn");
saveButton.addListener("execute", e => {
this.__save(saveButton);
}, this);
saveButton.addListener("execute", () => this.__save(saveButton), this);
buttons.add(saveButton);
this.bind("liveUpdate", buttons, "visibility", {
converter: value => value ? "excluded" : "visible"
});
this.add(buttons);
this._add(buttons);
},

/**
* If the attachment (element close to which the TagManager is being rendered) is already on the DOM,
* this function calculates where the TagManager should render, taking into account the window edges.
*/
__updatePosition: function() {
if (this.__attachment && this.__attachment.getContentElement().getDomElement()) {
const location = qx.bom.element.Location.get(this.__attachment.getContentElement().getDomElement());
const freeDistances = osparc.utils.Utils.getFreeDistanceToWindowEdges(this.__attachment);
let position = {
top: location.bottom,
left: location.right
};
if (this.getWidth() > freeDistances.right) {
position.left = location.left - this.getWidth();
if (this.getHeight() > freeDistances.bottom) {
position.top = location.top - (this.getHeight() || this.getSizeHint().height);
}
} else if (this.getHeight() > freeDistances.bottom) {
position.top = location.top - this.getHeight();
}
this.moveTo(position.left, position.top);
} else {
this.center();
}
setStudydata: function(studyData) {
this.__studyData = studyData;
this.__resourceId = studyData["uuid"];
this.__selectedTags.removeAll();
this.__selectedTags.append(studyData["tags"]);
this.__repopulateTags();
},

__repopulateTags: function() {
this.__tagsContainer.removeAll();
const tags = osparc.store.Store.getInstance().getTags();
tags.forEach(tag => this.__tagsContainer.add(this.__tagButton(tag)));
},

__tagButton: function(tag) {
Expand Down Expand Up @@ -208,9 +211,6 @@ qx.Class.define("osparc.component.form.tag.TagManager", {
},

__attachEventHandlers: function() {
this.addListener("appear", () => {
this.__updatePosition();
});
this.__selectedTags.addListener("change", evt => {
this.fireDataEvent("changeSelected", {
...evt.getData(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ qx.Class.define("osparc.component.task.TasksButton", {
}
case "number":
control = new qx.ui.basic.Label().set({
backgroundColor: "background-main-1",
font: "text-12"
});
control.getContentElement().setStyles({
"border-radius": "4px"
});
this._add(control, {
bottom: 3,
right: 0
bottom: 8,
right: 4
});
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,11 @@ qx.Class.define("osparc.dashboard.CardBase", {
moreOpts.openAccessRights();
},

openTags: function() {
const moreOpts = this.__openMoreOptions();
moreOpts.openTags();
},

__openQualityEditor: function() {
const moreOpts = this.__openMoreOptions();
moreOpts.openQuality();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,18 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
const shareButton = new qx.ui.menu.Button(this.tr("Share..."));
shareButton.addListener("tap", () => card.openAccessRights(), this);
return shareButton;
},

_getTagsMenuButton: function(card) {
const resourceData = card.getResourceData();
const isCurrentUserOwner = osparc.data.model.Study.canIWrite(resourceData["accessRights"]);
if (!isCurrentUserOwner) {
return null;
}

const tagsButton = new qx.ui.menu.Button(this.tr("Tags..."));
tagsButton.addListener("tap", () => card.openTags(), this);
return tagsButton;
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
__serviceVersionLayout: null,
__serviceVersionSelector: null,
__permissionsPage: null,
__tagsPage: null,
__classifiersPage: null,
__qualityPage: null,
__servicesUpdatePage: null,
Expand All @@ -76,6 +77,10 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
this.__openPage(this.__permissionsPage);
},

openTags: function() {
this.__openPage(this.__tagsPage);
},

openClassifiers: function() {
this.__openPage(this.__classifiersPage);
},
Expand Down Expand Up @@ -150,6 +155,7 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
this.__getPermissionsPage,
this.__getClassifiersPage,
this.__getQualityPage,
this.__getTagsPage,
this.__getServicesUpdatePage,
this.__getServicesBootOptionsPage,
this.__getSaveAsTemplatePage
Expand Down Expand Up @@ -219,6 +225,7 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
infoCard.addListener("openAccessRights", () => this.openAccessRights());
infoCard.addListener("openClassifiers", () => this.openClassifiers());
infoCard.addListener("openQuality", () => this.openQuality());
infoCard.addListener("openTags", () => this.openTags());
infoCard.addListener("updateStudy", e => {
const updatedData = e.getData();
if (osparc.utils.Resources.isStudy(resourceData)) {
Expand Down Expand Up @@ -373,6 +380,28 @@ qx.Class.define("osparc.dashboard.ResourceMoreOptions", {
return null;
},

__getTagsPage: function() {
const id = "Tags";
const resourceData = this.__resourceData;
if (osparc.utils.Resources.isTemplate(resourceData) && !osparc.data.model.Study.canIWrite(resourceData["accessRights"])) {
return null;
}
if (osparc.utils.Resources.isService(resourceData) && !osparc.utils.Services.canIWrite(resourceData["accessRights"])) {
return null;
}

const title = this.tr("Tags");
const icon = "@FontAwesome5Solid/tags";
const tagManager = new osparc.component.form.tag.TagManager(resourceData);
tagManager.addListener("updateTags", e => {
const updatedData = e.getData();
tagManager.setStudydata(updatedData);
this.fireDataEvent("updateStudy", updatedData);
}, this);
const page = this.__tagsPage = this.__createPage(title, tagManager, icon, id);
return page;
},

__getServicesUpdatePage: function() {
const id = "ServicesUpdate";
const resourceData = this.__resourceData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,11 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
if (shareButton) {
menu.add(shareButton);
}

const tagsButton = this._getTagsMenuButton(card);
if (tagsButton) {
menu.add(tagsButton);
}
}

const duplicateStudyButton = this.__getDuplicateMenuButton(studyData);
Expand Down Expand Up @@ -875,7 +880,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
"studyId": studyData["uuid"]
}
};
const fetchPromise = osparc.data.Resources.fetch("studies", "duplicate", params);
const fetchPromise = osparc.data.Resources.fetch("studies", "duplicate", params, null, {"pollTask": true});
const interval = 1000;
const pollTasks = osparc.data.PollTasks.getInstance();
pollTasks.createPollingTask(fetchPromise, interval)
Expand Down
Loading

0 comments on commit 1e7a0af

Please sign in to comment.