Skip to content

Commit dbec189

Browse files
authored
🎨 [Frontend] Enh ViP Market: Display bundled models in thumbnail list (#7236)
1 parent 76ace06 commit dbec189

File tree

3 files changed

+82
-55
lines changed

3 files changed

+82
-55
lines changed

services/static-webserver/client/source/class/osparc/editor/ThumbnailSuggestions.js

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,15 +209,18 @@ qx.Class.define("osparc.editor.ThumbnailSuggestions", {
209209
this.setSuggestions(this.__thumbnails);
210210
},
211211

212-
thumbnailTapped: function(thumbnail) {
212+
__thumbnailTapped: function(thumbnail) {
213+
// reset decoration
214+
const unselectedBorderColor = qx.theme.manager.Color.getInstance().resolve("text");
215+
const unselectedBGColor = qx.theme.manager.Color.getInstance().resolve("fab-background");
213216
this.getChildren().forEach(thumbnailImg => {
214-
osparc.utils.Utils.updateBorderColor(thumbnailImg, qx.theme.manager.Color.getInstance().resolve("box-shadow"));
215-
osparc.utils.Utils.addBackground(thumbnailImg, qx.theme.manager.Color.getInstance().resolve("fab-background"));
217+
osparc.utils.Utils.updateBorderColor(thumbnailImg, unselectedBorderColor);
218+
osparc.utils.Utils.addBackground(thumbnailImg, unselectedBGColor);
216219
});
217-
const color = qx.theme.manager.Color.getInstance().resolve("background-selected-dark");
218-
const bgColor = qx.theme.manager.Color.getInstance().resolve("background-selected");
219-
osparc.utils.Utils.updateBorderColor(thumbnail, color);
220-
osparc.utils.Utils.addBackground(thumbnail, bgColor);
220+
const selectedBorderColor = qx.theme.manager.Color.getInstance().resolve("strong-main");
221+
const selectedBGColor = qx.theme.manager.Color.getInstance().resolve("background-selected");
222+
osparc.utils.Utils.updateBorderColor(thumbnail, selectedBorderColor);
223+
osparc.utils.Utils.addBackground(thumbnail, selectedBGColor);
221224
this.fireDataEvent("thumbnailTapped", {
222225
type: thumbnail.thumbnailType || "templateThumbnail",
223226
source: thumbnail.thumbnailFileUrl || thumbnail.getSource()
@@ -238,9 +241,7 @@ qx.Class.define("osparc.editor.ThumbnailSuggestions", {
238241
thumbnail.thumbnailFileUrl = suggestion.fileUrl || suggestion;
239242
thumbnail.addListener("mouseover", () => thumbnail.set({decorator: "thumbnail-selected"}), this);
240243
thumbnail.addListener("mouseout", () => thumbnail.set({decorator: "thumbnail"}), this);
241-
thumbnail.addListener("tap", () => {
242-
this.thumbnailTapped(thumbnail);
243-
}, this);
244+
thumbnail.addListener("tap", () => this.__thumbnailTapped(thumbnail), this);
244245
this.add(thumbnail);
245246
});
246247
}

services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelDetails.js

Lines changed: 67 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
2121
construct: function() {
2222
this.base(arguments);
2323

24-
const layout = new qx.ui.layout.VBox(10);
24+
const layout = new qx.ui.layout.VBox(15);
2525
this._setLayout(layout);
2626

2727
this.__populateLayout();
@@ -48,7 +48,25 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
4848
},
4949
},
5050

51+
statics: {
52+
createThumbnail: function(source, size) {
53+
return new qx.ui.basic.Image().set({
54+
source: source,
55+
alignY: "middle",
56+
scale: true,
57+
allowGrowX: true,
58+
allowGrowY: true,
59+
allowShrinkX: true,
60+
allowShrinkY: true,
61+
maxWidth: size,
62+
maxHeight: size,
63+
});
64+
},
65+
},
66+
5167
members: {
68+
__selectedModelLayout: null,
69+
5270
__populateLayout: function() {
5371
this._removeAll();
5472

@@ -71,43 +89,56 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
7189
},
7290

7391
__addModelsInfo: function() {
74-
const modelLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(16));
92+
const modelLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6));
93+
94+
this.__selectedModelLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6));
95+
modelLayout.add(this.__selectedModelLayout);
7596

7697
const anatomicalModelsData = this.getAnatomicalModelsData();
7798
const modelsInfo = anatomicalModelsData["licensedResources"];
7899
if (modelsInfo.length > 1) {
79-
const sBox = new qx.ui.form.SelectBox().set({
80-
minWidth: 200,
81-
allowGrowX: false,
82-
});
83-
modelsInfo.forEach(modelInfo => {
84-
const sbItem = new qx.ui.form.ListItem(modelInfo["source"]["features"]["name"]);
85-
sbItem.modelId = modelInfo["source"]["id"];
86-
sBox.add(sbItem);
100+
const modelSelectionLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(4));
101+
const titleLabel = new qx.ui.basic.Label(this.tr("This bundle contains:"));
102+
modelSelectionLayout.add(titleLabel);
103+
const thumbnailsLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(2));
104+
modelSelectionLayout.add(thumbnailsLayout);
105+
const thumbnailTapped = idx => {
106+
this.__populateSelectedModelInfo(idx);
107+
const selectedBorderColor = qx.theme.manager.Color.getInstance().resolve("strong-main");
108+
const unselectedBorderColor = "transparent";
109+
thumbnailsLayout.getChildren().forEach((thumbnail, index) => {
110+
osparc.utils.Utils.updateBorderColor(thumbnail, index === idx ? selectedBorderColor : unselectedBorderColor);
111+
});
112+
}
113+
modelsInfo.forEach((modelInfo, idx) => {
114+
const miniThumbnail = this.self().createThumbnail(modelInfo["source"]["thumbnail"], 32);
115+
miniThumbnail.set({
116+
toolTipText: osparc.store.LicensedItems.licensedResourceNameAndVersion(modelInfo),
117+
});
118+
osparc.utils.Utils.addBorder(miniThumbnail);
119+
miniThumbnail.addListener("tap", () => thumbnailTapped(idx));
120+
thumbnailsLayout.add(miniThumbnail);
87121
});
88-
this._add(sBox);
89-
sBox.addListener("changeSelection", e => {
90-
const selection = e.getData();
91-
if (selection.length) {
92-
const idxFound = modelsInfo.findIndex(mdlInfo => mdlInfo["source"]["id"] === selection[0].modelId)
93-
this.__populateModelInfo(modelLayout, anatomicalModelsData, idxFound);
94-
}
95-
}, this);
96-
this.__populateModelInfo(modelLayout, anatomicalModelsData, 0);
122+
modelLayout.add(modelSelectionLayout);
123+
thumbnailTapped(0);
124+
125+
this.__populateSelectedModelInfo();
97126
} else {
98-
this.__populateModelInfo(modelLayout, anatomicalModelsData, 0);
127+
this.__populateSelectedModelInfo();
99128
}
100129

101130
this._add(modelLayout);
102131
},
103132

104-
__populateModelInfo: function(modelLayout, anatomicalModelsData, selectedIdx = 0) {
105-
modelLayout.removeAll();
133+
__populateSelectedModelInfo: function(selectedIdx = 0) {
134+
this.__selectedModelLayout.removeAll();
106135

107-
const anatomicalModel = anatomicalModelsData["licensedResources"][selectedIdx]["source"];
108-
const topGrid = new qx.ui.layout.Grid(8, 8);
136+
const anatomicalModelsData = this.getAnatomicalModelsData();
137+
138+
const topGrid = new qx.ui.layout.Grid(8, 6);
109139
topGrid.setColumnFlex(0, 1);
110-
const topLayout = new qx.ui.container.Composite(topGrid);
140+
const headerLayout = new qx.ui.container.Composite(topGrid);
141+
const anatomicalModel = anatomicalModelsData["licensedResources"][selectedIdx]["source"];
111142
let description = anatomicalModel["description"] || "";
112143
description = description.replace(/SPEAG/g, " "); // remove SPEAG substring
113144
const delimiter = " - ";
@@ -120,7 +151,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
120151
allowGrowX: true,
121152
allowGrowY: true,
122153
});
123-
topLayout.add(titleLabel, {
154+
headerLayout.add(titleLabel, {
124155
column: 0,
125156
row: 0,
126157
});
@@ -135,7 +166,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
135166
allowGrowX: true,
136167
allowGrowY: true,
137168
});
138-
topLayout.add(subtitleLabel, {
169+
headerLayout.add(subtitleLabel, {
139170
column: 0,
140171
row: 1,
141172
});
@@ -166,27 +197,17 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
166197
decorator: "rounded",
167198
});
168199
manufacturerLink.addListener("tap", () => window.open(manufacturerData["link"]));
169-
topLayout.add(manufacturerLink, {
200+
headerLayout.add(manufacturerLink, {
170201
column: 1,
171202
row: 0,
172203
rowSpan: 2,
173204
});
174205
}
175-
modelLayout.add(topLayout);
206+
this.__selectedModelLayout.add(headerLayout);
176207

177208

178209
const middleLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(16));
179-
const thumbnail = new qx.ui.basic.Image().set({
180-
source: anatomicalModel["thumbnail"],
181-
alignY: "middle",
182-
scale: true,
183-
allowGrowX: true,
184-
allowGrowY: true,
185-
allowShrinkX: true,
186-
allowShrinkY: true,
187-
maxWidth: 256,
188-
maxHeight: 256,
189-
});
210+
const thumbnail = this.self().createThumbnail(anatomicalModel["thumbnail"], 256);
190211
middleLayout.add(thumbnail);
191212

192213
const features = anatomicalModel["features"];
@@ -264,14 +285,14 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
264285

265286
middleLayout.add(featuresLayout);
266287

267-
modelLayout.add(middleLayout);
288+
this.__selectedModelLayout.add(middleLayout);
268289

269-
const importButton = this.__createImportSection(anatomicalModelsData, selectedIdx);
270-
modelLayout.add(importButton);
290+
const importSection = this.__createImportSection(anatomicalModelsData, selectedIdx);
291+
this.__selectedModelLayout.add(importSection);
271292
},
272293

273294
__createImportSection: function(anatomicalModelsData, selectedIdx) {
274-
const importSection = new qx.ui.container.Composite(new qx.ui.layout.VBox(5).set({
295+
const importSection = new qx.ui.container.Composite(new qx.ui.layout.VBox().set({
275296
alignX: "center"
276297
}));
277298

@@ -281,6 +302,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
281302
center: true,
282303
maxWidth: 200,
283304
alignX: "center",
305+
marginTop: 10,
284306
});
285307
this.bind("openBy", importButton, "visibility", {
286308
converter: openBy => openBy ? "visible" : "excluded"
@@ -344,7 +366,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
344366
.then(licensedItems => {
345367
const lowerLicensedItems = osparc.store.LicensedItems.getLowerLicensedItems(licensedItems, licensedItemData["key"], licensedItemData["version"])
346368
if (licensedItemData["licensedResources"].length > 1 || lowerLicensedItems.length) {
347-
let text = this.tr("This Bundle gives you access to:") + "<br>";
369+
let text = this.tr("This bundle gives you access to:") + "<br>";
348370
licensedItemData["licensedResources"].forEach(licensedResource => {
349371
text += `- ${osparc.store.LicensedItems.licensedResourceNameAndVersion(licensedResource)}<br>`;
350372
});

services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelListItem.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelListItem", {
177177

178178
__applyDisplayName: function(value) {
179179
this.getChildControl("name").setValue(value);
180+
181+
this.set({
182+
toolTipText: value
183+
});
180184
},
181185

182186
__applySeats: function(seats) {

0 commit comments

Comments
 (0)