diff --git a/services/docker-compose.local.yml b/services/docker-compose.local.yml
index 62856f04083..8031d7a4523 100644
--- a/services/docker-compose.local.yml
+++ b/services/docker-compose.local.yml
@@ -260,4 +260,4 @@ services:
networks:
docker-api-network:
driver_opts:
- encrypted: "false" # disable locally, some WSL versions have issues with encrypted networks SEE https://github.com/microsoft/WSL/issues/10029
+ {} # override 'encrypted' locally, some WSL versions have issues with encrypted networks SEE https://github.com/microsoft/WSL/issues/10029
diff --git a/services/static-webserver/client/source/class/osparc/store/LicensedItems.js b/services/static-webserver/client/source/class/osparc/store/LicensedItems.js
index 8331e95bb8c..16fd69b77f9 100644
--- a/services/static-webserver/client/source/class/osparc/store/LicensedItems.js
+++ b/services/static-webserver/client/source/class/osparc/store/LicensedItems.js
@@ -72,8 +72,9 @@ qx.Class.define("osparc.store.LicensedItems", {
licensedResourceTitle: function(licensedResource) {
const name = licensedResource["source"]["features"]["name"] || osparc.store.LicensedItems.extractNameFromDescription(licensedResource);
+ const version = licensedResource["source"]["features"]["version"] || "";
const functionality = licensedResource["source"]["features"]["functionality"] || "Static";
- return `${name}, ${functionality}`;
+ return `${name} ${version}, ${functionality}`;
},
extractNameFromDescription: function(licensedResource) {
diff --git a/services/static-webserver/client/source/class/osparc/study/PricingUnitLicense.js b/services/static-webserver/client/source/class/osparc/study/PricingUnitLicense.js
index 00db92b60e1..5e79a87c044 100644
--- a/services/static-webserver/client/source/class/osparc/study/PricingUnitLicense.js
+++ b/services/static-webserver/client/source/class/osparc/study/PricingUnitLicense.js
@@ -74,7 +74,7 @@ qx.Class.define("osparc.study.PricingUnitLicense", {
// add price info
const price = this.getChildControl("price");
pricingUnit.bind("cost", price, "value", {
- converter: v => this.tr("Credits") + ": " + v
+ converter: v => this.tr("Credits") + ": " + osparc.utils.Utils.addWhiteSpaces(v)
});
// add edit button
diff --git a/services/static-webserver/client/source/class/osparc/utils/Utils.js b/services/static-webserver/client/source/class/osparc/utils/Utils.js
index 942356acbb3..b0b77bfcafd 100644
--- a/services/static-webserver/client/source/class/osparc/utils/Utils.js
+++ b/services/static-webserver/client/source/class/osparc/utils/Utils.js
@@ -91,6 +91,10 @@ qx.Class.define("osparc.utils.Utils", {
FLOATING_Z_INDEX: 1000001 + 1,
+ addWhiteSpaces: function(integer) {
+ return new Intl.NumberFormat("fr-FR").format(integer); // french will add white spaces every 3 digits
+ },
+
updateTabName: function(name) {
document.title = name;
},
diff --git a/services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelDetails.js b/services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelDetails.js
index f4b53ae5c6b..5a90bd2d46d 100644
--- a/services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelDetails.js
+++ b/services/static-webserver/client/source/class/osparc/vipMarket/AnatomicalModelDetails.js
@@ -65,7 +65,7 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
},
members: {
- __selectedModelLayout: null,
+ __modelsInfoStack: null,
__populateLayout: function() {
this._removeAll();
@@ -91,8 +91,13 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
__addModelsInfo: function() {
const modelBundleLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6));
- this.__selectedModelLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6));
- modelBundleLayout.add(this.__selectedModelLayout);
+ const stack = this.__modelsInfoStack = new qx.ui.container.Stack();
+ this._add(stack, {
+ flex: 1
+ });
+ modelBundleLayout.add(this.__modelsInfoStack);
+
+ this.__populateModelsInfo();
const licensedItemBundleData = this.getAnatomicalModelsData();
const modelsInfo = licensedItemBundleData["licensedResources"];
@@ -102,8 +107,12 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
modelSelectionLayout.add(titleLabel);
const modelsLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(4));
modelSelectionLayout.add(modelsLayout);
- const thumbnailTapped = idx => {
- this.__populateSelectedModelInfo(idx);
+
+ const modelSelected = idx => {
+ if (this.__modelsInfoStack.getSelectables().length > idx) {
+ this.__modelsInfoStack.setSelection([stack.getSelectables()[idx]]);
+ }
+
const selectedBorderColor = qx.theme.manager.Color.getInstance().resolve("strong-main");
const unselectedBorderColor = "transparent";
modelsLayout.getChildren().forEach((thumbnailAndTitle, index) => {
@@ -111,209 +120,217 @@ qx.Class.define("osparc.vipMarket.AnatomicalModelDetails", {
osparc.utils.Utils.updateBorderColor(thumbnail, index === idx ? selectedBorderColor : unselectedBorderColor);
});
}
+
modelsInfo.forEach((modelInfo, idx) => {
- const modelLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(4));
+ const modelLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(4)).set({
+ allowGrowX: false,
+ });
const miniThumbnail = this.self().createThumbnail(modelInfo["source"]["thumbnail"], 32);
osparc.utils.Utils.addBorder(miniThumbnail);
modelLayout.add(miniThumbnail);
- miniThumbnail.addListener("tap", () => thumbnailTapped(idx));
const title = new qx.ui.basic.Label().set({
value: osparc.store.LicensedItems.licensedResourceTitle(modelInfo),
alignY: "middle"
});
modelLayout.add(title);
+ modelLayout.setCursor("pointer");
+ modelLayout.addListener("tap", () => modelSelected(idx));
modelsLayout.add(modelLayout);
});
modelBundleLayout.add(modelSelectionLayout);
- thumbnailTapped(0);
- this.__populateSelectedModelInfo();
- } else {
- this.__populateSelectedModelInfo();
+ modelSelected(0);
}
this._add(modelBundleLayout);
},
- __populateSelectedModelInfo: function(selectedIdx = 0) {
- this.__selectedModelLayout.removeAll();
+ __populateModelsInfo: function() {
+ this.__modelsInfoStack.removeAll();
const licensedItemBundleData = this.getAnatomicalModelsData();
-
- const topGrid = new qx.ui.layout.Grid(8, 6);
- topGrid.setColumnFlex(0, 1);
- const headerLayout = new qx.ui.container.Composite(topGrid);
- const anatomicalModel = licensedItemBundleData["licensedResources"][selectedIdx]["source"];
- let description = anatomicalModel["description"] || "";
- description = description.replace(/SPEAG/g, " "); // remove SPEAG substring
- const delimiter = " - ";
- let titleAndSubtitle = description.split(delimiter);
- if (titleAndSubtitle.length > 0) {
- const titleLabel = new qx.ui.basic.Label().set({
- value: titleAndSubtitle[0],
- font: "text-16",
- alignY: "middle",
- allowGrowX: true,
- allowGrowY: true,
- });
- headerLayout.add(titleLabel, {
- column: 0,
- row: 0,
- });
- titleAndSubtitle.shift();
- }
- if (titleAndSubtitle.length > 0) {
- titleAndSubtitle = titleAndSubtitle.join(delimiter);
- const subtitleLabel = new qx.ui.basic.Label().set({
- value: titleAndSubtitle,
- font: "text-16",
- alignY: "middle",
- allowGrowX: true,
- allowGrowY: true,
- });
- headerLayout.add(subtitleLabel, {
- column: 0,
- row: 1,
- });
- }
- if (anatomicalModel["thumbnail"]) {
- const manufacturerData = {};
- if (anatomicalModel["thumbnail"].includes("itis.swiss")) {
- manufacturerData["label"] = "IT'IS Foundation";
- manufacturerData["link"] = "https://itis.swiss/virtual-population/";
- 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";
- } else if (anatomicalModel["thumbnail"].includes("speag.swiss")) {
- manufacturerData["label"] = "Speag";
- manufacturerData["link"] = "https://speag.swiss/products/em-phantoms/overview-2/";
- 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";
- }
- if (Object.keys(manufacturerData).length) {
- const manufacturerLink = new qx.ui.basic.Atom().set({
- label: manufacturerData["label"],
- icon: manufacturerData["icon"],
+ const modelsInfo = licensedItemBundleData["licensedResources"];
+ modelsInfo.forEach((modelInfo, index) => {
+ const modelInfoLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(4));
+
+ const anatomicalModel = modelInfo["source"];
+
+ const topGrid = new qx.ui.layout.Grid(8, 6);
+ topGrid.setColumnFlex(0, 1);
+ const headerLayout = new qx.ui.container.Composite(topGrid);
+ let description = anatomicalModel["description"] || "";
+ description = description.replace(/SPEAG/g, " "); // remove SPEAG substring
+ const delimiter = " - ";
+ let titleAndSubtitle = description.split(delimiter);
+ if (titleAndSubtitle.length > 0) {
+ const titleLabel = new qx.ui.basic.Label().set({
+ value: titleAndSubtitle[0],
font: "text-16",
- gap: 10,
- iconPosition: "right",
- cursor: "pointer",
- });
- manufacturerLink.getChildControl("icon").set({
- maxWidth: 32,
- maxHeight: 32,
- scale: true,
- decorator: "rounded",
+ alignY: "middle",
+ allowGrowX: true,
+ allowGrowY: true,
});
- manufacturerLink.addListener("tap", () => window.open(manufacturerData["link"]));
- headerLayout.add(manufacturerLink, {
- column: 1,
+ headerLayout.add(titleLabel, {
+ column: 0,
row: 0,
- rowSpan: 2,
});
+ titleAndSubtitle.shift();
}
- }
- this.__selectedModelLayout.add(headerLayout);
-
-
- const middleLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(16));
- const thumbnail = this.self().createThumbnail(anatomicalModel["thumbnail"], 256);
- middleLayout.add(thumbnail);
-
- const features = anatomicalModel["features"];
- const featuresGrid = new qx.ui.layout.Grid(8, 8);
- const featuresLayout = new qx.ui.container.Composite(featuresGrid);
- let idx = 0;
- [
- "Name",
- "Version",
- "Date",
- "Species",
- "Sex",
- "Age",
- "Weight",
- "Height",
- "Ethnicity",
- "Functionality",
- ].forEach(key => {
- if (key.toLowerCase() in features) {
- const titleLabel = new qx.ui.basic.Label().set({
- value: key,
+ if (titleAndSubtitle.length > 0) {
+ titleAndSubtitle = titleAndSubtitle.join(delimiter);
+ const subtitleLabel = new qx.ui.basic.Label().set({
+ value: titleAndSubtitle,
+ font: "text-16",
+ alignY: "middle",
+ allowGrowX: true,
+ allowGrowY: true,
+ });
+ headerLayout.add(subtitleLabel, {
+ column: 0,
+ row: 1,
+ });
+ }
+ if (anatomicalModel["thumbnail"]) {
+ const manufacturerData = {};
+ if (anatomicalModel["thumbnail"].includes("itis.swiss")) {
+ manufacturerData["label"] = "IT'IS Foundation";
+ manufacturerData["link"] = "https://itis.swiss/virtual-population/";
+ 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";
+ } else if (anatomicalModel["thumbnail"].includes("speag.swiss")) {
+ manufacturerData["label"] = "Speag";
+ manufacturerData["link"] = "https://speag.swiss/products/em-phantoms/overview-2/";
+ 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";
+ }
+ if (Object.keys(manufacturerData).length) {
+ const manufacturerLink = new qx.ui.basic.Atom().set({
+ label: manufacturerData["label"],
+ icon: manufacturerData["icon"],
+ font: "text-16",
+ gap: 10,
+ iconPosition: "right",
+ cursor: "pointer",
+ });
+ manufacturerLink.getChildControl("icon").set({
+ maxWidth: 32,
+ maxHeight: 32,
+ scale: true,
+ decorator: "rounded",
+ });
+ manufacturerLink.addListener("tap", () => window.open(manufacturerData["link"]));
+ headerLayout.add(manufacturerLink, {
+ column: 1,
+ row: 0,
+ rowSpan: 2,
+ });
+ }
+ }
+ modelInfoLayout.add(headerLayout);
+
+
+ const middleLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(16));
+ const thumbnail = this.self().createThumbnail(anatomicalModel["thumbnail"], 256);
+ middleLayout.add(thumbnail);
+
+ const features = anatomicalModel["features"];
+ const featuresGrid = new qx.ui.layout.Grid(8, 8);
+ const featuresLayout = new qx.ui.container.Composite(featuresGrid);
+ let idx = 0;
+ [
+ "Name",
+ "Version",
+ "Date",
+ "Species",
+ "Sex",
+ "Age",
+ "Weight",
+ "Height",
+ "Ethnicity",
+ "Functionality",
+ ].forEach(key => {
+ if (key.toLowerCase() in features) {
+ const titleLabel = new qx.ui.basic.Label().set({
+ value: key,
+ font: "text-14",
+ alignX: "right",
+ });
+ featuresLayout.add(titleLabel, {
+ column: 0,
+ row: idx,
+ });
+
+ const nameLabel = new qx.ui.basic.Label().set({
+ value: features[key.toLowerCase()],
+ font: "text-14",
+ alignX: "left",
+ });
+ featuresLayout.add(nameLabel, {
+ column: 1,
+ row: idx,
+ });
+
+ idx++;
+ }
+ });
+
+ if (anatomicalModel["doi"]) {
+ const doiTitle = new qx.ui.basic.Label().set({
+ value: "DOI",
font: "text-14",
alignX: "right",
+ marginTop: 10,
});
- featuresLayout.add(titleLabel, {
+ featuresLayout.add(doiTitle, {
column: 0,
row: idx,
});
- const nameLabel = new qx.ui.basic.Label().set({
- value: features[key.toLowerCase()],
- font: "text-14",
- alignX: "left",
- });
- featuresLayout.add(nameLabel, {
+ const doiToLink = doi => {
+ const doiLabel = new osparc.ui.basic.LinkLabel("-").set({
+ font: "text-14",
+ alignX: "left",
+ marginTop: 10,
+ });
+ if (doi) {
+ doiLabel.set({
+ value: doi,
+ url: "https://doi.org/" + doi,
+ font: "link-label-14",
+ });
+ }
+ return doiLabel;
+ };
+ featuresLayout.add(doiToLink(anatomicalModel["doi"]), {
column: 1,
row: idx,
});
-
idx++;
}
- });
-
- if (anatomicalModel["doi"]) {
- const doiTitle = new qx.ui.basic.Label().set({
- value: "DOI",
- font: "text-14",
- alignX: "right",
- marginTop: 10,
- });
- featuresLayout.add(doiTitle, {
- column: 0,
- row: idx,
- });
- const doiToLink = doi => {
- const doiLabel = new osparc.ui.basic.LinkLabel("-").set({
+ if (licensedItemBundleData["termsOfUseUrl"] || anatomicalModel["termsOfUseUrl"]) { // remove the first one when this info goes down to the model
+ const tAndC = new qx.ui.basic.Label().set({
font: "text-14",
- alignX: "left",
- marginTop: 10,
+ value: this.tr("Terms and Conditions"),
+ rich: true,
+ anonymous: false,
+ cursor: "pointer",
});
- if (doi) {
- doiLabel.set({
- value: doi,
- url: "https://doi.org/" + doi,
- font: "link-label-14",
- });
- }
- return doiLabel;
- };
- featuresLayout.add(doiToLink(anatomicalModel["doi"]), {
- column: 1,
- row: idx,
- });
- idx++;
- }
+ tAndC.addListener("tap", () => this.__openLicense(licensedItemBundleData["termsOfUseUrl"] || anatomicalModel["termsOfUseUrl"]));
+ featuresLayout.add(tAndC, {
+ column: 1,
+ row: idx,
+ });
+ idx++;
+ }
- if (licensedItemBundleData["termsOfUseUrl"] || anatomicalModel["termsOfUseUrl"]) { // remove the first one when this info goes down to the model
- const tAndC = new qx.ui.basic.Label().set({
- font: "text-14",
- value: this.tr("Terms and Conditions"),
- rich: true,
- anonymous: false,
- cursor: "pointer",
- });
- tAndC.addListener("tap", () => this.__openLicense(licensedItemBundleData["termsOfUseUrl"] || anatomicalModel["termsOfUseUrl"]));
- featuresLayout.add(tAndC, {
- column: 1,
- row: idx,
- });
- idx++;
- }
+ middleLayout.add(featuresLayout);
- middleLayout.add(featuresLayout);
+ modelInfoLayout.add(middleLayout);
- this.__selectedModelLayout.add(middleLayout);
+ const importSection = this.__createImportSection(licensedItemBundleData, index);
+ modelInfoLayout.add(importSection);
- const importSection = this.__createImportSection(licensedItemBundleData, selectedIdx);
- this.__selectedModelLayout.add(importSection);
+ this.__modelsInfoStack.add(modelInfoLayout);
+ })
},
__openLicense: function(rawLink) {
diff --git a/services/static-webserver/client/source/class/osparc/vipMarket/Market.js b/services/static-webserver/client/source/class/osparc/vipMarket/Market.js
index ec5f0d38e9a..4a85fece443 100644
--- a/services/static-webserver/client/source/class/osparc/vipMarket/Market.js
+++ b/services/static-webserver/client/source/class/osparc/vipMarket/Market.js
@@ -33,7 +33,8 @@ qx.Class.define("osparc.vipMarket.Market", {
return;
}
- this.__populateCategories(openCategory);
+ this.__reqOpenCategory = openCategory;
+ this.__populateCategories();
},
events: {
@@ -50,10 +51,11 @@ qx.Class.define("osparc.vipMarket.Market", {
},
members: {
+ __reqOpenCategory: null,
__myModelsCategoryMarket: null,
__myModelsCategoryButton: null,
- __populateCategories: function(openCategory) {
+ __populateCategories: function() {
const store = osparc.store.Store.getInstance();
const contextWallet = store.getContextWallet();
@@ -75,10 +77,11 @@ qx.Class.define("osparc.vipMarket.Market", {
items: [],
};
categories.push(availableCategory);
+ let openCategory = null;
licensedItems.forEach(licensedItem => {
if (licensedItem["seats"].length) {
availableCategory["items"].push(licensedItem);
- if (!openCategory) {
+ if (!this.__reqOpenCategory) {
openCategory = availableCategory["categoryId"];
}
}
@@ -124,6 +127,9 @@ qx.Class.define("osparc.vipMarket.Market", {
this.__freeItems.push(licensedItem);
}
}
+ if (!this.__reqOpenCategory && this.__freeItems.length) {
+ this.__openCategory("availableModels");
+ }
this.__repopulateMyModelsCategory();
});
},