Skip to content

Commit 4653f36

Browse files
authored
🎨 [Frontend] Enh: Tags UX (#7169)
1 parent 05eea4b commit 4653f36

File tree

10 files changed

+122
-90
lines changed

10 files changed

+122
-90
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ qx.Class.define("osparc.dashboard.CardBase", {
489489
lastChangeDate: resourceData.lastChangeDate ? new Date(resourceData.lastChangeDate) : null,
490490
trashedAt: resourceData.trashedAt ? new Date(resourceData.trashedAt) : null,
491491
trashedBy: resourceData.trashedBy || null,
492-
icon: ["study", "template"].includes(resourceData.resourceType) ? osparc.study.Utils.guessIcon(resourceData) : null,
492+
icon: ["study", "template"].includes(resourceData.resourceType) ? osparc.study.Utils.guessIcon(resourceData) : osparc.dashboard.CardBase.PRODUCT_ICON,
493493
thumbnail: resourceData.thumbnail || this.self().PRODUCT_THUMBNAIL,
494494
state: resourceData.state ? resourceData.state : {},
495495
classifiers: resourceData.classifiers && resourceData.classifiers ? resourceData.classifiers : [],

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

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
4444
ITEM_WIDTH: 190,
4545
ITEM_HEIGHT: 220,
4646
PADDING: 10,
47+
TITLE_PADDING: 6,
4748
SPACING_IN: 5,
4849
SPACING: 15,
4950
ICON_SIZE: 32,
@@ -202,8 +203,8 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
202203
control = new qx.ui.basic.Label().set({
203204
textColor: "contrasted-text-light",
204205
font: "text-14",
205-
padding: this.self().PADDING,
206-
maxWidth: this.self().ITEM_WIDTH - 2*this.self().PADDING,
206+
padding: this.self().TITLE_PADDING,
207+
maxWidth: this.self().ITEM_WIDTH,
207208
maxHeight: this.self().TITLE_MAX_HEIGHT,
208209
});
209210
layout = this.getChildControl("header");
@@ -368,14 +369,6 @@ qx.Class.define("osparc.dashboard.GridButtonBase", {
368369
thumbnailLayout.recheckSize();
369370
},
370371

371-
replaceIcon: function(newIcon) {
372-
const plusIcon = this.getChildControl("icon");
373-
plusIcon.exclude();
374-
375-
const bodyLayout = this.getChildControl("body");
376-
bodyLayout.add(newIcon, {flex: 1});
377-
},
378-
379372
/**
380373
* Event handler for the pointer over event.
381374
*/

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

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
9393
break;
9494
case "menu-button":
9595
this.getChildControl("title").set({
96-
maxWidth: osparc.dashboard.GridButtonBase.ITEM_WIDTH - osparc.dashboard.GridButtonBase.ICON_SIZE - this.self().MENU_BTN_DIMENSIONS - 6,
97-
padding: 4,
96+
maxWidth: osparc.dashboard.GridButtonBase.ITEM_WIDTH - osparc.dashboard.GridButtonBase.ICON_SIZE - this.self().MENU_BTN_DIMENSIONS,
9897
});
9998
control = new qx.ui.form.MenuButton().set({
10099
appearance: "form-button-outlined",
@@ -245,18 +244,28 @@ qx.Class.define("osparc.dashboard.GridButtonItem", {
245244

246245
_applyTags: function(tags) {
247246
if (osparc.data.Permissions.getInstance().canDo("study.tag")) {
247+
const maxTags = 2;
248248
const tagsContainer = this.getChildControl("tags");
249249
tagsContainer.setVisibility(tags.length ? "visible" : "excluded");
250250
tagsContainer.removeAll();
251-
tags.forEach(tag => {
251+
for (let i=0; i<=tags.length && i<maxTags; i++) {
252+
const tag = tags[i];
252253
const tagUI = new osparc.ui.basic.Tag(tag, "searchBarFilter");
253254
tagUI.set({
254255
font: "text-12",
255256
toolTipText: this.tr("Click to filter by this Tag")
256257
});
257258
tagUI.addListener("tap", () => this.fireDataEvent("tagClicked", tag));
258259
tagsContainer.add(tagUI);
259-
});
260+
}
261+
if (tags.length > maxTags) {
262+
const moreButton = new qx.ui.basic.Label(this.tr("More...")).set({
263+
font: "text-12",
264+
backgroundColor: "strong-main",
265+
appearance: "tag",
266+
});
267+
tagsContainer.add(moreButton);
268+
}
260269
}
261270
},
262271

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ qx.Class.define("osparc.dashboard.GridButtonLoadMore", {
3939

4040
members: {
4141
_applyFetching: function(value) {
42-
this.setIcon(osparc.dashboard.CardBase.LOADING_ICON);
42+
this.setThumbnail(osparc.dashboard.CardBase.LOADING_ICON);
4343
if (value) {
44-
this.getChildControl("icon").getChildControl("image").getContentElement()
44+
this.getChildControl("thumbnail").getChildControl("image").getContentElement()
4545
.addClass("rotate");
4646
} else {
47-
this.getChildControl("icon").getChildControl("image").getContentElement()
47+
this.getChildControl("thumbnail").getChildControl("image").getContentElement()
4848
.removeClass("rotate");
4949
}
5050
this.setEnabled(!value);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ qx.Class.define("osparc.dashboard.GridButtonPlaceholder", {
105105
title.setValue(titleText);
106106
}
107107
if (icon) {
108-
this.setIcon(icon);
108+
this.setThumbnail(icon);
109109
}
110110

111111
const stateLabel = this.getChildControl("state-label");

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,11 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
253253

254254
_applyTags: function(tags) {
255255
if (osparc.data.Permissions.getInstance().canDo("study.tag")) {
256+
const maxTags = 2;
256257
const tagsContainer = this.getChildControl("tags");
257258
tagsContainer.removeAll();
258-
tags.forEach(tag => {
259+
for (let i=0; i<=tags.length && i<maxTags; i++) {
260+
const tag = tags[i];
259261
const tagUI = new osparc.ui.basic.Tag(tag, "searchBarFilter");
260262
tagUI.set({
261263
alignY: "middle",
@@ -264,7 +266,15 @@ qx.Class.define("osparc.dashboard.ListButtonItem", {
264266
});
265267
tagUI.addListener("tap", () => this.fireDataEvent("tagClicked", tag));
266268
tagsContainer.add(tagUI);
267-
});
269+
}
270+
if (tags.length > maxTags) {
271+
const moreButton = new qx.ui.basic.Label(this.tr("More...")).set({
272+
font: "text-12",
273+
backgroundColor: "strong-main",
274+
appearance: "tag",
275+
});
276+
tagsContainer.add(moreButton);
277+
}
268278
this.__makeItemResponsive(tagsContainer);
269279
}
270280
},

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

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,29 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
5454
__buildLayout: function() {
5555
const filtersSpacer = new qx.ui.core.Spacer(10, 10);
5656
switch (this.__resourceType) {
57-
case "study":
57+
case "study": {
5858
this._add(this.__createWorkspacesAndFoldersTree());
5959
this._add(this.__createTrashBin());
6060
this._add(this.__createResourceTypeContextButtons());
6161
this._add(filtersSpacer);
62-
this._add(this.__createTagsFilterLayout());
62+
const scrollView = new qx.ui.container.Scroll();
63+
scrollView.add(this.__createTagsFilterLayout());
64+
this._add(scrollView, {
65+
flex: 1
66+
});
6367
break;
64-
case "template":
68+
}
69+
case "template": {
6570
this._add(this.__createResourceTypeContextButtons());
6671
this._add(filtersSpacer);
6772
this._add(this.__createSharedWithFilterLayout());
68-
this._add(this.__createTagsFilterLayout());
73+
const scrollView = new qx.ui.container.Scroll();
74+
scrollView.add(this.__createTagsFilterLayout());
75+
this._add(scrollView, {
76+
flex: 1
77+
});
6978
break;
79+
}
7080
case "service":
7181
this._add(this.__createResourceTypeContextButtons());
7282
this._add(filtersSpacer);
@@ -350,26 +360,26 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
350360

351361
/* TAGS */
352362
__createTagsFilterLayout: function() {
353-
const layout = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
354-
osparc.utils.Utils.setIdToWidget(layout, this.__resourceType + "-tagsFilter");
363+
const tagsLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(2));
364+
osparc.utils.Utils.setIdToWidget(tagsLayout, this.__resourceType + "-tagsFilter");
355365

356-
this.__populateTags(layout, []);
366+
this.__populateTags(tagsLayout, []);
357367
osparc.store.Tags.getInstance().addListener("tagsChanged", () => {
358-
this.__populateTags(layout, this.__getSelectedTagIds());
368+
this.__populateTags(tagsLayout, this.__getSelectedTagIds());
359369
}, this);
360370

361-
return layout;
371+
return tagsLayout;
362372
},
363373

364374
__getSelectedTagIds: function() {
365375
const selectedTagIds = this.__tagButtons.filter(btn => btn.getValue()).map(btn => btn.id);
366376
return selectedTagIds;
367377
},
368378

369-
__populateTags: function(layout, selectedTagIds) {
379+
__populateTags: function(tagsLayout, selectedTagIds) {
370380
const maxTags = 5;
371381
this.__tagButtons = [];
372-
layout.removeAll();
382+
tagsLayout.removeAll();
373383
osparc.store.Tags.getInstance().getTags().forEach((tag, idx) => {
374384
const button = new qx.ui.form.ToggleButton(null, "@FontAwesome5Solid/tag/16");
375385
button.id = tag.getTagId();
@@ -381,7 +391,7 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
381391
value: selectedTagIds.includes(tag.getTagId())
382392
});
383393

384-
layout.add(button);
394+
tagsLayout.add(button);
385395

386396
button.addListener("execute", () => {
387397
const selection = this.__getSelectedTagIds();
@@ -411,7 +421,7 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
411421
showAllButton.showingAll = true;
412422
}
413423
});
414-
layout.add(showAllButton);
424+
tagsLayout.add(showAllButton);
415425
}
416426

417427
const editTagsButton = new qx.ui.form.Button(this.tr("Edit Tags..."), "@FontAwesome5Solid/pencil-alt/14");
@@ -422,10 +432,10 @@ qx.Class.define("osparc.dashboard.ResourceFilter", {
422432
const myAccountWindow = osparc.desktop.account.MyAccountWindow.openWindow();
423433
myAccountWindow.openTags();
424434
});
425-
layout.add(editTagsButton);
435+
tagsLayout.add(editTagsButton);
426436

427437
if (this.__resourceType === "study") {
428-
layout.getChildren().forEach(item => item.setPaddingLeft(10)); // align them with the context
438+
tagsLayout.getChildren().forEach(item => item.setPaddingLeft(10)); // align them with the context
429439
}
430440
},
431441
/* /TAGS */

services/static-webserver/client/source/class/osparc/desktop/preferences/pages/TagsPage.js

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,64 +26,60 @@ qx.Class.define("osparc.desktop.preferences.pages.TagsPage", {
2626

2727
this._add(new qx.ui.core.Spacer(null, 10));
2828

29-
this.__container = new qx.ui.container.Composite(new qx.ui.layout.VBox(10));
30-
this.__container.set({
31-
paddingLeft: 10
32-
});
33-
const scroll = new qx.ui.container.Scroll(this.__container);
34-
this._add(scroll);
35-
36-
this.__createComponents();
29+
this.__renderLayout();
3730
},
3831

3932
members: {
40-
__container: null,
41-
__addTagButton: null,
42-
__tagItems: null,
33+
__tagsContainer: null,
34+
35+
__renderLayout: function() {
36+
// Tags
37+
this.__tagsContainer = new qx.ui.container.Composite(new qx.ui.layout.VBox(10));
38+
this.__tagsContainer.set({
39+
paddingLeft: 10
40+
});
41+
const tagContainerScroll = new qx.ui.container.Scroll(this.__tagsContainer);
42+
this._add(tagContainerScroll, {
43+
flex: 1
44+
});
45+
46+
const tags = osparc.store.Tags.getInstance().getTags();
47+
const tagItems = tags.map(tag => new osparc.form.tag.TagItem().set({tag}));
48+
tagItems.forEach(tagItem => {
49+
this.__tagsContainer.add(tagItem);
50+
this.__attachTagItemEvents(tagItem);
51+
});
4352

44-
__createComponents: function() {
45-
this.__addTagButton = new qx.ui.form.Button().set({
53+
// New tag Button
54+
const addTagButton = new qx.ui.form.Button().set({
4655
appearance: "form-button-outlined",
4756
label: this.tr("New Tag"),
4857
icon: "@FontAwesome5Solid/plus/14"
4958
});
50-
osparc.utils.Utils.setIdToWidget(this.__addTagButton, "addTagBtn");
51-
const tags = osparc.store.Tags.getInstance().getTags();
52-
this.__tagItems = tags.map(tag => new osparc.form.tag.TagItem().set({tag}));
53-
this.__renderLayout();
54-
this.__attachEventHandlers();
55-
},
56-
57-
__renderLayout: function() {
58-
this.__container.removeAll();
59+
osparc.utils.Utils.setIdToWidget(addTagButton, "addTagBtn");
60+
addTagButton.addListener("execute", () => {
61+
const newItem = new osparc.form.tag.TagItem().set({
62+
mode: osparc.form.tag.TagItem.modes.EDIT
63+
});
64+
this.__tagsContainer.add(newItem);
65+
this.__attachTagItemEvents(newItem);
5966

60-
// Print tag items
61-
this.__tagItems.forEach(tagItem => this.__container.add(tagItem));
67+
// scroll down
68+
const height = tagContainerScroll.getSizeHint().height;
69+
tagContainerScroll.scrollToY(height);
70+
});
6271

6372
// New tag button
6473
const buttonContainer = new qx.ui.container.Composite(new qx.ui.layout.HBox().set({
6574
alignX: "center"
6675
}));
67-
buttonContainer.add(new qx.ui.core.Spacer(null, 10));
68-
buttonContainer.add(this.__addTagButton);
69-
this.__container.add(buttonContainer);
70-
},
71-
72-
__attachEventHandlers: function() {
73-
this.__addTagButton.addListener("execute", () => {
74-
const itemCount = this.__container.getChildren().length;
75-
const newItem = new osparc.form.tag.TagItem().set({
76-
mode: osparc.form.tag.TagItem.modes.EDIT
77-
});
78-
this.__attachTagItemEvents(newItem);
79-
this.__container.addAt(newItem, Math.max(0, itemCount - 1));
80-
});
81-
this.__tagItems.forEach(tagItem => this.__attachTagItemEvents(tagItem));
76+
buttonContainer.add(addTagButton);
77+
this._add(buttonContainer);
8278
},
8379

8480
__attachTagItemEvents: function(tagItem) {
85-
tagItem.addListener("cancelNewTag", e => this.__container.remove(e.getTarget()), this);
86-
tagItem.addListener("deleteTag", e => this.__container.remove(e.getTarget()));
81+
tagItem.addListener("cancelNewTag", e => this.__tagsContainer.remove(e.getTarget()), this);
82+
tagItem.addListener("deleteTag", e => this.__tagsContainer.remove(e.getTarget()));
8783
}
8884
}
8985
});

services/static-webserver/client/source/class/osparc/form/tag/TagManager.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ qx.Class.define("osparc.form.tag.TagManager", {
7070
this._add(filter);
7171

7272
const tagsContainer = this.__tagsContainer = new qx.ui.container.Composite(new qx.ui.layout.VBox());
73-
this._add(tagsContainer, {
73+
const scrollTags = new qx.ui.container.Scroll();
74+
scrollTags.add(tagsContainer);
75+
this._add(scrollTags, {
7476
flex: 1
7577
});
7678

@@ -90,6 +92,10 @@ qx.Class.define("osparc.form.tag.TagManager", {
9092
newItem.addListener("cancelNewTag", e => tagsContainer.remove(e.getTarget()), this);
9193
newItem.addListener("deleteTag", e => tagsContainer.remove(e.getTarget()), this);
9294
tagsContainer.add(newItem);
95+
96+
// scroll down
97+
const height = scrollTags.getSizeHint().height;
98+
scrollTags.scrollToY(height);
9399
});
94100
this._add(addTagButton);
95101

@@ -120,7 +126,11 @@ qx.Class.define("osparc.form.tag.TagManager", {
120126
__repopulateTags: function() {
121127
this.__tagsContainer.removeAll();
122128
const tags = osparc.store.Tags.getInstance().getTags();
123-
tags.forEach(tag => this.__tagsContainer.add(this.__tagButton(tag)));
129+
const tagButtons = [];
130+
tags.forEach(tag => tagButtons.push(this.__tagButton(tag)));
131+
// list the selected tags first
132+
tagButtons.sort((a, b) => b.getValue() - a.getValue());
133+
tagButtons.forEach(tagButton => this.__tagsContainer.add(tagButton));
124134
},
125135

126136
__tagButton: function(tag) {

0 commit comments

Comments
 (0)