Skip to content

Commit 77ed00a

Browse files
authored
🎨 [Frontend] Plus Button: Support myMostUsed Services (#7238)
1 parent db4a34e commit 77ed00a

File tree

4 files changed

+162
-97
lines changed

4 files changed

+162
-97
lines changed

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

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
"newStudyLabel": "string", // optional
4545
"category": "categories.id", // optional
4646
"idToWidget": "string" // optional
47+
}, {
48+
"resourceType": "service", // it will create a study from the service
49+
"myMostUsed": 2, // required
50+
"category": "categories.id", // optional
4751
}, {
4852
"showDisabled": true, // it will show a disabled button on the defined item
4953
"title": "string", // required
@@ -201,12 +205,18 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
201205

202206
__addIcon: function(menuButton, resourceInfo, resourceMetadata) {
203207
let source = null;
204-
if (resourceInfo && "icon" in resourceInfo) {
208+
if (resourceInfo && resourceInfo["icon"]) {
205209
// first the one set in the ui_config
206210
source = resourceInfo["icon"];
207-
} else if (resourceMetadata && "thumbnail" in resourceMetadata) {
208-
// second the one from the resource
211+
} else if (resourceMetadata && resourceMetadata["icon"]) {
212+
// second the icon from the resource
213+
source = resourceMetadata["icon"];
214+
} else if (resourceMetadata && resourceMetadata["thumbnail"]) {
215+
// third the thumbnail from the resource
209216
source = resourceMetadata["thumbnail"];
217+
} else {
218+
// finally product icon
219+
source = osparc.dashboard.CardBase.PRODUCT_ICON;
210220
}
211221

212222
if (source) {
@@ -280,48 +290,76 @@ qx.Class.define("osparc.dashboard.NewPlusMenu", {
280290
},
281291

282292
__addFromServiceButton: function(newStudyData) {
283-
const menuButton = this.self().createMenuButton(null, newStudyData["title"]);
284-
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData["idToWidget"]);
285-
// disable it until found in services store
286-
menuButton.setEnabled(false);
293+
const addListenerToButton = (menuButton, latestMetadata) => {
294+
menuButton.addListener("tap", () => {
295+
this.fireDataEvent("newStudyFromServiceClicked", {
296+
serviceMetadata: latestMetadata,
297+
newStudyLabel: newStudyData["newStudyLabel"],
298+
});
299+
});
287300

288-
const key = newStudyData["expectedKey"];
289-
// Include deprecated versions, they should all be updatable to a non deprecated version
290-
const versions = osparc.service.Utils.getVersions(key, false);
291-
if (versions.length && newStudyData) {
292-
// scale to latest compatible
293-
const latestVersion = versions[0];
294-
const latestCompatible = osparc.service.Utils.getLatestCompatible(key, latestVersion);
295-
osparc.store.Services.getService(latestCompatible["key"], latestCompatible["version"])
296-
.then(latestMetadata => {
297-
// make sure this one is not deprecated
298-
if (osparc.service.Utils.isDeprecated(latestMetadata)) {
299-
return;
300-
}
301-
menuButton.setEnabled(true);
302-
menuButton.addListener("tap", () => {
303-
this.fireDataEvent("newStudyFromServiceClicked", {
304-
serviceMetadata: latestMetadata,
305-
newStudyLabel: newStudyData["newStudyLabel"],
306-
});
301+
const cb = e => {
302+
this.hide();
303+
// so that is not consumed by the menu button itself
304+
e.stopPropagation();
305+
latestMetadata["resourceType"] = "service";
306+
const resourceDetails = new osparc.dashboard.ResourceDetails(latestMetadata);
307+
osparc.dashboard.ResourceDetails.popUpInWindow(resourceDetails);
308+
}
309+
const infoButton = new osparc.ui.basic.IconButton(osparc.ui.hint.InfoHint.INFO_ICON + "/16", cb);
310+
// where the shortcut is supposed to go
311+
// eslint-disable-next-line no-underscore-dangle
312+
menuButton._add(infoButton, {column: 2});
313+
};
314+
315+
if ("expectedKey" in newStudyData) {
316+
const menuButton = this.self().createMenuButton(null, newStudyData["title"]);
317+
osparc.utils.Utils.setIdToWidget(menuButton, newStudyData["idToWidget"]);
318+
// disable it until found in services store
319+
menuButton.setEnabled(false);
320+
321+
const key = newStudyData["expectedKey"];
322+
// Include deprecated versions, they should all be updatable to a non deprecated version
323+
const versions = osparc.service.Utils.getVersions(key, false);
324+
if (versions.length && newStudyData) {
325+
// scale to latest compatible
326+
const latestVersion = versions[0];
327+
const latestCompatible = osparc.service.Utils.getLatestCompatible(key, latestVersion);
328+
osparc.store.Services.getService(latestCompatible["key"], latestCompatible["version"])
329+
.then(latestMetadata => {
330+
// make sure this one is not deprecated
331+
if (osparc.service.Utils.isDeprecated(latestMetadata)) {
332+
return;
333+
}
334+
menuButton.setEnabled(true);
335+
this.__addIcon(menuButton, newStudyData, latestMetadata);
336+
this.__addFromResourceButton(menuButton, newStudyData["category"]);
337+
addListenerToButton(menuButton, latestMetadata);
307338
});
308-
309-
const cb = e => {
310-
this.hide();
311-
// so that is not consumed by the menu button itself
312-
e.stopPropagation();
313-
latestMetadata["resourceType"] = "service";
314-
const resourceDetails = new osparc.dashboard.ResourceDetails(latestMetadata);
315-
osparc.dashboard.ResourceDetails.popUpInWindow(resourceDetails);
339+
}
340+
} else if ("myMostUsed" in newStudyData) {
341+
const excludeFrontend = true;
342+
const excludeDeprecated = true
343+
osparc.store.Services.getServicesLatestList(excludeFrontend, excludeDeprecated)
344+
.then(servicesList => {
345+
osparc.service.Utils.sortObjectsBasedOn(servicesList, {
346+
"sort": "hits",
347+
"order": "down"
348+
});
349+
for (let i=0; i<newStudyData["myMostUsed"]; i++) {
350+
const latestMetadata = servicesList[i];
351+
if (latestMetadata["hits"] > 0) {
352+
const menuButton = new qx.ui.menu.Button().set({
353+
label: latestMetadata["name"],
354+
font: "text-16",
355+
allowGrowX: true,
356+
});
357+
this.__addIcon(menuButton, null, latestMetadata);
358+
this.__addFromResourceButton(menuButton, newStudyData["category"]);
359+
addListenerToButton(menuButton, latestMetadata);
360+
}
316361
}
317-
const infoButton = new osparc.ui.basic.IconButton(osparc.ui.hint.InfoHint.INFO_ICON + "/16", cb);
318-
// where the shortcut is supposed to go
319-
// eslint-disable-next-line no-underscore-dangle
320-
menuButton._add(infoButton, {column: 2});
321-
322-
this.__addIcon(menuButton, newStudyData, latestMetadata);
323-
this.__addFromResourceButton(menuButton, newStudyData["category"]);
324-
})
362+
});
325363
}
326364
},
327365

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

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -935,36 +935,91 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
935935

936936
if (!osparc.product.Utils.hasNewPlusButton()) {
937937
switch (osparc.product.Utils.getProductName()) {
938-
case "osparc":
939-
this.__addEmptyStudyPlusButton();
940-
break;
941938
case "tis":
942939
case "tiplite":
940+
// this one is different since it groups all new buttons in one new button
943941
this.__addTIPPlusButton();
944942
break;
945-
case "s4l":
946-
case "s4lacad":
947-
case "s4llite":
948-
this.__addPlusButtonsFromServices();
943+
default:
944+
this.__addPlusButtons();
949945
break;
950946
}
951947
}
952948
},
953949

954-
__addEmptyStudyPlusButton: function() {
950+
__addPlusButtons: function() {
951+
const plusButtonConfig = osparc.store.Products.getInstance().getNewStudiesUiConfig();
952+
plusButtonConfig["resources"].forEach(newStudyData => {
953+
if (newStudyData["resourceType"] === "study") {
954+
this.__addEmptyStudyPlusButton(newStudyData);
955+
} else if (newStudyData["resourceType"] === "service") {
956+
this.__addNewStudyFromServiceButton(newStudyData);
957+
}
958+
});
959+
},
960+
961+
__addEmptyStudyPlusButton: function(newStudyData) {
955962
const mode = this._resourcesContainer.getMode();
956-
const title = this.tr("Empty") + " " + osparc.product.Utils.getStudyAlias({
963+
const defTitle = this.tr("Empty") + " " + osparc.product.Utils.getStudyAlias({
957964
firstUpperCase: true
958-
})
959-
const desc = this.tr("Start with an empty study");
965+
});
966+
const title = newStudyData["title"] || defTitle;
967+
const desc = newStudyData["description"] || this.tr("Start with an empty study");
960968
const newEmptyStudyBtn = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
961969
newEmptyStudyBtn.setCardKey("new-study");
962970
newEmptyStudyBtn.subscribeToFilterGroup("searchBarFilter");
963-
osparc.utils.Utils.setIdToWidget(newEmptyStudyBtn, "emptyStudyBtn");
964-
newEmptyStudyBtn.addListener("tap", () => this.__newEmptyStudyBtnClicked("New Study"));
971+
osparc.utils.Utils.setIdToWidget(newEmptyStudyBtn, newStudyData["idToWidget"]);
972+
newEmptyStudyBtn.addListener("tap", () => this.__newEmptyStudyBtnClicked(newStudyData["newStudyLabel"]));
965973
this._resourcesContainer.addNonResourceCard(newEmptyStudyBtn);
966974
},
967975

976+
__addNewStudyFromServiceButton: function(newStudyData) {
977+
if ("expectedKey" in newStudyData) {
978+
const key = newStudyData["expectedKey"];
979+
// Include deprecated versions, they should all be updatable to a non deprecated version
980+
const versions = osparc.service.Utils.getVersions(key, false);
981+
if (versions.length && newStudyData) {
982+
// scale to latest compatible
983+
const latestVersion = versions[0];
984+
const latestCompatible = osparc.service.Utils.getLatestCompatible(key, latestVersion);
985+
osparc.store.Services.getService(latestCompatible["key"], latestCompatible["version"])
986+
.then(latestMetadata => {
987+
// make sure this one is not deprecated
988+
if (osparc.service.Utils.isDeprecated(latestMetadata)) {
989+
return;
990+
}
991+
const title = newStudyData.title + " " + osparc.service.Utils.extractVersionDisplay(latestMetadata);
992+
const desc = newStudyData.description;
993+
const mode = this._resourcesContainer.getMode();
994+
const newStudyFromServiceButton = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
995+
newStudyFromServiceButton.setCardKey("new-"+key);
996+
if (newStudyData["idToWidget"]) {
997+
osparc.utils.Utils.setIdToWidget(newStudyFromServiceButton, newStudyData["idToWidget"]);
998+
}
999+
newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(latestMetadata["key"], latestMetadata["version"], newStudyData.newStudyLabel));
1000+
this._resourcesContainer.addNonResourceCard(newStudyFromServiceButton);
1001+
})
1002+
}
1003+
} else if ("myMostUsed" in newStudyData) {
1004+
const excludeFrontend = true;
1005+
const excludeDeprecated = true
1006+
osparc.store.Services.getServicesLatestList(excludeFrontend, excludeDeprecated)
1007+
.then(servicesList => {
1008+
osparc.service.Utils.sortObjectsBasedOn(servicesList, {
1009+
"sort": "hits",
1010+
"order": "down"
1011+
});
1012+
for (let i=0; i<newStudyData["myMostUsed"]; i++) {
1013+
const latestMetadata = servicesList[i];
1014+
const mode = this._resourcesContainer.getMode();
1015+
const newStudyFromServiceButton = (mode === "grid") ? new osparc.dashboard.GridButtonNew(latestMetadata["name"]) : new osparc.dashboard.ListButtonNew(latestMetadata["name"]);
1016+
newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(latestMetadata["key"], latestMetadata["version"], latestMetadata["name"]));
1017+
this._resourcesContainer.addNonResourceCard(newStudyFromServiceButton);
1018+
}
1019+
});
1020+
}
1021+
},
1022+
9681023
__addTIPPlusButton: function() {
9691024
const mode = this._resourcesContainer.getMode();
9701025
const title = this.tr("New Plan");
@@ -975,15 +1030,15 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
9751030
this._resourcesContainer.addNonResourceCard(newPlansBtn);
9761031
newPlansBtn.setEnabled(false);
9771032

978-
const newStudiesData = osparc.store.Products.getInstance().getNewStudiesUiConfig();
979-
if (newStudiesData) {
1033+
const newStudiesConfig = osparc.store.Products.getInstance().getNewStudiesUiConfig();
1034+
if (newStudiesConfig) {
9801035
newPlansBtn.setEnabled(true);
9811036

9821037
newPlansBtn.addListener("tap", () => {
9831038
osparc.data.Resources.get("templates")
9841039
.then(templates => {
9851040
if (templates) {
986-
const newStudies = new osparc.dashboard.NewStudies(newStudiesData);
1041+
const newStudies = new osparc.dashboard.NewStudies(newStudiesConfig);
9871042
newStudies.addListener("templatesLoaded", () => {
9881043
newStudies.setGroupBy("category");
9891044
const winTitle = this.tr("New Plan");
@@ -1007,45 +1062,6 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
10071062
}
10081063
},
10091064

1010-
// Used in S4L products
1011-
__addNewStudyFromServiceButtons: function(key, newButtonInfo) {
1012-
// Include deprecated versions, they should all be updatable to a non deprecated version
1013-
const versions = osparc.service.Utils.getVersions(key, false);
1014-
if (versions.length && newButtonInfo) {
1015-
// scale to latest compatible
1016-
const latestVersion = versions[0];
1017-
const latestCompatible = osparc.service.Utils.getLatestCompatible(key, latestVersion);
1018-
osparc.store.Services.getService(latestCompatible["key"], latestCompatible["version"])
1019-
.then(latestMetadata => {
1020-
// make sure this one is not deprecated
1021-
if (osparc.service.Utils.isDeprecated(latestMetadata)) {
1022-
return;
1023-
}
1024-
const title = newButtonInfo.title + " " + osparc.service.Utils.extractVersionDisplay(latestMetadata);
1025-
const desc = newButtonInfo.description;
1026-
const mode = this._resourcesContainer.getMode();
1027-
const newStudyFromServiceButton = (mode === "grid") ? new osparc.dashboard.GridButtonNew(title, desc) : new osparc.dashboard.ListButtonNew(title, desc);
1028-
newStudyFromServiceButton.setCardKey("new-"+key);
1029-
if (newButtonInfo["idToWidget"]) {
1030-
osparc.utils.Utils.setIdToWidget(newStudyFromServiceButton, newButtonInfo["idToWidget"]);
1031-
}
1032-
newStudyFromServiceButton.addListener("tap", () => this.__newStudyFromServiceBtnClicked(latestMetadata["key"], latestMetadata["version"], newButtonInfo.newStudyLabel));
1033-
this._resourcesContainer.addNonResourceCard(newStudyFromServiceButton);
1034-
})
1035-
}
1036-
},
1037-
1038-
__addPlusButtonsFromServices: function() {
1039-
// add new plus buttons if key services exists
1040-
const newStudiesData = osparc.store.Products.getInstance().getNewStudiesUiConfig();
1041-
if (newStudiesData) {
1042-
const newButtonsInfo = newStudiesData["resources"];
1043-
newButtonsInfo.forEach(newButtonInfo => {
1044-
this.__addNewStudyFromServiceButtons(newButtonInfo.expectedKey, newButtonInfo);
1045-
});
1046-
}
1047-
},
1048-
10491065
// LAYOUT //
10501066
_createLayout: function() {
10511067
this._createSearchBar();

services/static-webserver/client/source/resource/osparc/ui_config.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@
153153
"title": "Empty Study",
154154
"newStudyLabel": "New Study",
155155
"idToWidget": "emptyStudyBtn"
156+
}, {
157+
"resourceType": "service",
158+
"myMostUsed": 2
156159
}]
157160
}
158161
}

services/static-webserver/client/source/resource/schemas/product-ui.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
"idToWidget": { "type": "string" }
6464
},
6565
"required": ["resourceType", "expectedKey", "title"]
66+
}, {
67+
"type": "object",
68+
"properties": {
69+
"resourceType": { "enum": ["service"] },
70+
"myMostUsed": { "type": "integer" },
71+
"category": { "type": "string" }
72+
},
73+
"required": ["resourceType", "myMostUsed"]
6674
}, {
6775
"type": "object",
6876
"properties": {

0 commit comments

Comments
 (0)