Skip to content

Commit 93e7ab0

Browse files
authored
✨ [Frontend] Group Sim4Life Featured services (#7841)
1 parent 75b38cc commit 93e7ab0

File tree

7 files changed

+161
-13
lines changed

7 files changed

+161
-13
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ qx.Class.define("osparc.dashboard.GroupedCardContainer", {
2323

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

26-
const showAllButton = this.__showAllButton = new qx.ui.form.Button().set({
26+
const showAllButton = this.__expandButton = new qx.ui.form.Button().set({
2727
margin: 10,
2828
marginBottom: 5
2929
});
@@ -70,7 +70,7 @@ qx.Class.define("osparc.dashboard.GroupedCardContainer", {
7070
},
7171

7272
members: {
73-
__showAllButton: null,
73+
__expandButton: null,
7474
__contentContainer: null,
7575

7676
_createChildControlImpl: function(id) {
@@ -116,7 +116,7 @@ qx.Class.define("osparc.dashboard.GroupedCardContainer", {
116116
__createContentContainer: function() {
117117
let contentContainer = null;
118118
const expanded = this.isExpanded();
119-
const showAllBtn = this.__showAllButton;
119+
const showAllBtn = this.__expandButton;
120120
if (expanded) {
121121
contentContainer = new osparc.dashboard.CardContainer();
122122
showAllBtn.show();
@@ -174,6 +174,10 @@ qx.Class.define("osparc.dashboard.GroupedCardContainer", {
174174
return this.__contentContainer;
175175
},
176176

177+
getExpandButton: function() {
178+
return this.__expandButton;
179+
},
180+
177181
// overridden
178182
add: function(child, idx) {
179183
if (osparc.dashboard.CardContainer.isValidCard(child)) {

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
324324
this._addToLayout(resourcesContainer);
325325
},
326326

327-
__groupByChanged: function(groupBy) {
327+
_groupByChanged: function(groupBy) {
328328
// if cards are grouped they need to be in grid mode
329329
this._resourcesContainer.setMode("grid");
330330
this.__viewModeLayout.setVisibility(groupBy ? "excluded" : "visible");
@@ -356,27 +356,34 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", {
356356

357357
const dontGroup = new qx.ui.menu.RadioButton(this.tr("None"));
358358
osparc.utils.Utils.setIdToWidget(dontGroup, "groupByNone");
359-
dontGroup.addListener("execute", () => this.__groupByChanged(null));
359+
dontGroup.addListener("execute", () => this._groupByChanged(null));
360360

361361
groupByMenu.add(dontGroup);
362362
groupOptions.add(dontGroup);
363363

364364
if (this._resourceType === "template") {
365-
const tagByGroup = new qx.ui.menu.RadioButton(this.tr("Tags"));
366-
tagByGroup.addListener("execute", () => this.__groupByChanged("tags"));
367-
groupByMenu.add(tagByGroup);
368-
groupOptions.add(tagByGroup);
365+
const groupByTag = new qx.ui.menu.RadioButton(this.tr("Tags"));
366+
groupByTag.addListener("execute", () => this._groupByChanged("tags"));
367+
groupByMenu.add(groupByTag);
368+
groupOptions.add(groupByTag);
369369
if (
370370
osparc.product.Utils.isProduct("s4l") ||
371371
osparc.product.Utils.isProduct("s4lacad") ||
372372
osparc.product.Utils.isProduct("s4llite")
373373
) {
374-
tagByGroup.execute();
374+
groupByTag.execute();
375375
}
376+
} else if (this._resourceType === "service" && osparc.product.Utils.groupServices()) {
377+
const groupByFeatured = new qx.ui.menu.RadioButton(this.tr("Featured"));
378+
groupByFeatured.addListener("execute", () => this._groupByChanged("groupedServices"));
379+
groupByMenu.add(groupByFeatured);
380+
groupOptions.add(groupByFeatured);
381+
groupByFeatured.execute();
382+
groupByButton.exclude(); // don't let users change the grouping
376383
}
377384

378385
const groupByShared = new qx.ui.menu.RadioButton(this.tr("Shared with"));
379-
groupByShared.addListener("execute", () => this.__groupByChanged("shared"));
386+
groupByShared.addListener("execute", () => this._groupByChanged("shared"));
380387
groupByMenu.add(groupByShared);
381388
groupOptions.add(groupByShared);
382389

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

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
5858
},
5959

6060
groupBy: {
61-
check: [null, "tags", "shared"],
61+
check: [null, "tags", "shared", "groupedServices"],
6262
init: null,
6363
nullable: true
6464
}
@@ -309,8 +309,11 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
309309
case "shared":
310310
groupTitle = "Not Shared";
311311
break;
312+
case "groupedServices":
313+
groupTitle = "Misc";
314+
break;
312315
}
313-
const noGroupContainer = this.__createGroupContainer("no-group", groupTitle, "transparent");
316+
const noGroupContainer = this.__createGroupContainer("no-group", groupTitle, "text");
314317
this.__groupedContainers.add(noGroupContainer);
315318
this._add(this.__groupedContainers);
316319
} else {
@@ -525,12 +528,55 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
525528
}
526529
},
527530

531+
__groupByGroupedServices: function(cards, resourceData) {
532+
const groupedServicesConfig = osparc.store.Products.getInstance().getGroupedServicesUiConfig();
533+
if (groupedServicesConfig == null) {
534+
return;
535+
}
536+
537+
// create group containers for each category
538+
groupedServicesConfig["categories"].forEach(category => {
539+
if (this.__getGroupContainer(category["id"]) === null) {
540+
const groupContainer = this.__createGroupContainer(category["id"], category["title"], category["color"]);
541+
groupContainer.setHeaderIcon("@FontAwesome5Solid/tag/24");
542+
this.__groupedContainers.add(groupContainer);
543+
}
544+
});
545+
546+
// get the right container
547+
let container = null;
548+
const serviceKey = resourceData["key"];
549+
if (serviceKey) {
550+
const groupInfo = groupedServicesConfig["services"].find(serviceInfo => serviceInfo["serviceKey"] === serviceKey);
551+
if (groupInfo) {
552+
container = this.__getGroupContainer(groupInfo["category"]);
553+
}
554+
}
555+
if (container === null) {
556+
container = this.__getGroupContainer("no-group");
557+
container.setHeaderIcon("@FontAwesome5Solid/tag/24");
558+
}
559+
560+
// create the card and add it to the container
561+
const card = this.__createCard(resourceData);
562+
this.__addCardToContainer(card, container);
563+
cards.push(card);
564+
565+
this.__moveNoGroupToLast();
566+
this.__groupedContainersList.forEach(groupedContainer => {
567+
groupedContainer.setExpanded(true);
568+
groupedContainer.getExpandButton().exclude();
569+
});
570+
},
571+
528572
__resourceToCards: function(resourceData) {
529573
const cardsCreated = [];
530574
if (this.getGroupBy() === "tags") {
531575
this.__groupByTags(cardsCreated, resourceData);
532576
} else if (this.getGroupBy() === "shared") {
533577
this.__groupByShareWith(cardsCreated, resourceData);
578+
} else if (this.getGroupBy() === "groupedServices") {
579+
this.__groupByGroupedServices(cardsCreated, resourceData);
534580
} else {
535581
const card = this.__createCard(resourceData);
536582
this.__addCardToContainer(card, this.__nonGroupedContainer);

services/static-webserver/client/source/class/osparc/product/Utils.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,5 +380,9 @@ qx.Class.define("osparc.product.Utils", {
380380
hasNewPlusButton: function() {
381381
return Boolean(osparc.store.Products.getInstance().getPlusButtonUiConfig());
382382
},
383+
384+
groupServices: function() {
385+
return Boolean(osparc.store.Products.getInstance().getGroupedServicesUiConfig());
386+
},
383387
}
384388
});

services/static-webserver/client/source/class/osparc/store/Products.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,9 @@ qx.Class.define("osparc.store.Products", {
9292
getNewStudiesUiConfig: function() {
9393
return this.__uiConfig["newStudies"];
9494
},
95+
96+
getGroupedServicesUiConfig: function() {
97+
return this.__uiConfig["groupedServices"];
98+
},
9599
}
96100
});

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,32 @@
120120
"newStudyLabel": "New Pipeline",
121121
"idToWidget": "emptyStudyBtn"
122122
}]
123+
},
124+
"groupedServices": {
125+
"categories": [{
126+
"id": "featured",
127+
"title": "Featured",
128+
"color": "product-color"
129+
}],
130+
"services": [{
131+
"serviceKey": "simcore/services/dynamic/s4l-ui",
132+
"category": "featured"
133+
}, {
134+
"serviceKey": "simcore/services/dynamic/s4l-jupyter",
135+
"category": "featured"
136+
}, {
137+
"serviceKey": "simcore/services/dynamic/iseg-web",
138+
"category": "featured"
139+
}, {
140+
"serviceKey": "simcore/services/dynamic/s4l-ui-framework",
141+
"category": "featured"
142+
}, {
143+
"serviceKey": "simcore/services/comp/s4l-python-runner",
144+
"category": "featured"
145+
}, {
146+
"serviceKey": "simcore/services/comp/s4l-python-runner-gpu",
147+
"category": "featured"
148+
}]
123149
}
124150
},
125151
"s4lacad": {
@@ -146,6 +172,32 @@
146172
"newStudyLabel": "New Pipeline",
147173
"idToWidget": "emptyStudyBtn"
148174
}]
175+
},
176+
"groupedServices": {
177+
"categories": [{
178+
"id": "featured",
179+
"title": "Featured",
180+
"color": "product-color"
181+
}],
182+
"services": [{
183+
"serviceKey": "simcore/services/dynamic/s4l-ui",
184+
"category": "featured"
185+
}, {
186+
"serviceKey": "simcore/services/dynamic/s4l-jupyter",
187+
"category": "featured"
188+
}, {
189+
"serviceKey": "simcore/services/dynamic/iseg-web",
190+
"category": "featured"
191+
}, {
192+
"serviceKey": "simcore/services/dynamic/s4l-ui-framework",
193+
"category": "featured"
194+
}, {
195+
"serviceKey": "simcore/services/comp/s4l-python-runner",
196+
"category": "featured"
197+
}, {
198+
"serviceKey": "simcore/services/comp/s4l-python-runner-gpu",
199+
"category": "featured"
200+
}]
149201
}
150202
},
151203
"s4llite": {

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
},
88
"newStudies": {
99
"$ref": "#/definitions/buttonConfig"
10+
},
11+
"groupedServices": {
12+
"$ref": "#/definitions/groupedServicesConfig"
1013
}
1114
},
1215
"additionalProperties": false,
@@ -92,6 +95,34 @@
9295
}
9396
},
9497
"additionalProperties": false
98+
},
99+
"groupedServicesConfig": {
100+
"type": "object",
101+
"properties": {
102+
"categories": {
103+
"type": "array",
104+
"items": {
105+
"type": "object",
106+
"properties": {
107+
"id": { "type": "string" },
108+
"title": { "type": "string" },
109+
"description": { "type": "string" }
110+
},
111+
"required": ["id", "title"]
112+
}
113+
},
114+
"services": {
115+
"type": "array",
116+
"items": {
117+
"type": "object",
118+
"properties": {
119+
"serviceKey": { "type": "string" },
120+
"category": { "type": "string" }
121+
},
122+
"required": ["serviceKey", "category"]
123+
}
124+
}
125+
}
95126
}
96127
}
97128
}

0 commit comments

Comments
 (0)