From 0dcca8b8d35eb1450dd6f835df23424c2691fa08 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Thu, 20 Jun 2024 15:49:55 +0200 Subject: [PATCH 01/15] update form --- .../class/osparc/auth/ui/RequestAccount.js | 155 ++++++++++-------- 1 file changed, 87 insertions(+), 68 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/auth/ui/RequestAccount.js b/services/static-webserver/client/source/class/osparc/auth/ui/RequestAccount.js index d1f68963fcf..13b022b26d1 100644 --- a/services/static-webserver/client/source/class/osparc/auth/ui/RequestAccount.js +++ b/services/static-webserver/client/source/class/osparc/auth/ui/RequestAccount.js @@ -52,40 +52,48 @@ qx.Class.define("osparc.auth.ui.RequestAccount", { }); this._form.add(lastName, this.tr("Last Name"), null, "lastName"); + const email = new qx.ui.form.TextField().set({ required: true }); - if ( - osparc.product.Utils.isProduct("s4lacad") || - osparc.product.Utils.isProduct("s4ldesktopacad") - ) { - this._form.add(email, this.tr("University Email"), qx.util.Validate.email(), "email"); - } else { - this._form.add(email, this.tr("Email"), qx.util.Validate.email(), "email"); + switch (osparc.product.Utils.getProductName()) { + case "s4l": + case "tis": + this._form.add(email, this.tr("Email"), qx.util.Validate.email(), "email"); + break; + case "s4lacad": + case "s4ldesktopacad": + this._form.add(email, this.tr("University Email"), qx.util.Validate.email(), "email"); + break; } const phone = new qx.ui.form.TextField(); this._form.add(phone, this.tr("Phone Number"), null, "phone"); - if ( - osparc.product.Utils.isProduct("s4lacad") || - osparc.product.Utils.isProduct("s4ldesktopacad") - ) { - const university = new qx.ui.form.TextField(); - doubleSpaced.push(university); - this._form.add(university, this.tr("University"), null, "university"); - } else { - const company = new qx.ui.form.TextField(); - doubleSpaced.push(company); - this._form.add(company, this.tr("Company Name"), null, "company"); + + const organization = new qx.ui.form.TextField(); + doubleSpaced.push(organization); + switch (osparc.product.Utils.getProductName()) { + case "s4l": + this._form.add(organization, this.tr("Company Name"), null, "company"); + break; + case "s4lacad": + case "s4ldesktopacad": + this._form.add(organization, this.tr("University"), null, "university"); + break; + case "tis": + this._form.add(organization, this.tr("Organization"), null, "organization"); + break; } + const address = new qx.ui.form.TextField().set({ required: true }); doubleSpaced.push(address); this._form.add(address, this.tr("Address"), null, "address"); + const city = new qx.ui.form.TextField().set({ required: true }); @@ -96,6 +104,7 @@ qx.Class.define("osparc.auth.ui.RequestAccount", { }); this._form.add(postalCode, this.tr("Postal code"), null, "postalCode"); + const country = new qx.ui.form.SelectBox().set({ required: true }); @@ -117,58 +126,67 @@ qx.Class.define("osparc.auth.ui.RequestAccount", { }); this._form.add(country, this.tr("Country"), null, "country"); - const application = new qx.ui.form.SelectBox(); - [{ - id: "Antenna_Design_for_Wireless_Communication", - label: "Antenna Design for Wireless Communication" - }, { - id: "Bioelectronics,_Electroceuticals_and_Neuroprosthetics", - label: "Bioelectronics, Electroceuticals & Neuroprosthetics" - }, { - id: "Safety_and_Efficacy_Assessment", - label: "Safety & Efficacy Assessment" - }, { - id: "Exposure_and_Compliance", - label: "Exposure & Compliance" - }, { - id: "Focused_Ultrasound", - label: "Focused Ultrasound" - }, { - id: "In_Silico_Trials", - label: "In Silico Trials" - }, { - id: "Implant_Design", - label: "Implant Design" - }, { - id: "Magnetic_Resonance_Imaging", - label: "Magnetic Resonance Imaging" - }, { - id: "Neurostimulation", - label: "Neurostimulation" - }, { - id: "Personalized_Medicine", - label: "Personalized Medicine" - }, { - id: "Thermal_Therapies", - label: "Thermal Therapies" - }, { - id: "Wireless_Power_Transfer_Systems", - label: "Wireless Power Transfer Systems" - }, { - id: "Vascular_Flow_and_Perfusion", - label: "Vascular Flow & Perfusion" - }].forEach(appData => { - const lItem = new qx.ui.form.ListItem(appData.label, null, appData.id).set({ - rich: true + + if ( + osparc.product.Utils.isProduct("s4l") || + osparc.product.Utils.isProduct("s4lacad") || + osparc.product.Utils.isProduct("s4ldesktopacad") + ) { + const application = new qx.ui.form.SelectBox(); + [{ + id: "Antenna_Design_for_Wireless_Communication", + label: "Antenna Design for Wireless Communication" + }, { + id: "Bioelectronics,_Electroceuticals_and_Neuroprosthetics", + label: "Bioelectronics, Electroceuticals & Neuroprosthetics" + }, { + id: "Safety_and_Efficacy_Assessment", + label: "Safety & Efficacy Assessment" + }, { + id: "Exposure_and_Compliance", + label: "Exposure & Compliance" + }, { + id: "Focused_Ultrasound", + label: "Focused Ultrasound" + }, { + id: "In_Silico_Trials", + label: "In Silico Trials" + }, { + id: "Implant_Design", + label: "Implant Design" + }, { + id: "Magnetic_Resonance_Imaging", + label: "Magnetic Resonance Imaging" + }, { + id: "Neurostimulation", + label: "Neurostimulation" + }, { + id: "Personalized_Medicine", + label: "Personalized Medicine" + }, { + id: "Thermal_Therapies", + label: "Thermal Therapies" + }, { + id: "Wireless_Power_Transfer_Systems", + label: "Wireless Power Transfer Systems" + }, { + id: "Vascular_Flow_and_Perfusion", + label: "Vascular Flow & Perfusion" + }].forEach(appData => { + const lItem = new qx.ui.form.ListItem(appData.label, null, appData.id).set({ + rich: true + }); + application.add(lItem); }); - application.add(lItem); - }); - doubleSpaced.push(application); - this._form.add(application, this.tr("Application"), null, "application"); + doubleSpaced.push(application); + this._form.add(application, this.tr("Application"), null, "application"); + + + const description = new qx.ui.form.TextField(); + doubleSpaced.push(description); + this._form.add(description, this.tr("Description"), null, "description"); + } - const description = new qx.ui.form.TextField(); - doubleSpaced.push(description); - this._form.add(description, this.tr("Description"), null, "description"); const hear = new qx.ui.form.SelectBox(); [{ @@ -193,6 +211,7 @@ qx.Class.define("osparc.auth.ui.RequestAccount", { doubleSpaced.push(hear); this._form.add(hear, this.tr("How did you hear about us?"), null, "hear"); + // accept links // Privacy Policy link let ppLink = osparc.CookiePolicy.getS4LPrivacyPolicyLink("our privacy policy"); From 7b1c4e95f42955395eccd542328dbea0c8467fa5 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Thu, 20 Jun 2024 16:11:19 +0200 Subject: [PATCH 02/15] powered by sim4life --- .../source/class/osparc/auth/ui/LoginView.js | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/services/static-webserver/client/source/class/osparc/auth/ui/LoginView.js b/services/static-webserver/client/source/class/osparc/auth/ui/LoginView.js index 404e7e1b3cd..c3ce4587b27 100644 --- a/services/static-webserver/client/source/class/osparc/auth/ui/LoginView.js +++ b/services/static-webserver/client/source/class/osparc/auth/ui/LoginView.js @@ -132,6 +132,28 @@ qx.Class.define("osparc.auth.ui.LoginView", { `; const disclaimer = osparc.announcement.AnnouncementUIFactory.createLoginAnnouncement(this.tr("Disclaimer"), text); this.add(disclaimer); + + this.add(new qx.ui.core.Spacer(), { + flex: 1 + }); + + const poweredByLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox()).set({ + alignX: "center", + allowGrowX: false, + cursor: "pointer" + }); + poweredByLayout.addListener("tap", () => window.open("https://sim4life.swiss/")); + const label = new qx.ui.basic.Label(this.tr("powered by")); + poweredByLayout.add(label); + const s4lLogo = new qx.ui.basic.Image("osparc/Sim4Life_full_logo_white.svg"); + s4lLogo.set({ + width: osparc.auth.LoginPage.LOGO_WIDTH/2, + height: osparc.auth.LoginPage.LOGO_HEIGHT/2, + scale: true, + alignX: "center" + }); + poweredByLayout.add(s4lLogo); + this.add(poweredByLayout); } }, From 1ddc18b50dc7660952ef417137e90cb6e62867ee Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Thu, 20 Jun 2024 16:18:36 +0200 Subject: [PATCH 03/15] minor --- .../client/source/class/osparc/dashboard/GridButtonBase.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js index e29291e8715..61292dd7171 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/GridButtonBase.js @@ -48,6 +48,7 @@ qx.Class.define("osparc.dashboard.GridButtonBase", { SPACING: 15, // TITLE_MAX_HEIGHT: 34, // two lines in Roboto TITLE_MAX_HEIGHT: 40, // two lines in Manrope + ICON_SIZE: 50, POS: { TITLE: { row: 0, @@ -287,7 +288,7 @@ qx.Class.define("osparc.dashboard.GridButtonBase", { // overridden _applyIcon: function(value, old) { if (value.includes("@FontAwesome5Solid/")) { - value += "50"; + value += this.self().ICON_SIZE; const image = this.getChildControl("icon").getChildControl("image"); image.set({ source: value From 627eb6a123b977f42c8f2ae97477846076cefc33 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 09:11:45 +0200 Subject: [PATCH 04/15] billable plus icons --- .../client/source/class/osparc/dashboard/NewStudies.js | 10 ++++++++++ .../source/class/osparc/desktop/credits/Utils.js | 1 + .../client/source/resource/osparc/new_studies.json | 9 ++++++--- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js index 9651b75189b..e854dbb806f 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js @@ -143,6 +143,16 @@ qx.Class.define("osparc.dashboard.NewStudies", { const title = templateInfo.title; const desc = templateInfo.description; const newPlanButton = new osparc.dashboard.GridButtonNew(title, desc); + if (templateInfo.billable) { + newPlanButton.setIcon(osparc.desktop.credits.Utils.CREDITS_ICON); + const store = osparc.store.Store.getInstance(); + const contextWallet = store.getContextWallet(); + if (contextWallet) { + const credits = contextWallet.getCreditsAvailable(); + const creditsColor = osparc.desktop.credits.Utils.creditsToColor(credits, "strong-main"); + newPlanButton.setTextColor(creditsColor); + } + } newPlanButton.setCardKey(templateInfo.idToWidget); osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget); newPlanButton.addListener("execute", () => this.fireDataEvent("newStudyClicked", templateInfo)) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js index 3a207e6c6b6..e05d53427da 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js @@ -20,6 +20,7 @@ qx.Class.define("osparc.desktop.credits.Utils", { statics: { DANGER_ZONE: 25, // one hour consumption + CREDITS_ICON: "@FontAwesome5Solid/database/", areWalletsEnabled: function() { const statics = osparc.store.Store.getInstance().get("statics"); diff --git a/services/static-webserver/client/source/resource/osparc/new_studies.json b/services/static-webserver/client/source/resource/osparc/new_studies.json index 14c6ffd45bd..3123f2ae328 100644 --- a/services/static-webserver/client/source/resource/osparc/new_studies.json +++ b/services/static-webserver/client/source/resource/osparc/new_studies.json @@ -28,21 +28,24 @@ "description": "Start new Personalized Classic TI planning", "newStudyLabel": "Personalized Classic TI", "category": "personalized", - "idToWidget": "personalizationNewTIPlanButton" + "idToWidget": "personalizationNewTIPlanButton", + "billable": true }, { "expectedTemplateLabel": "personalized mcTI Planning Tool", "title": "Personalized MC TI", "description": "Start new Personalized Multichannel TI planning", "newStudyLabel": "Personalized Multichannel TI", "category": "personalized", - "idToWidget": "personalizationNewMTIPlanButton" + "idToWidget": "personalizationNewMTIPlanButton", + "billable": true }, { "expectedTemplateLabel": "personalized pmTI Planning Tool", "title": "Personalized PM TI", "description": "Start new Personalized Phase-Modulation TI planning", "newStudyLabel": "Personalized Phase-Modulation TI", "category": "personalized", - "idToWidget": "personalizationNewPMTIPlanButton" + "idToWidget": "personalizationNewPMTIPlanButton", + "billable": true }], "categories": [{ "id": "precomputed", From 1b8b097e03ea6efb35044e6edb80dc4bc1f79ead Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 11:07:56 +0200 Subject: [PATCH 05/15] setCreditsIconToButton --- .../source/class/osparc/dashboard/NewStudies.js | 9 +-------- .../source/class/osparc/desktop/credits/Utils.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js index e854dbb806f..216dcda8322 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js @@ -144,14 +144,7 @@ qx.Class.define("osparc.dashboard.NewStudies", { const desc = templateInfo.description; const newPlanButton = new osparc.dashboard.GridButtonNew(title, desc); if (templateInfo.billable) { - newPlanButton.setIcon(osparc.desktop.credits.Utils.CREDITS_ICON); - const store = osparc.store.Store.getInstance(); - const contextWallet = store.getContextWallet(); - if (contextWallet) { - const credits = contextWallet.getCreditsAvailable(); - const creditsColor = osparc.desktop.credits.Utils.creditsToColor(credits, "strong-main"); - newPlanButton.setTextColor(creditsColor); - } + osparc.desktop.credits.Utils.setCreditsIconToButton(newPlanButton); } newPlanButton.setCardKey(templateInfo.idToWidget); osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget); diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js index e05d53427da..bcb8e13fa72 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js @@ -27,6 +27,17 @@ qx.Class.define("osparc.desktop.credits.Utils", { return Boolean(statics && statics["isPaymentEnabled"]); }, + setCreditsIconToButton: function(button) { + button.setIcon(osparc.desktop.credits.Utils.CREDITS_ICON); + const store = osparc.store.Store.getInstance(); + const contextWallet = store.getContextWallet(); + if (contextWallet) { + const credits = contextWallet.getCreditsAvailable(); + const creditsColor = osparc.desktop.credits.Utils.creditsToColor(credits, "strong-main"); + button.setTextColor(creditsColor); + } + }, + getNoWriteAccessInformationLabel: function() { return new qx.ui.basic.Label().set({ value: qx.locale.Manager.tr("You can't access this information"), From 1e3804f97cad05e277641d1f8b79799757f233a3 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 11:36:37 +0200 Subject: [PATCH 06/15] minor --- .../source/class/osparc/dashboard/NewStudies.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js index 216dcda8322..4070f8f4654 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js @@ -143,12 +143,17 @@ qx.Class.define("osparc.dashboard.NewStudies", { const title = templateInfo.title; const desc = templateInfo.description; const newPlanButton = new osparc.dashboard.GridButtonNew(title, desc); + newPlanButton.setCardKey(templateInfo.idToWidget); + osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget); if (templateInfo.billable) { osparc.desktop.credits.Utils.setCreditsIconToButton(newPlanButton); + newPlanButton.addListener("execute", () => { + // todo: check first if the user has credits + this.fireDataEvent("newStudyClicked", templateInfo); + }); + } else { + newPlanButton.addListener("execute", () => this.fireDataEvent("newStudyClicked", templateInfo)) } - newPlanButton.setCardKey(templateInfo.idToWidget); - osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget); - newPlanButton.addListener("execute", () => this.fireDataEvent("newStudyClicked", templateInfo)) return newPlanButton; }, From ad91ea1b52639846bac2ecfc682b24b2be828e65 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 11:36:48 +0200 Subject: [PATCH 07/15] bound to credits --- .../client/source/class/osparc/desktop/credits/Utils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js index bcb8e13fa72..fc9539e6213 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/Utils.js @@ -32,9 +32,9 @@ qx.Class.define("osparc.desktop.credits.Utils", { const store = osparc.store.Store.getInstance(); const contextWallet = store.getContextWallet(); if (contextWallet) { - const credits = contextWallet.getCreditsAvailable(); - const creditsColor = osparc.desktop.credits.Utils.creditsToColor(credits, "strong-main"); - button.setTextColor(creditsColor); + contextWallet.bind("creditsAvailable", button, "textColor", { + converter: c => osparc.desktop.credits.Utils.creditsToColor(c, "strong-main") + }); } }, From 36678853bf48289823f8b3f251c85463a93c60a5 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 11:40:30 +0200 Subject: [PATCH 08/15] unused --- .../desktop/credits/WalletsMiniViewer.js | 95 ------------------- 1 file changed, 95 deletions(-) delete mode 100644 services/static-webserver/client/source/class/osparc/desktop/credits/WalletsMiniViewer.js diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/WalletsMiniViewer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/WalletsMiniViewer.js deleted file mode 100644 index ca9e3077736..00000000000 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/WalletsMiniViewer.js +++ /dev/null @@ -1,95 +0,0 @@ -/* ************************************************************************ - - osparc - the simcore frontend - - https://osparc.io - - Copyright: - 2023 IT'IS Foundation, https://itis.swiss - - License: - MIT: https://opensource.org/licenses/MIT - - Authors: - * Odei Maiz (odeimaiz) - -************************************************************************ */ - -qx.Class.define("osparc.desktop.credits.WalletsMiniViewer", { - extend: qx.ui.core.Widget, - - construct: function() { - this.base(arguments); - - this._setLayout(new qx.ui.layout.VBox(2)); - - osparc.utils.Utils.setIdToWidget(this, "walletsMiniViewer"); - - this.set({ - alignX: "center", - margin: 6, - marginRight: 20, - cursor: "pointer" - }); - - this.__buildLayout(); - }, - - properties: { - contextWallet: { - check: "osparc.data.model.Wallet", - init: null, - nullable: true, - apply: "__reloadLayout" - } - }, - - members: { - __buildLayout: function() { - const store = osparc.store.Store.getInstance(); - // there is a bug with the binding the second time a user logs in - store.bind("contextWallet", this, "contextWallet"); - }, - - __reloadLayout: function() { - this._removeAll(); - const contextWallet = this.getContextWallet(); - if (contextWallet) { - this.__showOneWallet(contextWallet); - } else { - this.__showSelectWallet(); - } - }, - - __showOneWallet: function(wallet) { - const creditsIndicator = new osparc.desktop.credits.CreditsIndicator(wallet); - creditsIndicator.addListener("tap", () => { - const walletsEnabled = osparc.desktop.credits.Utils.areWalletsEnabled(); - if (walletsEnabled) { - osparc.desktop.credits.BillingCenterWindow.openWindow(); - } - }, this); - this._add(creditsIndicator, { - flex: 1 - }); - }, - - __showSelectWallet: function() { - const iconSrc = "@MaterialIcons/account_balance_wallet/26"; - const walletsButton = new qx.ui.basic.Image(iconSrc).set({ - toolTipText: this.tr("Select Credit Account"), - textColor: "danger-red" - }); - walletsButton.addListener("tap", () => { - const walletsEnabled = osparc.desktop.credits.Utils.areWalletsEnabled(); - if (walletsEnabled) { - const billingCenterWindow = osparc.desktop.credits.BillingCenterWindow.openWindow(); - billingCenterWindow.openWallets(); - } - }, this); - this._add(walletsButton, { - flex: 1 - }); - } - } -}); From 1e24f052cb485717e9c2d321d312bd2ba9172c4c Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 14:21:54 +0200 Subject: [PATCH 09/15] CreditsButton on NavBar --- .../desktop/credits/CreditsIndicatorButton.js | 98 +++++++++++++++++++ .../desktop/credits/CreditsNavBarContainer.js | 79 +++++++++++++++ .../class/osparc/navigation/NavigationBar.js | 9 +- 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js create mode 100644 services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js new file mode 100644 index 00000000000..f81e7d1acfc --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js @@ -0,0 +1,98 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2024 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.desktop.credits.CreditsIndicatorButton", { + extend: qx.ui.form.Button, + + construct: function() { + this.base(arguments); + + this.set({ + backgroundColor: "transparent" + }); + + const store = osparc.store.Store.getInstance(); + store.bind("contextWallet", this, "wallet"); + + this.__creditsContainer = new osparc.desktop.credits.CreditsNavBarContainer(); + this.__creditsContainer.exclude(); + + this.addListener("tap", this.__buttonTapped, this); + }, + + properties: { + wallet: { + check: "osparc.data.model.Wallet", + init: null, + nullable: true, + event: "changeWallet", + apply: "__applyWallet" + } + }, + + members: { + __creditsContainer: null, + __tappedOut: null, + + __applyWallet: function() { + osparc.desktop.credits.Utils.setCreditsIconToButton(this); + }, + + __buttonTapped: function() { + if (this.__tappedOut) { + this.__tappedOut = false; + return; + } + this.__showCreditsContainer(); + }, + + __showCreditsContainer: function() { + const tapListener = event => { + // In case a notification was tapped propagate the event so it can be handled by the NotificationUI + if (osparc.utils.Utils.isMouseOnElement(this.__creditsContainer, event)) { + return; + } + // I somehow can't stop the propagation of the event so workaround: + // If the user tapped on the bell we don't want to show it again + if (osparc.utils.Utils.isMouseOnElement(this, event)) { + this.__tappedOut = true; + } + this.__hideNotifications(); + document.removeEventListener("mousedown", tapListener, this); + }; + + const bounds = this.getBounds(); + const cel = this.getContentElement(); + if (cel) { + const domeEle = cel.getDomElement(); + if (domeEle) { + const rect = domeEle.getBoundingClientRect(); + bounds.left = parseInt(rect.x); + bounds.top = parseInt(rect.y); + } + } + this.__creditsContainer.setPosition(bounds.left+bounds.width-2, bounds.top+bounds.height-2); + this.__creditsContainer.show(); + + document.addEventListener("mousedown", tapListener, this); + }, + + __hideNotifications: function() { + this.__creditsContainer.exclude(); + } + } +}); diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js new file mode 100644 index 00000000000..b7c7e108d65 --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -0,0 +1,79 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2024 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.Grow()); + + this.set({ + zIndex: osparc.utils.Utils.FLOATING_Z_INDEX, + maxWidth: 200, + backgroundColor: "background-main-2", + padding: 10 + }); + osparc.utils.Utils.setIdToWidget(this, "creditsNavBarContainer"); + + const layout = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)); + + const creditsIndicator = new osparc.desktop.credits.CreditsIndicator(); + const store = osparc.store.Store.getInstance(); + store.bind("contextWallet", creditsIndicator, "wallet"); + layout.add(creditsIndicator, { + flex: 1 + }); + + const buttonSize = 24; + const billingCenterButton = new qx.ui.form.Button().set({ + appearance: "form-button-outlined", + width: buttonSize, + height: buttonSize, + alignX: "center", + alignY: "middle", + icon: "@FontAwesome5Solid/ellipsis-h/12" + }); + // make it circular + billingCenterButton.getContentElement().setStyles({ + "border-radius": `${buttonSize / 2}px` + }); + billingCenterButton.addListener("execute", () => { + osparc.desktop.credits.BillingCenterWindow.openWindow(); + this.exclude(); + }); + layout.add(billingCenterButton); + + this._add(layout); + + const root = qx.core.Init.getApplication().getRoot(); + root.add(this, { + top: 0, + right: 0 + }); + }, + + members: { + setPosition: function(x, y) { + this.setLayoutProperties({ + left: x - osparc.notification.NotificationUI.MAX_WIDTH, + top: y + }); + } + } +}); diff --git a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js index f28868f302d..6a5d3b603d8 100644 --- a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js +++ b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js @@ -138,7 +138,7 @@ qx.Class.define("osparc.navigation.NavigationBar", { this.getChildControl("expiration-icon"); this.getChildControl("help"); if (osparc.desktop.credits.Utils.areWalletsEnabled()) { - this.getChildControl("credits-menu-button"); + this.getChildControl("credits-button"); } this.getChildControl("log-in-button"); this.getChildControl("user-menu"); @@ -235,6 +235,13 @@ qx.Class.define("osparc.navigation.NavigationBar", { currentUsage, maxHeight: this.self().HEIGHT }); + this.getChildControl("right-items").add(control); + break; + } + case "credits-button": { + control = new osparc.desktop.credits.CreditsIndicatorButton().set({ + maxHeight: 32 + }); osparc.utils.Utils.setIdToWidget(control, "creditsNavigationBtn"); this.getChildControl("right-items").add(control); break; From f7159d40f7854dfd6ae95631a8c3e0e0a9caab18 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 14:47:44 +0200 Subject: [PATCH 10/15] width --- .../osparc/desktop/credits/CreditsIndicatorButton.js | 4 +++- .../osparc/desktop/credits/CreditsNavBarContainer.js | 8 ++++++-- .../source/class/osparc/navigation/NavigationBar.js | 7 +++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js index f81e7d1acfc..82df3da26ad 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js @@ -85,7 +85,9 @@ qx.Class.define("osparc.desktop.credits.CreditsIndicatorButton", { bounds.top = parseInt(rect.y); } } - this.__creditsContainer.setPosition(bounds.left+bounds.width-2, bounds.top+bounds.height-2); + const bottom = bounds.top+bounds.height+10; + const right = bounds.left+bounds.width-4; + this.__creditsContainer.setPosition(right, bottom); this.__creditsContainer.show(); document.addEventListener("mousedown", tapListener, this); diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js index b7c7e108d65..2eb249d8f79 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -25,7 +25,7 @@ qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { this.set({ zIndex: osparc.utils.Utils.FLOATING_Z_INDEX, - maxWidth: 200, + maxWidth: this.self().WIDTH, backgroundColor: "background-main-2", padding: 10 }); @@ -68,10 +68,14 @@ qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { }); }, + statics: { + WIDTH: 200 + }, + members: { setPosition: function(x, y) { this.setLayoutProperties({ - left: x - osparc.notification.NotificationUI.MAX_WIDTH, + left: x - this.self().WIDTH, top: y }); } diff --git a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js index 6a5d3b603d8..db55016a71e 100644 --- a/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js +++ b/services/static-webserver/client/source/class/osparc/navigation/NavigationBar.js @@ -238,14 +238,17 @@ qx.Class.define("osparc.navigation.NavigationBar", { this.getChildControl("right-items").add(control); break; } - case "credits-button": { + case "credits-button": control = new osparc.desktop.credits.CreditsIndicatorButton().set({ maxHeight: 32 }); + control.getChildControl("icon").set({ + maxHeight: 24, + scale: true + }); osparc.utils.Utils.setIdToWidget(control, "creditsNavigationBtn"); this.getChildControl("right-items").add(control); break; - } case "tasks-button": control = new osparc.task.TasksButton(); this.getChildControl("right-items").add(control); From 043b11d11dbeee3d8b2896203e87def2783314a3 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 14:51:23 +0200 Subject: [PATCH 11/15] aesthetics --- .../class/osparc/desktop/credits/CreditsNavBarContainer.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js index 2eb249d8f79..223497c1d6b 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -40,13 +40,14 @@ qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { flex: 1 }); - const buttonSize = 24; + const buttonSize = 26; const billingCenterButton = new qx.ui.form.Button().set({ appearance: "form-button-outlined", width: buttonSize, height: buttonSize, alignX: "center", alignY: "middle", + center: true, icon: "@FontAwesome5Solid/ellipsis-h/12" }); // make it circular From 47db0d20360e114649418ec759b2811183753b57 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Fri, 21 Jun 2024 15:42:18 +0200 Subject: [PATCH 12/15] Confirmation window if low in credits --- .../class/osparc/dashboard/NewStudies.js | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js index 4070f8f4654..9fc4f8441ab 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/NewStudies.js @@ -140,6 +140,8 @@ qx.Class.define("osparc.dashboard.NewStudies", { }, __createCard: function(templateInfo) { + const newStudyClicked = () => this.fireDataEvent("newStudyClicked", templateInfo); + const title = templateInfo.title; const desc = templateInfo.description; const newPlanButton = new osparc.dashboard.GridButtonNew(title, desc); @@ -148,11 +150,30 @@ qx.Class.define("osparc.dashboard.NewStudies", { if (templateInfo.billable) { osparc.desktop.credits.Utils.setCreditsIconToButton(newPlanButton); newPlanButton.addListener("execute", () => { - // todo: check first if the user has credits - this.fireDataEvent("newStudyClicked", templateInfo); + const store = osparc.store.Store.getInstance(); + const credits = store.getContextWallet().getCreditsAvailable() + const preferencesSettings = osparc.Preferences.getInstance(); + const warningThreshold = preferencesSettings.getCreditsWarningThreshold(); + if (credits <= warningThreshold) { + const msg = this.tr("This Plan requires Credits to run Sim4Life powered simulations. You can top up in the Billing Center."); + const win = new osparc.ui.window.Confirmation(msg).set({ + caption: this.tr("Credits required"), + confirmText: this.tr("Start, I'll get them later"), + confirmAction: "create" + }); + win.center(); + win.open(); + win.addListener("close", () => { + if (win.getConfirmed()) { + this.fireDataEvent("newStudyClicked", templateInfo); + } + }); + } else { + newStudyClicked(); + } }); } else { - newPlanButton.addListener("execute", () => this.fireDataEvent("newStudyClicked", templateInfo)) + newPlanButton.addListener("execute", () => newStudyClicked()); } return newPlanButton; }, From 5c3ab1c8f106fcc023bb395f7905303f47230e9e Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Mon, 24 Jun 2024 14:21:20 +0200 Subject: [PATCH 13/15] upgrade fontawesome5 dependency to 1.0.0 (still no coins) --- services/static-webserver/client/Manifest.json | 2 +- services/static-webserver/client/qx-lock.json | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/services/static-webserver/client/Manifest.json b/services/static-webserver/client/Manifest.json index 80463514298..21d82cd8cd3 100644 --- a/services/static-webserver/client/Manifest.json +++ b/services/static-webserver/client/Manifest.json @@ -41,7 +41,7 @@ "requires": { "@qooxdoo/compiler": "^1.0.0-beta", "@qooxdoo/framework": "^6.0.0-beta", - "ITISFoundation/qx-iconfont-fontawesome5": "^0.2.0", + "ITISFoundation/qx-iconfont-fontawesome5": "^1.0.0", "ITISFoundation/qx-osparc-theme": "^0.5.6", "qooxdoo/qxl.testtapper": "^0.4.3", "qooxdoo/qxl.apiviewer": "^1.0.0-beta", diff --git a/services/static-webserver/client/qx-lock.json b/services/static-webserver/client/qx-lock.json index d52dff39e77..6b9be87bd53 100644 --- a/services/static-webserver/client/qx-lock.json +++ b/services/static-webserver/client/qx-lock.json @@ -2,11 +2,11 @@ "libraries": [ { "library_name": "qx-iconfont-fontawesome5", - "library_version": "0.2.0", - "path": "qx_packages/ITISFoundation_qx-iconfont-fontawesome5_v0_2_0", + "library_version": "1.0.0", + "path": "qx_packages/ITISFoundation_qx-iconfont-fontawesome5_v1_0_0", "uri": "ITISFoundation/qx-iconfont-fontawesome5", "repo_name": "ITISFoundation/qx-iconfont-fontawesome5", - "repo_tag": "v0.2.0" + "repo_tag": "v1.0.0" }, { "library_name": "qx-osparc-theme", From 14d7d3ef4c0ef17e46d19e5662961e8389af457e Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Mon, 24 Jun 2024 15:10:12 +0200 Subject: [PATCH 14/15] vertical ellipses --- .../class/osparc/desktop/credits/CreditsNavBarContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js index 223497c1d6b..1c9b6f02147 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -48,7 +48,7 @@ qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { alignX: "center", alignY: "middle", center: true, - icon: "@FontAwesome5Solid/ellipsis-h/12" + icon: "@FontAwesome5Solid/ellipsis-v/12" }); // make it circular billingCenterButton.getContentElement().setStyles({ From 0db1d48c1850b401c5d46c8b0e09b6a5c0fe2ea8 Mon Sep 17 00:00:00 2001 From: Odei Maiz Date: Mon, 24 Jun 2024 15:34:37 +0200 Subject: [PATCH 15/15] floating menu appearance --- .../osparc/desktop/credits/CreditsIndicatorButton.js | 4 ++-- .../osparc/desktop/credits/CreditsNavBarContainer.js | 7 +++---- .../client/source/class/osparc/theme/Appearance.js | 10 ++++++++++ .../client/source/class/osparc/theme/Decoration.js | 7 +++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js index 82df3da26ad..e331547fbca 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js @@ -85,8 +85,8 @@ qx.Class.define("osparc.desktop.credits.CreditsIndicatorButton", { bounds.top = parseInt(rect.y); } } - const bottom = bounds.top+bounds.height+10; - const right = bounds.left+bounds.width-4; + const bottom = bounds.top+bounds.height; + const right = bounds.left+bounds.width; this.__creditsContainer.setPosition(right, bottom); this.__creditsContainer.show(); diff --git a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js index 1c9b6f02147..4bc6eceb91f 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -24,10 +24,9 @@ qx.Class.define("osparc.desktop.credits.CreditsNavBarContainer", { this._setLayout(new qx.ui.layout.Grow()); this.set({ - zIndex: osparc.utils.Utils.FLOATING_Z_INDEX, - maxWidth: this.self().WIDTH, - backgroundColor: "background-main-2", - padding: 10 + appearance: "floating-menu", + padding: 8, + maxWidth: this.self().WIDTH }); osparc.utils.Utils.setIdToWidget(this, "creditsNavBarContainer"); diff --git a/services/static-webserver/client/source/class/osparc/theme/Appearance.js b/services/static-webserver/client/source/class/osparc/theme/Appearance.js index e72b2cce9a7..ebf773d2934 100644 --- a/services/static-webserver/client/source/class/osparc/theme/Appearance.js +++ b/services/static-webserver/client/source/class/osparc/theme/Appearance.js @@ -177,6 +177,16 @@ qx.Theme.define("osparc.theme.Appearance", { "none": {}, + "floating-menu": { + style: function() { + return { + backgroundColor: "background-main", + padding: 4, + decorator: "border-simple" + } + } + }, + /* --------------------------------------------------------------------------- WINDOW-SMALL-CAP CHOOSER diff --git a/services/static-webserver/client/source/class/osparc/theme/Decoration.js b/services/static-webserver/client/source/class/osparc/theme/Decoration.js index 6cda4485919..12c85bc3ec6 100644 --- a/services/static-webserver/client/source/class/osparc/theme/Decoration.js +++ b/services/static-webserver/client/source/class/osparc/theme/Decoration.js @@ -236,6 +236,13 @@ qx.Theme.define("osparc.theme.Decoration", { } }, + "border-simple": { + include: "border", + style: { + radius: 4 + } + }, + "no-border": { style: { radius: 4,