Skip to content

Commit fdd64ed

Browse files
authored
♻️✨ ViP Store: Licensed Item model and Cache (#7261)
1 parent 7526a43 commit fdd64ed

File tree

16 files changed

+486
-183
lines changed

16 files changed

+486
-183
lines changed

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,15 +248,17 @@ qx.Class.define("osparc.dashboard.ResourceContainerManager", {
248248
container.add(card);
249249

250250
if (this.getMode() === "list") {
251+
const fitToContainer = () => {
252+
const bounds = container.getBounds() || container.getSizeHint();
253+
card.setWidth(bounds.width);
254+
};
251255
[
252256
"appear",
253257
"resize",
254258
].forEach(ev => {
255-
container.addListener(ev, () => {
256-
const bounds = container.getBounds() || container.getSizeHint();
257-
card.setWidth(bounds.width);
258-
});
259+
container.addListener(ev, () => fitToContainer());
259260
});
261+
fitToContainer();
260262
}
261263
},
262264

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

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,13 +234,15 @@ qx.Class.define("osparc.dashboard.StudyBrowserHeader", {
234234
},
235235

236236
__titleTapped: function() {
237-
const workspaceId = this.getCurrentWorkspaceId();
238-
const folderId = null;
239-
this.setCurrentFolderId(folderId);
240-
this.fireDataEvent("locationChanged", {
241-
workspaceId,
242-
folderId,
243-
});
237+
if (osparc.store.Store.getInstance().getStudyBrowserContext() === "studiesAndFolders") {
238+
const workspaceId = this.getCurrentWorkspaceId();
239+
const folderId = null;
240+
this.setCurrentFolderId(folderId);
241+
this.fireDataEvent("locationChanged", {
242+
workspaceId,
243+
folderId,
244+
});
245+
}
244246
},
245247

246248
__buildLayout: function() {
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.data.model.LicensedItem", {
19+
extend: qx.core.Object,
20+
21+
/**
22+
* @param licensedItemData {Object} Object containing the serialized LicensedItem Data
23+
*/
24+
construct: function(licensedItemData) {
25+
this.base(arguments);
26+
27+
let thumbnail = "";
28+
let date = null;
29+
let licensedResources = [];
30+
if (licensedItemData["licensedResources"]) {
31+
if (licensedItemData["licensedResources"].length) {
32+
const firstItem = licensedItemData["licensedResources"][0]["source"];
33+
if (firstItem["thumbnail"]) {
34+
thumbnail = firstItem["thumbnail"];
35+
}
36+
if (firstItem["features"] && firstItem["features"]["date"]) {
37+
date = firstItem["features"]["date"];
38+
}
39+
}
40+
licensedItemData["licensedResources"].forEach(licensedRsrc => {
41+
const licensedItemResource = new osparc.data.model.LicensedItemResource(licensedRsrc["source"]);
42+
if (licensedItemData["termsOfUseUrl"]) {
43+
licensedItemResource.set({
44+
termsOfUseUrl: licensedItemData["termsOfUseUrl"],
45+
})
46+
}
47+
licensedResources.push(licensedItemResource);
48+
});
49+
}
50+
let categoryIcon = "@FontAwesome5Solid/shopping-bag/20";
51+
if (licensedItemData.categoryIcon) {
52+
categoryIcon = licensedItemData.categoryIcon;
53+
} else if (qx.util.ResourceManager.getInstance().has(`osparc/market/${licensedItemData.categoryId}.svg`)) {
54+
categoryIcon = `osparc/market/${licensedItemData.categoryId}.svg`;
55+
}
56+
57+
this.set({
58+
licensedItemId: licensedItemData.licensedItemId,
59+
categoryId: licensedItemData.categoryId,
60+
categoryDisplay: licensedItemData.categoryDisplay,
61+
categoryIcon: categoryIcon,
62+
pricingPlanId: licensedItemData.pricingPlanId,
63+
key: licensedItemData.key,
64+
version: licensedItemData.version,
65+
thumbnail: thumbnail,
66+
displayName: licensedItemData.displayName,
67+
date: new Date(date),
68+
licensedResources: licensedResources,
69+
seats: licensedItemData.seats || [],
70+
});
71+
},
72+
73+
properties: {
74+
licensedItemId: {
75+
check: "String",
76+
nullable: false,
77+
init: null,
78+
event: "changeLicensedItemId",
79+
},
80+
81+
categoryId: {
82+
check: "String",
83+
nullable: true,
84+
init: null,
85+
event: "changeCategoryId",
86+
},
87+
88+
categoryDisplay: {
89+
check: "String",
90+
nullable: true,
91+
init: null,
92+
event: "changeCategoryDisplay",
93+
},
94+
95+
categoryIcon: {
96+
check: "String",
97+
nullable: true,
98+
init: null,
99+
event: "changeCategoryIcon",
100+
},
101+
102+
pricingPlanId: {
103+
check: "Number",
104+
nullable: false,
105+
init: null,
106+
event: "changePricingPlanId",
107+
},
108+
109+
key: {
110+
check: "String",
111+
nullable: false,
112+
init: null,
113+
event: "changeKey",
114+
},
115+
116+
version: {
117+
check: "String",
118+
nullable: false,
119+
init: null,
120+
event: "changeVersion",
121+
},
122+
123+
thumbnail: {
124+
check: "String",
125+
nullable: true,
126+
init: null,
127+
event: "changeThumbnail",
128+
},
129+
130+
displayName: {
131+
check: "String",
132+
nullable: false,
133+
init: null,
134+
event: "changeDisplayName",
135+
},
136+
137+
date: {
138+
check: "Date",
139+
nullable: false,
140+
init: null,
141+
event: "changeDate",
142+
},
143+
144+
licensedResources: {
145+
check: "Array",
146+
nullable: false,
147+
init: [],
148+
event: "changeLicensedResources",
149+
},
150+
151+
seats: {
152+
check: "Array",
153+
nullable: false,
154+
init: [],
155+
event: "changeSeats",
156+
},
157+
},
158+
159+
statics: {
160+
addSeatsFromPurchases: function(licensedItems, purchases) {
161+
// reset seats
162+
Object.values(licensedItems).forEach(licensedItem => licensedItem.setSeats([]));
163+
// populate seats
164+
purchases.forEach(purchase => {
165+
const {
166+
key,
167+
version,
168+
} = purchase;
169+
Object.values(licensedItems).forEach(licensedItem => {
170+
if (licensedItem.getKey() === key && licensedItem.getVersion() <= version) {
171+
licensedItem.getSeats().push({
172+
licensedItemId: purchase["licensedItemId"],
173+
licensedItemPurchaseId: purchase["licensedItemPurchaseId"],
174+
numOfSeats: purchase["numOfSeats"],
175+
expireAt: new Date(purchase["expireAt"]),
176+
});
177+
}
178+
});
179+
})
180+
},
181+
},
182+
183+
members: {
184+
}
185+
});
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/* ************************************************************************
2+
3+
osparc - the simcore frontend
4+
5+
https://osparc.io
6+
7+
Copyright:
8+
2025 IT'IS Foundation, https://itis.swiss
9+
10+
License:
11+
MIT: https://opensource.org/licenses/MIT
12+
13+
Authors:
14+
* Odei Maiz (odeimaiz)
15+
16+
************************************************************************ */
17+
18+
qx.Class.define("osparc.data.model.LicensedItemResource", {
19+
extend: qx.core.Object,
20+
21+
/**
22+
* @param licensedItemResourceData {Object} Object containing the serialized LicensedItem Data
23+
*/
24+
construct: function(licensedItemResourceData) {
25+
this.base(arguments);
26+
27+
let description = licensedItemResourceData["description"] || "";
28+
let title = "";
29+
let subtitle = null;
30+
description = description.replace(/SPEAG/g, " "); // remove SPEAG substring
31+
const delimiter = " - ";
32+
let titleAndSubtitle = description.split(delimiter);
33+
if (titleAndSubtitle.length > 0) {
34+
title = titleAndSubtitle[0];
35+
titleAndSubtitle.shift();
36+
}
37+
if (titleAndSubtitle.length > 0) {
38+
subtitle = titleAndSubtitle.join(delimiter);
39+
}
40+
41+
const manufacturerData = {};
42+
if (licensedItemResourceData["thumbnail"]) {
43+
if (licensedItemResourceData["thumbnail"].includes("itis.swiss")) {
44+
manufacturerData["label"] = "IT'IS Foundation";
45+
manufacturerData["link"] = "https://itis.swiss/virtual-population/";
46+
manufacturerData["icon"] = "https://media.licdn.com/dms/image/v2/C4D0BAQE_FGa66IyvrQ/company-logo_200_200/company-logo_200_200/0/1631341490431?e=2147483647&v=beta&t=7f_IK-ArGjPrz-1xuWolAT4S2NdaVH-e_qa8hsKRaAc";
47+
} else if (licensedItemResourceData["thumbnail"].includes("speag.swiss")) {
48+
manufacturerData["label"] = "Speag";
49+
manufacturerData["link"] = "https://speag.swiss/products/em-phantoms/overview-2/";
50+
manufacturerData["icon"] = "https://media.licdn.com/dms/image/v2/D4E0BAQG2CYG28KAKbA/company-logo_200_200/company-logo_200_200/0/1700045977122/schmid__partner_engineering_ag_logo?e=2147483647&v=beta&t=6CZb1jjg5TnnzQWkrZBS9R3ebRKesdflg-_xYi4dwD8";
51+
}
52+
}
53+
54+
this.set({
55+
description: description,
56+
title: title,
57+
subtitle: subtitle,
58+
thumbnail: licensedItemResourceData.thumbnail || "",
59+
features: licensedItemResourceData.features || {},
60+
doi: licensedItemResourceData.doi || null,
61+
termsOfUseUrl: licensedItemResourceData.termsOfUseUrl || null,
62+
manufacturerLabel: manufacturerData.label || null,
63+
manufacturerLink: manufacturerData.link || null,
64+
manufacturerIcon: manufacturerData.icon || null,
65+
});
66+
},
67+
68+
properties: {
69+
description: {
70+
check: "String",
71+
nullable: false,
72+
init: null,
73+
event: "changeDescription",
74+
},
75+
76+
title: {
77+
check: "String",
78+
nullable: false,
79+
init: null,
80+
event: "changeTitle",
81+
},
82+
83+
subtitle: {
84+
check: "String",
85+
nullable: true,
86+
init: null,
87+
event: "changeSubtitle",
88+
},
89+
90+
thumbnail: {
91+
check: "String",
92+
nullable: false,
93+
init: null,
94+
event: "changeThumbnail",
95+
},
96+
97+
features: {
98+
check: "Object",
99+
nullable: false,
100+
init: null,
101+
event: "changeFeatures",
102+
},
103+
104+
doi: {
105+
check: "String",
106+
nullable: true,
107+
init: null,
108+
event: "changeDoi",
109+
},
110+
111+
termsOfUseUrl: {
112+
check: "String",
113+
nullable: true,
114+
init: null,
115+
event: "changeTermsOfUseUrl",
116+
},
117+
118+
manufacturerLabel: {
119+
check: "String",
120+
nullable: true,
121+
init: null,
122+
event: "changeManufacturerLabel",
123+
},
124+
125+
manufacturerLink: {
126+
check: "String",
127+
nullable: true,
128+
init: null,
129+
event: "changeManufacturerLink",
130+
},
131+
132+
manufacturerIcon: {
133+
check: "String",
134+
nullable: true,
135+
init: null,
136+
event: "changeManufacturerIcon",
137+
},
138+
},
139+
140+
statics: {
141+
longName: function(licensedResource) {
142+
const name = licensedResource.getFeatures()["name"] || licensedResource.getSubtitle();
143+
const version = licensedResource.getFeatures()["version"] || "";
144+
const functionality = licensedResource.getFeatures()["functionality"] || "Static";
145+
return `${name} ${version}, ${functionality}`;
146+
},
147+
},
148+
149+
members: {
150+
}
151+
});

0 commit comments

Comments
 (0)