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 385d8b3c6d2d..fed29c54090b 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 @@ -144,50 +144,8 @@ qx.Class.define("osparc.auth.ui.RequestAccount", { case "s4lacad": case "s4ldesktopacad": { const application = new qx.ui.form.SelectBox(); - [{ - id: "other", - label: "Other" - }, { - 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({ + osparc.product.Utils.S4L_TOPICS.forEach(topic => { + const lItem = new qx.ui.form.ListItem(topic.label, null, topic.id).set({ rich: true }); application.add(lItem); diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js index 4fb63a41a05c..61f72d136fac 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/MembersList.js @@ -137,8 +137,7 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { __getMembersList: function() { const membersUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3, + appearance: "listing", width: 150 }); @@ -157,6 +156,9 @@ qx.Class.define("osparc.desktop.organizations.MembersList", { ctrl.bindProperty("showOptions", "showOptions", null, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.subscribeToFilterGroup("organizationMembersList"); item.getChildControl("thumbnail").setDecorator("circled"); item.addListener("promoteToMember", e => { diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationDetails.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationDetails.js index 52426c896e8b..038a7fb3f4f6 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationDetails.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationDetails.js @@ -33,6 +33,24 @@ qx.Class.define("osparc.desktop.organizations.OrganizationDetails", { "backToOrganizations": "qx.event.type.Event" }, + statics: { + createTabPage: function(label, icon) { + const tabPage = new qx.ui.tabview.Page().set({ + layout: new qx.ui.layout.VBox(), + }); + if (label) { + tabPage.setLabel(label); + } + if (icon) { + tabPage.setIcon(icon); + } + tabPage.getChildControl("button").set({ + font: "text-13" + }); + return tabPage; + }, + }, + members: { __orgModel: null, __titleLayout: null, @@ -88,6 +106,10 @@ qx.Class.define("osparc.desktop.organizations.OrganizationDetails", { this.__titleLayout.remove(this.__organizationListItem); } const organizationListItem = this.__organizationListItem = new osparc.ui.list.OrganizationListItem(); + organizationListItem.set({ + cursor: "default", + backgroundColor: null, + }); organizationListItem.getChildControl("options").exclude(); organizationListItem.setShowDeleteButton(false); organizationListItem.addListener("openEditOrganization", () => this.__openEditOrganization()); @@ -126,28 +148,12 @@ qx.Class.define("osparc.desktop.organizations.OrganizationDetails", { }); }, - __createTabPage: function(label, icon) { - const tabPage = new qx.ui.tabview.Page().set({ - layout: new qx.ui.layout.VBox() - }); - if (label) { - tabPage.setLabel(label); - } - if (icon) { - tabPage.setIcon(icon); - } - tabPage.getChildControl("button").set({ - font: "text-13" - }); - return tabPage; - }, - __getTabs: function() { const tabView = new qx.ui.tabview.TabView().set({ contentPadding: 10 }); - const membersListPage = this.__createTabPage(this.tr("Members"), "@FontAwesome5Solid/users/14"); + const membersListPage = this.self().createTabPage(this.tr("Members"), "@FontAwesome5Solid/users/14"); const membersList = this.__membersList = new osparc.desktop.organizations.MembersList(); membersListPage.add(membersList, { flex: 1 @@ -158,14 +164,14 @@ qx.Class.define("osparc.desktop.organizations.OrganizationDetails", { plural: true, firstUpperCase: true }); - const templatesListPage = this.__createTabPage(templatesText, "@FontAwesome5Solid/copy/14"); + const templatesListPage = this.self().createTabPage(templatesText, "@FontAwesome5Solid/copy/14"); const templatesList = this.__templatesList = new osparc.desktop.organizations.TutorialsList(); templatesListPage.add(templatesList, { flex: 1 }); tabView.add(templatesListPage); - const servicesListPage = this.__createTabPage(this.tr("Services"), "@FontAwesome5Solid/cogs/14"); + const servicesListPage = this.self().createTabPage(this.tr("Services"), "@FontAwesome5Solid/cogs/14"); const servicesList = this.__servicesList = new osparc.desktop.organizations.ServicesList(); servicesListPage.add(servicesList, { flex: 1 diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationsList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationsList.js index 82abb9e17120..dc17339d103b 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationsList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/OrganizationsList.js @@ -126,10 +126,9 @@ qx.Class.define("osparc.desktop.organizations.OrganizationsList", { __getOrganizationsList: function() { const orgsUIList = this.__orgsUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3, + appearance: "listing", height: 150, - width: 150 + width: 150, }); osparc.utils.Utils.setIdToWidget(orgsUIList, "organizationsList"); orgsUIList.addListener("changeSelection", e => this.__organizationSelected(e.getData()), this); @@ -170,6 +169,7 @@ qx.Class.define("osparc.desktop.organizations.OrganizationsList", { item.set({ minHeight: 1, maxHeight: 1, + backgroundColor: "transparent", decorator: "separator-strong", }); } diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/ServicesList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/ServicesList.js index 492d6b6ea4c9..d7eba64172a7 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/ServicesList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/ServicesList.js @@ -63,8 +63,7 @@ qx.Class.define("osparc.desktop.organizations.ServicesList", { __getServicesList: function() { const servicesUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3 + appearance: "listing", }); const servicesModel = this.__servicesModel = new qx.data.Array(); @@ -84,6 +83,9 @@ qx.Class.define("osparc.desktop.organizations.ServicesList", { }, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.subscribeToFilterGroup("organizationServicesList"); item.addListener("openMoreInfo", e => { const serviceKey = e.getData()["key"]; diff --git a/services/static-webserver/client/source/class/osparc/desktop/organizations/TutorialsList.js b/services/static-webserver/client/source/class/osparc/desktop/organizations/TutorialsList.js index c735aefe30a1..4ef1dabf6f5c 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/organizations/TutorialsList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/organizations/TutorialsList.js @@ -63,8 +63,7 @@ qx.Class.define("osparc.desktop.organizations.TutorialsList", { __getTutorialsList: function() { const templatesUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3 + appearance: "listing", }); const templatesModel = this.__tutorialsModel = new qx.data.Array(); @@ -83,6 +82,9 @@ qx.Class.define("osparc.desktop.organizations.TutorialsList", { }, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.subscribeToFilterGroup("organizationTutorialsList"); item.addListener("openMoreInfo", e => { const templateId = e.getData()["key"]; diff --git a/services/static-webserver/client/source/class/osparc/desktop/paymentMethods/PaymentMethods.js b/services/static-webserver/client/source/class/osparc/desktop/paymentMethods/PaymentMethods.js index 14b64b3a8ea6..923e57fefa76 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/paymentMethods/PaymentMethods.js +++ b/services/static-webserver/client/source/class/osparc/desktop/paymentMethods/PaymentMethods.js @@ -195,6 +195,9 @@ qx.Class.define("osparc.desktop.paymentMethods.PaymentMethods", { ctrl.bindProperty("expirationYear", "expirationYear", null, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.addListener("openPaymentMethodDetails", e => this.__openPaymentMethodDetails(e.getData())); item.addListener("deletePaymentMethod", e => this.__deletePaymentMethod(e.getData())); } diff --git a/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js b/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js index 3cf57a6ce6aa..76a8818a653b 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/wallets/MembersList.js @@ -124,8 +124,7 @@ qx.Class.define("osparc.desktop.wallets.MembersList", { __getMembersList: function() { const membersUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3, + appearance: "listing", width: 150 }); @@ -145,6 +144,9 @@ qx.Class.define("osparc.desktop.wallets.MembersList", { ctrl.bindProperty("showOptions", "showOptions", null, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.subscribeToFilterGroup("walletMembersList"); item.getChildControl("thumbnail").setDecorator("circled"); item.addListener("promoteToAccountant", e => { diff --git a/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletListItem.js b/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletListItem.js index fc6750140763..5fe1cd5324bd 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletListItem.js +++ b/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletListItem.js @@ -29,6 +29,11 @@ qx.Class.define("osparc.desktop.wallets.WalletListItem", { layout.setColumnAlign(creditsCol, "right", "middle"); this.__buildLayout(); + + this.set({ + backgroundColor: "transparent", + cursor: "default", + }); }, properties: { diff --git a/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletsList.js b/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletsList.js index 57c069388d79..e20e73003f3c 100644 --- a/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletsList.js +++ b/services/static-webserver/client/source/class/osparc/desktop/wallets/WalletsList.js @@ -90,9 +90,7 @@ qx.Class.define("osparc.desktop.wallets.WalletsList", { __createWalletsList: function(widgetId) { const walletsUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3, - backgroundColor: "transparent", + appearance: "listing", height: null, focusable: false }); @@ -118,7 +116,6 @@ qx.Class.define("osparc.desktop.wallets.WalletsList", { }, configureItem: item => { item.subscribeToFilterGroup("walletsList"); - item.addListener("openEditWallet", e => this.__openEditWallet(e.getData())); item.addListener("openShareWallet", e => this.__walletSelected(e.getData())); item.addListener("buyCredits", e => this.fireDataEvent("buyCredits", e.getData())); diff --git a/services/static-webserver/client/source/class/osparc/pricing/Plans.js b/services/static-webserver/client/source/class/osparc/pricing/Plans.js index 95876a2a067f..05697c441587 100644 --- a/services/static-webserver/client/source/class/osparc/pricing/Plans.js +++ b/services/static-webserver/client/source/class/osparc/pricing/Plans.js @@ -54,8 +54,7 @@ qx.Class.define("osparc.pricing.Plans", { break; case "pricing-plans-list": control = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3 + appearance: "listing", }); control.addListener("changeSelection", e => { const selection = e.getData(); diff --git a/services/static-webserver/client/source/class/osparc/product/Utils.js b/services/static-webserver/client/source/class/osparc/product/Utils.js index c88a4a3c8ffc..7dd8c46b7cad 100644 --- a/services/static-webserver/client/source/class/osparc/product/Utils.js +++ b/services/static-webserver/client/source/class/osparc/product/Utils.js @@ -450,5 +450,55 @@ qx.Class.define("osparc.product.Utils", { groupServices: function() { return Boolean(osparc.store.Products.getInstance().getGroupedServicesUiConfig()); }, + + isBookACallEnabled: function() { + return osparc.utils.Utils.isDevelopmentPlatform(); + }, + + S4L_TOPICS: [ + { + id: "other", + label: "Other" + }, { + 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" + } + ], } }); diff --git a/services/static-webserver/client/source/class/osparc/share/Collaborators.js b/services/static-webserver/client/source/class/osparc/share/Collaborators.js index 5ab5c84a5a13..3f54c1e90455 100644 --- a/services/static-webserver/client/source/class/osparc/share/Collaborators.js +++ b/services/static-webserver/client/source/class/osparc/share/Collaborators.js @@ -329,11 +329,9 @@ qx.Class.define("osparc.share.Collaborators", { vBox.add(header); const collaboratorsUIList = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 3, + appearance: "listing", width: 150, padding: 0, - backgroundColor: "transparent", }); const collaboratorsModel = this.__collaboratorsModel = new qx.data.Array(); @@ -356,6 +354,9 @@ qx.Class.define("osparc.share.Collaborators", { }, item, id); }, configureItem: item => { + item.set({ + cursor: "default", + }); item.getChildControl("thumbnail").setDecorator("circled"); item.addListener("promoteToEditor", e => { const orgMember = e.getData(); @@ -402,6 +403,7 @@ qx.Class.define("osparc.share.Collaborators", { item.set({ minHeight: 1, maxHeight: 1, + backgroundColor: "transparent", decorator: "separator-strong", }); } diff --git a/services/static-webserver/client/source/class/osparc/store/Study.js b/services/static-webserver/client/source/class/osparc/store/Study.js index b20bc06d6174..f7150275133d 100644 --- a/services/static-webserver/client/source/class/osparc/store/Study.js +++ b/services/static-webserver/client/source/class/osparc/store/Study.js @@ -380,6 +380,16 @@ qx.Class.define("osparc.store.Study", { }); }, + __updateCurrentStudyAccessRights: function(updatedStudyData) { + const currentStudy = osparc.store.Store.getInstance().getCurrentStudy(); + if (currentStudy && currentStudy.getUuid() === updatedStudyData["uuid"]) { + currentStudy.set({ + accessRights: updatedStudyData["accessRights"], + lastChangeDate: new Date(updatedStudyData["lastChangeDate"]), + }); + } + }, + addCollaborators: function(studyData, newCollaborators) { const promises = []; Object.keys(newCollaborators).forEach(gid => { @@ -398,6 +408,7 @@ qx.Class.define("osparc.store.Study", { studyData["accessRights"][gid] = newCollaborators[gid]; }); studyData["lastChangeDate"] = new Date().toISOString(); + this.__updateCurrentStudyAccessRights(studyData); }) .catch(err => { osparc.FlashMessenger.logError(err); @@ -416,6 +427,7 @@ qx.Class.define("osparc.store.Study", { .then(() => { delete studyData["accessRights"][gid]; studyData["lastChangeDate"] = new Date().toISOString(); + this.__updateCurrentStudyAccessRights(studyData); }) .catch(err => { osparc.FlashMessenger.logError(err); @@ -435,6 +447,7 @@ qx.Class.define("osparc.store.Study", { .then(() => { studyData["accessRights"][gid] = newPermissions; studyData["lastChangeDate"] = new Date().toISOString(); + this.__updateCurrentStudyAccessRights(studyData); }) .catch(err => { osparc.FlashMessenger.logError(err); diff --git a/services/static-webserver/client/source/class/osparc/support/BookACallTopicSelector.js b/services/static-webserver/client/source/class/osparc/support/BookACallTopicSelector.js new file mode 100644 index 000000000000..9c39a10e75ac --- /dev/null +++ b/services/static-webserver/client/source/class/osparc/support/BookACallTopicSelector.js @@ -0,0 +1,204 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2025 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + + +qx.Class.define("osparc.support.BookACallTopicSelector", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.VBox(20)); + + this.set({ + padding: 10, + font: "text-14", + }); + + this.__buildLayout(); + }, + + events: { + "callTopicSelected": "qx.event.type.Data", + }, + + members: { + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "content-box": + control = new qx.ui.container.Composite(new qx.ui.layout.VBox(10)).set({ + decorator: "rounded", + backgroundColor: "background-main-2", + padding: 10, + }); + this._add(control); + break; + case "intro-label": + control = new qx.ui.basic.Label().set({ + value: this.tr("I would like..."), + font: "text-14", + }); + this.getChildControl("content-box").add(control); + break; + case "generic-intro-button": + control = new qx.ui.form.RadioButton().set({ + label: this.tr("a generic introduction"), + value: false, + paddingTop: 10, + }); + this.getChildControl("content-box").add(control); + break; + case "specific-intro-button": + control = new qx.ui.form.RadioButton().set({ + label: this.tr("a specific introduction for"), + value: false, + paddingTop: 10, + }); + this.getChildControl("content-box").add(control); + break; + case "specific-intro-select-box": + control = new qx.ui.form.SelectBox().set({ + marginLeft: 20, + }); + this.getChildControl("content-box").add(control); + this.getChildControl("specific-intro-button").bind("value", control, "visibility", { + converter: val => val ? "visible" : "excluded" + }); + break; + case "help-with-project-button": + control = new qx.ui.form.RadioButton().set({ + label: this.tr("some help with my project"), + value: false, + paddingTop: 10, + }); + this.getChildControl("content-box").add(control); + break; + case "share-project-checkbox": { + control = new qx.ui.form.CheckBox().set({ + value: true, + label: this.tr("share current project with support team (optional)"), + marginLeft: 20, + }); + this.getChildControl("content-box").add(control); + this.getChildControl("help-with-project-button").bind("value", control, "visibility", { + converter: val => val ? "visible" : "excluded" + }); + const store = osparc.store.Store.getInstance(); + store.bind("currentStudy", control, "enabled", { + converter: study => { + if (!study) { + control.setValue(false); + } + return Boolean(study); + } + }); + break; + } + case "specific-topic-button": + control = new qx.ui.form.RadioButton().set({ + label: this.tr("to discuss a specific topic"), + value: false, + paddingTop: 10, + }); + this.getChildControl("content-box").add(control); + break; + case "specific-topic-textfield": + control = new qx.ui.form.TextArea().set({ + placeholder: this.tr("please provide any background information that could help us make this meeting more productive"), + marginLeft: 20, + }); + this.getChildControl("content-box").add(control); + this.getChildControl("specific-topic-button").bind("value", control, "visibility", { + converter: val => val ? "visible" : "excluded" + }); + break; + case "next-button": + control = new qx.ui.form.Button().set({ + label: this.tr("Next"), + appearance: "strong-button", + center: true, + allowGrowX: false, + alignX: "right", + marginTop: 20, + }); + control.addListener("execute", () => this.__nextPressed()); + this._add(control); + break; + } + return control || this.base(arguments, id); + }, + + __buildLayout: function() { + this.getChildControl("intro-label"); + const genericIntroButton = this.getChildControl("generic-intro-button"); + const specificIntroButton = this.getChildControl("specific-intro-button"); + const selectBox = this.getChildControl("specific-intro-select-box"); + osparc.product.Utils.S4L_TOPICS.forEach(topic => { + const lItem = new qx.ui.form.ListItem(topic.label, null, topic.id).set({ + rich: true + }); + selectBox.add(lItem); + }); + const helpWithProjectButton = this.getChildControl("help-with-project-button"); + this.getChildControl("share-project-checkbox"); + const specificTopicButton = this.getChildControl("specific-topic-button"); + this.getChildControl("specific-topic-textfield"); + this.getChildControl("next-button"); + + // make them act as radio buttons + [ + genericIntroButton, + specificIntroButton, + helpWithProjectButton, + specificTopicButton, + ].forEach(rb => { + rb.addListener("changeValue", () => { + if (rb.getValue()) { + [genericIntroButton, specificIntroButton, helpWithProjectButton, specificTopicButton].forEach(otherRb => { + if (otherRb !== rb) { + otherRb.setValue(false); + } + }); + } + }); + }); + }, + + __nextPressed: function() { + const topicData = {}; + if (this.getChildControl("generic-intro-button").getValue()) { + topicData["topic"] = "Generic Introduction"; + } else if (this.getChildControl("specific-intro-button").getValue()) { + topicData["topic"] = "Specific Introduction"; + const selectBox = this.getChildControl("specific-intro-select-box"); + const selectedItem = selectBox.getSelection()[0]; + topicData["extraInfo"] = selectedItem ? selectedItem.getModel() : ""; + } else if (this.getChildControl("help-with-project-button").getValue()) { + topicData["topic"] = "Help with Project"; + if (this.getChildControl("share-project-checkbox").getValue()) { + topicData["share-project"] = true; + } + } else if (this.getChildControl("specific-topic-button").getValue()) { + topicData["topic"] = "Specific Topic"; + topicData["extraInfo"] = this.getChildControl("specific-topic-textfield").getValue(); + } + + this.fireDataEvent("callTopicSelected", topicData); + }, + } +}); diff --git a/services/static-webserver/client/source/class/osparc/support/Conversation.js b/services/static-webserver/client/source/class/osparc/support/Conversation.js index 23588a4c1e26..6bb15a6384e2 100644 --- a/services/static-webserver/client/source/class/osparc/support/Conversation.js +++ b/services/static-webserver/client/source/class/osparc/support/Conversation.js @@ -38,6 +38,8 @@ qx.Class.define("osparc.support.Conversation", { }, members: { + __bookACallInfo: null, + _createChildControlImpl: function(id) { let control; switch (id) { @@ -58,6 +60,7 @@ qx.Class.define("osparc.support.Conversation", { this.getChildControl("share-project-layout").add(new qx.ui.core.Spacer(), { flex: 1 }); this.getChildControl("share-project-layout").add(control); this.getChildControl("share-project-layout").add(new qx.ui.core.Spacer(), { flex: 1 }); + control.addListener("tap", () => this.__shareProjectWithSupport(control.getValue()), this); break; } return control || this.base(arguments, id); @@ -81,23 +84,27 @@ qx.Class.define("osparc.support.Conversation", { } osparc.store.ConversationsSupport.getInstance().postConversation(extraContext) .then(data => { - let prePostMessagePromise = new Promise((resolve) => resolve()); - let isBookACall = false; - // make these checks first, setConversation will reload messages - if ( - this._messages.length === 1 && - this._messages[0]["systemMessageType"] && - this._messages[0]["systemMessageType"] === osparc.support.Conversation.SYSTEM_MESSAGE_TYPE.BOOK_A_CALL - ) { - isBookACall = true; - } + // clone first, it will be reset when setting the conversation + const bookACallInfo = this.__bookACallInfo ? Object.assign({}, this.__bookACallInfo) : null; const newConversation = new osparc.data.model.Conversation(data); this.setConversation(newConversation); - if (isBookACall) { + let prePostMessagePromise = new Promise((resolve) => resolve()); + if (bookACallInfo) { // add a first message - prePostMessagePromise = this.__postMessage("Book a Call"); + let msg = "Book a Call"; + if (bookACallInfo) { + msg += `\n- Topic: ${bookACallInfo["topic"]}`; + if ("extraInfo" in bookACallInfo) { + msg += `\n- Extra Info: ${bookACallInfo["extraInfo"]}`; + } + } + prePostMessagePromise = this.__postMessage(msg); // rename the conversation newConversation.renameConversation("Book a Call"); + // share project if needed + if (bookACallInfo["share-project"] && currentStudy) { + this.__shareProjectWithSupport(true); + } } prePostMessagePromise .then(() => { @@ -112,10 +119,18 @@ qx.Class.define("osparc.support.Conversation", { }); }, + // overridden + clearAllMessages: function() { + this.base(arguments); + + this.__bookACallInfo = null; + }, + _applyConversation: function(conversation) { this.base(arguments, conversation); - this.__populateShareProjectCheckbox(); + this.__bookACallInfo = null; + this.__evaluateShareProject(); }, __postMessage: function(content) { @@ -123,28 +138,29 @@ qx.Class.define("osparc.support.Conversation", { return osparc.store.ConversationsSupport.getInstance().postMessage(conversationId, content); }, - __populateShareProjectCheckbox: function() { - const conversation = this.getConversation(); - - const shareProjectCB = this.getChildControl("share-project-checkbox"); + __evaluateShareProject: function() { const shareProjectLayout = this.getChildControl("share-project-layout"); - const currentStudy = osparc.store.Store.getInstance().getCurrentStudy(); - let showCB = false; - let enabledCB = false; - if (conversation === null && currentStudy) { - // initiating conversation - showCB = true; - enabledCB = true; - } else if (conversation) { - // it was already set - showCB = conversation.getContextProjectId(); - enabledCB = conversation.amIOwner(); + let showLayout = false; + let enabledLayout = false; + const conversation = this.getConversation(); + if (conversation) { + showLayout = Boolean(conversation.getContextProjectId()); + enabledLayout = conversation.amIOwner(); } shareProjectLayout.set({ - visibility: showCB ? "visible" : "excluded", - enabled: enabledCB, + visibility: showLayout ? "visible" : "excluded", + enabled: enabledLayout, }); + if (showLayout) { + this.__populateShareProjectCB(); + const currentStudy = osparc.store.Store.getInstance().getCurrentStudy(); + currentStudy.addListener("changeAccessRights", () => this.__populateShareProjectCB(), this); + } + }, + + __populateShareProjectCB: function() { + const conversation = this.getConversation(); if (conversation && conversation.getContextProjectId()) { const projectId = conversation.getContextProjectId(); osparc.store.Study.getInstance().getOne(projectId) @@ -157,17 +173,13 @@ qx.Class.define("osparc.support.Conversation", { } else { isAlreadyShared = false; } + const shareProjectCB = this.getChildControl("share-project-checkbox"); shareProjectCB.setValue(isAlreadyShared); - shareProjectCB.removeListener("changeValue", this.__shareProjectWithSupport, this); - if (showCB) { - shareProjectCB.addListener("changeValue", this.__shareProjectWithSupport, this); - } }); } }, - __shareProjectWithSupport: function(e) { - const share = e.getData(); + __shareProjectWithSupport: function(share) { const supportGroupId = osparc.store.Groups.getInstance().getSupportGroup().getGroupId(); const projectId = this.getConversation().getContextProjectId(); osparc.store.Study.getInstance().getOne(projectId) @@ -186,15 +198,6 @@ qx.Class.define("osparc.support.Conversation", { addSystemMessage: function(type) { type = type || osparc.support.Conversation.SYSTEM_MESSAGE_TYPE.ASK_A_QUESTION; - const now = new Date(); - const systemMessage = { - "conversationId": null, - "created": now.toISOString(), - "messageId": `system-${now.getTime()}`, - "modified": now.toISOString(), - "type": "MESSAGE", - "userGroupId": "system", - }; let msg = null; const greet = "Hi " + osparc.auth.Data.getInstance().getUserName() + ",\n"; switch (type) { @@ -212,10 +215,22 @@ qx.Class.define("osparc.support.Conversation", { break; } if (msg) { - systemMessage["content"] = msg; - systemMessage["systemMessageType"] = type; + const now = new Date(); + const systemMessage = { + "conversationId": null, + "content": msg, + "created": now.toISOString(), + "messageId": `system-${now.getTime()}`, + "modified": now.toISOString(), + "type": "MESSAGE", + "userGroupId": "system", + }; this.addMessage(systemMessage); } }, + + addBookACallInfo: function(bookACallInfo) { + this.__bookACallInfo = bookACallInfo; + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/support/ConversationPage.js b/services/static-webserver/client/source/class/osparc/support/ConversationPage.js index d7c1b87036c6..fd6381b3ba09 100644 --- a/services/static-webserver/client/source/class/osparc/support/ConversationPage.js +++ b/services/static-webserver/client/source/class/osparc/support/ConversationPage.js @@ -162,6 +162,10 @@ qx.Class.define("osparc.support.ConversationPage", { control = new osparc.support.Conversation(); this.getChildControl("conversation-container").add(control); break; + case "book-a-call-topic-selector": + control = new osparc.support.BookACallTopicSelector(); + this.getChildControl("main-stack").add(control); + break; case "book-a-call-iframe": control = new osparc.wrapper.BookACallIframe(); this.getChildControl("main-stack").add(control); @@ -185,11 +189,25 @@ qx.Class.define("osparc.support.ConversationPage", { break; case osparc.support.Conversation.SYSTEM_MESSAGE_TYPE.BOOK_A_CALL: title.setValue(this.tr("Book a Call")); + const bookACallTopicSelector = this.getChildControl("book-a-call-topic-selector"); + bookACallTopicSelector.getChildControl("next-button").setLabel(this.tr("Next")); + bookACallTopicSelector.addListener("callTopicSelected", e => { + const data = e.getData(); + conversationContent.addBookACallInfo(data); + this.getChildControl("main-stack").setSelection([conversationContainer]); + }); + this.getChildControl("main-stack").setSelection([bookACallTopicSelector]); break; case osparc.support.Conversation.SYSTEM_MESSAGE_TYPE.BOOK_A_CALL_3RD: { title.setValue(this.tr("Book a Call 3rd")); - const bookACallIframe = this.getChildControl("book-a-call-iframe"); - this.getChildControl("main-stack").setSelection([bookACallIframe]); + const bookACallTopicSelector = this.getChildControl("book-a-call-topic-selector"); + bookACallTopicSelector.getChildControl("next-button").setLabel(this.tr("Select date & time")); + bookACallTopicSelector.addListener("callTopicSelected", e => { + const data = e.getData(); + conversationContent.addBookACallInfo(data); + this.getChildControl("main-stack").setSelection([conversationContainer]); + }); + this.getChildControl("main-stack").setSelection([bookACallTopicSelector]); break; } case osparc.support.Conversation.SYSTEM_MESSAGE_TYPE.ESCALATE_TO_SUPPORT: diff --git a/services/static-webserver/client/source/class/osparc/support/ConversationsPage.js b/services/static-webserver/client/source/class/osparc/support/ConversationsPage.js index bbb45dd159b7..38d1ecc1fa38 100644 --- a/services/static-webserver/client/source/class/osparc/support/ConversationsPage.js +++ b/services/static-webserver/client/source/class/osparc/support/ConversationsPage.js @@ -27,7 +27,7 @@ qx.Class.define("osparc.support.ConversationsPage", { this.getChildControl("conversations-list"); this.getChildControl("ask-a-question-button"); this.getChildControl("book-a-call-button"); - if (osparc.utils.Utils.isDevelopmentPlatform()) { + if (osparc.product.Utils.isBookACallEnabled()) { this.getChildControl("book-a-call-button-3rd"); } }, diff --git a/services/static-webserver/client/source/class/osparc/support/HomePage.js b/services/static-webserver/client/source/class/osparc/support/HomePage.js index ac65bf740c43..a17173bf58cc 100644 --- a/services/static-webserver/client/source/class/osparc/support/HomePage.js +++ b/services/static-webserver/client/source/class/osparc/support/HomePage.js @@ -31,7 +31,7 @@ qx.Class.define("osparc.support.HomePage", { if (osparc.store.Groups.getInstance().isSupportEnabled()) { this.getChildControl("ask-a-question-button"); this.getChildControl("book-a-call-button"); - if (osparc.utils.Utils.isDevelopmentPlatform()) { + if (osparc.product.Utils.isBookACallEnabled()) { this.getChildControl("book-a-call-button-3rd"); } } @@ -127,39 +127,44 @@ qx.Class.define("osparc.support.HomePage", { }, __populateButtons: function() { - const learningBox = this.getChildControl("learning-box"); + const learningButtons = []; const quickStartButton = osparc.store.Support.getQuickStartButton(); if (quickStartButton) { - learningBox.add(quickStartButton); - this.self().decorateButton(quickStartButton); + learningButtons.push(quickStartButton); } - const permissions = osparc.data.Permissions.getInstance(); if (permissions.canDo("dashboard.templates.read")) { const tutorialsBtn = new qx.ui.form.Button(this.tr("Explore Tutorials"), "@FontAwesome5Solid/graduation-cap/14"); + const store = osparc.store.Store.getInstance(); + store.bind("currentStudy", tutorialsBtn, "enabled", { + converter: study => !Boolean(study) + }); tutorialsBtn.addListener("execute", () => qx.event.message.Bus.getInstance().dispatchByName("showTab", "tutorialsTab"), this); - learningBox.add(tutorialsBtn); - this.self().decorateButton(tutorialsBtn); + learningButtons.push(tutorialsBtn); } - const guidedToursButton = osparc.store.Support.getGuidedToursButton(); - learningBox.add(guidedToursButton); - this.self().decorateButton(guidedToursButton); + if (guidedToursButton) { + learningButtons.push(guidedToursButton); + } + if (learningButtons.length) { + const learningBox = this.getChildControl("learning-box"); + learningButtons.forEach(learningButton => { + learningBox.add(learningButton); + this.self().decorateButton(learningButton); + }); + } - const referencesBox = this.getChildControl("references-box"); const manualButtons = osparc.store.Support.getManualButtons(); - manualButtons.forEach(manualButton => { - referencesBox.add(manualButton); - this.self().decorateButton(manualButton); - this.self().addExternalLinkIcon(manualButton); - }); - const supportButtons = osparc.store.Support.getSupportButtons(); - supportButtons.forEach(supportButton => { - referencesBox.add(supportButton); - this.self().decorateButton(supportButton); - this.self().addExternalLinkIcon(supportButton); - }); + const referenceButtons = manualButtons.concat(supportButtons); + if (referenceButtons.length) { + const referencesBox = this.getChildControl("references-box"); + referenceButtons.forEach(referenceButton => { + referencesBox.add(referenceButton); + this.self().decorateButton(referenceButton); + this.self().addExternalLinkIcon(referenceButton); + }); + } const releaseNotesButton = osparc.store.Support.getReleaseNotesButton(); this._add(releaseNotesButton); 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 e89ba3e03d38..d47cb71637db 100644 --- a/services/static-webserver/client/source/class/osparc/theme/Appearance.js +++ b/services/static-webserver/client/source/class/osparc/theme/Appearance.js @@ -19,6 +19,16 @@ qx.Theme.define("osparc.theme.Appearance", { extend: osparc.theme.common.Appearance, appearances: { + "listing": { + style: () => { + return { + decorator: "no-border", + spacing: 3, + backgroundColor: "transparent" + }; + } + }, + "iframe-no-border": { style: () => { return { diff --git a/services/static-webserver/client/source/class/osparc/theme/ColorDark.js b/services/static-webserver/client/source/class/osparc/theme/ColorDark.js index a7fb3673b67b..e65b258dad50 100644 --- a/services/static-webserver/client/source/class/osparc/theme/ColorDark.js +++ b/services/static-webserver/client/source/class/osparc/theme/ColorDark.js @@ -6,7 +6,7 @@ qx.Theme.define("osparc.theme.ColorDark", { "c00": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105), "c01": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-5), "c02": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-10), - "c03": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-20), + "c03": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-17), "c04": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-25), "c05": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-35), "c06": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 105-50), diff --git a/services/static-webserver/client/source/class/osparc/theme/ColorLight.js b/services/static-webserver/client/source/class/osparc/theme/ColorLight.js index e6b8583074ad..d397c36e1d26 100644 --- a/services/static-webserver/client/source/class/osparc/theme/ColorLight.js +++ b/services/static-webserver/client/source/class/osparc/theme/ColorLight.js @@ -6,7 +6,7 @@ qx.Theme.define("osparc.theme.ColorLight", { "c00": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0), "c01": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+5), "c02": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+10), - "c03": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+20), + "c03": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+17), "c04": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+25), "c05": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+35), "c06": osparc.theme.colorProvider.ColorProvider.getColor("color.scales.static.base", 0+50), diff --git a/services/static-webserver/client/source/class/osparc/theme/colorProvider/ColorProvider.js b/services/static-webserver/client/source/class/osparc/theme/colorProvider/ColorProvider.js index ec0822c80bee..21631b191db3 100644 --- a/services/static-webserver/client/source/class/osparc/theme/colorProvider/ColorProvider.js +++ b/services/static-webserver/client/source/class/osparc/theme/colorProvider/ColorProvider.js @@ -81,6 +81,12 @@ qx.Class.define("osparc.theme.colorProvider.ColorProvider", { 228, 1 ], + "17": [ + 215, + 221, + 224, + 1 + ], "20": [ 210, 216, @@ -165,6 +171,12 @@ qx.Class.define("osparc.theme.colorProvider.ColorProvider", { 84, 1 ], + "88": [ + 65, + 72, + 77, + 1 + ], "90": [ 59, 66, diff --git a/services/static-webserver/client/source/class/osparc/ui/list/CollaboratorListItem.js b/services/static-webserver/client/source/class/osparc/ui/list/CollaboratorListItem.js index 9ef3d0b03e6f..78b6aec28f97 100644 --- a/services/static-webserver/client/source/class/osparc/ui/list/CollaboratorListItem.js +++ b/services/static-webserver/client/source/class/osparc/ui/list/CollaboratorListItem.js @@ -18,12 +18,6 @@ qx.Class.define("osparc.ui.list.CollaboratorListItem", { extend: osparc.ui.list.ListItem, - construct: function() { - this.base(arguments); - - this.setCursor("default"); - }, - properties: { collabType: { check: [ diff --git a/services/static-webserver/client/source/class/osparc/ui/list/ListItem.js b/services/static-webserver/client/source/class/osparc/ui/list/ListItem.js index 296486eaf78b..257c7d3185c2 100644 --- a/services/static-webserver/client/source/class/osparc/ui/list/ListItem.js +++ b/services/static-webserver/client/source/class/osparc/ui/list/ListItem.js @@ -63,6 +63,7 @@ qx.Class.define("osparc.ui.list.ListItem", { decorator: "rounded", }); + this.setBackgroundColor("background-main-2"); this.addListener("pointerover", this._onPointerOver, this); this.addListener("pointerout", this._onPointerOut, this); }, @@ -130,7 +131,6 @@ qx.Class.define("osparc.ui.list.ListItem", { this.addState("hovered"); }, - /** * Event handler for the pointer out event. */ diff --git a/services/static-webserver/client/source/class/osparc/vipMarket/VipMarket.js b/services/static-webserver/client/source/class/osparc/vipMarket/VipMarket.js index 7cf61cfcbac0..17a90850f439 100644 --- a/services/static-webserver/client/source/class/osparc/vipMarket/VipMarket.js +++ b/services/static-webserver/client/source/class/osparc/vipMarket/VipMarket.js @@ -112,10 +112,8 @@ qx.Class.define("osparc.vipMarket.VipMarket", { break; case "models-list": control = new qx.ui.form.List().set({ - decorator: "no-border", - spacing: 5, + appearance: "listing", width: 250, - backgroundColor: "transparent", }); this.getChildControl("left-side").add(control, { flex: 1