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", 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); } }, 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"); 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 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..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,12 +140,41 @@ 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); newPlanButton.setCardKey(templateInfo.idToWidget); osparc.utils.Utils.setIdToWidget(newPlanButton, templateInfo.idToWidget); - newPlanButton.addListener("execute", () => this.fireDataEvent("newStudyClicked", templateInfo)) + if (templateInfo.billable) { + osparc.desktop.credits.Utils.setCreditsIconToButton(newPlanButton); + newPlanButton.addListener("execute", () => { + 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", () => newStudyClicked()); + } return newPlanButton; }, 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..e331547fbca --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsIndicatorButton.js @@ -0,0 +1,100 @@ +/* ************************************************************************ + + 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); + } + } + const bottom = bounds.top+bounds.height; + const right = bounds.left+bounds.width; + this.__creditsContainer.setPosition(right, bottom); + 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..4bc6eceb91f --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/desktop/credits/CreditsNavBarContainer.js @@ -0,0 +1,83 @@ +/* ************************************************************************ + + 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({ + appearance: "floating-menu", + padding: 8, + maxWidth: this.self().WIDTH + }); + 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 = 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-v/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 + }); + }, + + statics: { + WIDTH: 200 + }, + + members: { + setPosition: function(x, y) { + this.setLayoutProperties({ + left: x - this.self().WIDTH, + top: y + }); + } + } +}); 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..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 @@ -20,12 +20,24 @@ 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"); 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) { + contextWallet.bind("creditsAvailable", button, "textColor", { + converter: c => osparc.desktop.credits.Utils.creditsToColor(c, "strong-main") + }); + } + }, + getNoWriteAccessInformationLabel: function() { return new qx.ui.basic.Label().set({ value: qx.locale.Manager.tr("You can't access this information"), 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 - }); - } - } -}); 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..db55016a71e 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,10 +235,20 @@ qx.Class.define("osparc.navigation.NavigationBar", { currentUsage, maxHeight: this.self().HEIGHT }); - osparc.utils.Utils.setIdToWidget(control, "creditsNavigationBtn"); this.getChildControl("right-items").add(control); break; } + 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); 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, 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",