diff --git a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js index a80672bd3cd..344507aad9a 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/ResourceBrowserBase.js @@ -95,7 +95,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { return isLogged; }, - startStudyById: function(studyId, openCB, cancelCB, isStudyCreation = false) { + startStudyById: function(studyId, openCB, cancelCB, showStudyOptions = false) { if (!osparc.dashboard.ResourceBrowserBase.checkLoggedIn()) { return; } @@ -117,7 +117,7 @@ qx.Class.define("osparc.dashboard.ResourceBrowserBase", { osparc.data.Resources.fetch("studies", "getWallet", params) .then(wallet => { if ( - isStudyCreation || + showStudyOptions || wallet === null || osparc.desktop.credits.Utils.getWallet(wallet["walletId"]) === null ) { diff --git a/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js index ceaee03b3ac..a2de2032524 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/StudyBrowser.js @@ -1229,7 +1229,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { folderId: this.getCurrentFolderId(), }; osparc.study.Utils.createStudyFromTemplate(templateCopyData, this._loadingPage, contextProps) - .then(studyId => this.__startStudyAfterCreating(studyId)) + .then(studyData => this.__startStudyAfterCreating(studyData["uuid"])) .catch(err => { this._hideLoadingPage(); osparc.FlashMessenger.getInstance().logAs(err.message, "ERROR"); diff --git a/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js b/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js index d597d8a438c..7f4f0362cab 100644 --- a/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js +++ b/services/static-webserver/client/source/class/osparc/dashboard/TemplateBrowser.js @@ -137,27 +137,85 @@ qx.Class.define("osparc.dashboard.TemplateBrowser", { return; } - this._showLoadingPage(this.tr("Creating ") + (templateData.name || osparc.product.Utils.getStudyAlias({firstUpperCase: true}))); - osparc.study.Utils.createStudyFromTemplate(templateData, this._loadingPage) - .then(studyId => { - const openCB = () => this._hideLoadingPage(); - const cancelCB = () => { - this._hideLoadingPage(); - const params = { - url: { - studyId - } + const studyAlias = osparc.product.Utils.getStudyAlias({firstUpperCase: true}); + this._showLoadingPage(this.tr("Creating ") + (templateData.name || studyAlias)); + + const studyOptions = new osparc.study.StudyOptions(); + // they will be patched once the study is created + studyOptions.setPatchStudy(false); + studyOptions.setStudyData(templateData); + const win = osparc.study.StudyOptions.popUpInWindow(studyOptions); + win.moveItUp(); + const cancelStudyOptions = () => { + this._hideLoadingPage(); + win.close(); + } + win.addListener("cancel", () => cancelStudyOptions()); + studyOptions.addListener("cancel", () => cancelStudyOptions()); + studyOptions.addListener("startStudy", () => { + const newName = studyOptions.getChildControl("title-field").getValue(); + const walletSelection = studyOptions.getChildControl("wallet-selector").getSelection(); + const nodesPricingUnits = studyOptions.getChildControl("study-pricing-units").getNodePricingUnits(); + win.close(); + this._showLoadingPage(this.tr("Creating ") + (newName || studyAlias)); + osparc.study.Utils.createStudyFromTemplate(templateData, this._loadingPage) + .then(newStudyData => { + const studyId = newStudyData["uuid"]; + const openCB = () => { + this._hideLoadingPage(); }; - osparc.data.Resources.fetch("studies", "delete", params); - }; - const isStudyCreation = true; - this._startStudyById(studyId, openCB, cancelCB, isStudyCreation); - }) - .catch(err => { - this._hideLoadingPage(); - osparc.FlashMessenger.getInstance().logAs(err.message, "ERROR"); - console.error(err); - }); + const cancelCB = () => { + this._hideLoadingPage(); + const params = { + url: { + studyId + } + }; + osparc.data.Resources.fetch("studies", "delete", params); + }; + + const promises = []; + // patch the name + if (newStudyData["name"] !== newName) { + promises.push(osparc.study.StudyOptions.updateName(newStudyData, newName)); + } + // patch the wallet + if (walletSelection.length && walletSelection[0]["walletId"]) { + const walletId = walletSelection[0]["walletId"]; + promises.push(osparc.study.StudyOptions.updateWallet(newStudyData["uuid"], walletId)); + } + // patch the pricing units + // the nodeIds are coming from the original template, they need to be mapped to the newStudy + const workbench = newStudyData["workbench"]; + const nodesIdsListed = []; + Object.keys(workbench).forEach(nodeId => { + const node = workbench[nodeId]; + if (osparc.study.StudyPricingUnits.includeInList(node)) { + nodesIdsListed.push(nodeId); + } + }); + nodesPricingUnits.forEach((nodePricingUnits, idx) => { + const selectedPricingUnitId = nodePricingUnits.getPricingUnits().getSelectedUnitId(); + if (selectedPricingUnitId) { + const nodeId = nodesIdsListed[idx]; + const pricingPlanId = nodePricingUnits.getPricingPlanId(); + promises.push(osparc.study.NodePricingUnits.patchPricingUnitSelection(studyId, nodeId, pricingPlanId, selectedPricingUnitId)); + } + }); + + Promise.all(promises) + .then(() => { + win.close(); + const showStudyOptions = false; + this._startStudyById(studyId, openCB, cancelCB, showStudyOptions); + }); + }) + .catch(err => { + this._hideLoadingPage(); + osparc.FlashMessenger.getInstance().logAs(err.message, "ERROR"); + console.error(err); + }); + }); }, // LAYOUT // diff --git a/services/static-webserver/client/source/class/osparc/node/TierSelectionView.js b/services/static-webserver/client/source/class/osparc/node/TierSelectionView.js index 34dfc397b37..ffa1431a00e 100644 --- a/services/static-webserver/client/source/class/osparc/node/TierSelectionView.js +++ b/services/static-webserver/client/source/class/osparc/node/TierSelectionView.js @@ -105,7 +105,7 @@ qx.Class.define("osparc.node.TierSelectionView", { if (selection.length) { tierBox.setEnabled(false); const selectedUnitId = selection[0].getModel(); - osparc.study.NodePricingUnits.pricingUnitSelected(studyId, nodeId, pricingPlans["pricingPlanId"], selectedUnitId) + osparc.study.NodePricingUnits.patchPricingUnitSelection(studyId, nodeId, pricingPlans["pricingPlanId"], selectedUnitId) .finally(() => { tierBox.setEnabled(true); showSelectedTier(selectedUnitId); diff --git a/services/static-webserver/client/source/class/osparc/study/NodePricingUnits.js b/services/static-webserver/client/source/class/osparc/study/NodePricingUnits.js index d8caa28b68f..76918e12b3e 100644 --- a/services/static-webserver/client/source/class/osparc/study/NodePricingUnits.js +++ b/services/static-webserver/client/source/class/osparc/study/NodePricingUnits.js @@ -30,8 +30,10 @@ qx.Class.define("osparc.study.NodePricingUnits", { layout: new qx.ui.layout.VBox() }); - this.__studyId = studyId; - this.__nodeId = nodeId; + this.set({ + studyId, + nodeId, + }); if (node instanceof osparc.data.model.Node) { this.__nodeKey = node.getKey(); this.__nodeVersion = node.getVersion(); @@ -43,8 +45,35 @@ qx.Class.define("osparc.study.NodePricingUnits", { } }, + properties: { + studyId: { + check: "String", + init: null, + nullable: false, + }, + + nodeId: { + check: "String", + init: null, + nullable: false, + }, + + pricingPlanId: { + check: "Number", + init: null, + nullable: false, + }, + + patchNode: { + check: "Boolean", + init: true, + nullable: false, + event: "changePatchNode", + }, + }, + statics: { - pricingUnitSelected: function(studyId, nodeId, planId, selectedUnitId) { + patchPricingUnitSelection: function(studyId, nodeId, planId, selectedUnitId) { const params = { url: { studyId, @@ -58,19 +87,18 @@ qx.Class.define("osparc.study.NodePricingUnits", { }, members: { - __studyId: null, - __nodeId: null, __nodeKey: null, __nodeVersion: null, __nodeLabel: null, + __pricingUnits: null, showPricingUnits: function(inGroupBox = true) { return new Promise(resolve => { const nodeKey = this.__nodeKey; const nodeVersion = this.__nodeVersion; const nodeLabel = this.__nodeLabel; - const studyId = this.__studyId; - const nodeId = this.__nodeId; + const studyId = this.getStudyId(); + const nodeId = this.getNodeId(); const plansParams = { url: osparc.data.Resources.getServiceUrl( @@ -79,30 +107,36 @@ qx.Class.define("osparc.study.NodePricingUnits", { ) }; osparc.data.Resources.fetch("services", "pricingPlans", plansParams) - .then(pricingPlans => { - if (pricingPlans) { + .then(pricingPlan => { + if (pricingPlan) { const unitParams = { url: { studyId, nodeId } }; + this.set({ + pricingPlanId: pricingPlan["pricingPlanId"] + }); osparc.data.Resources.fetch("studies", "getPricingUnit", unitParams) .then(preselectedPricingUnit => { - if (pricingPlans && "pricingUnits" in pricingPlans && pricingPlans["pricingUnits"].length) { - const unitButtons = new osparc.study.PricingUnits(pricingPlans["pricingUnits"], preselectedPricingUnit); + if (pricingPlan && "pricingUnits" in pricingPlan && pricingPlan["pricingUnits"].length) { + const pricingUnitButtons = this.__pricingUnits = new osparc.study.PricingUnits(pricingPlan["pricingUnits"], preselectedPricingUnit); if (inGroupBox) { const pricingUnitsLayout = osparc.study.StudyOptions.createGroupBox(nodeLabel); - pricingUnitsLayout.add(unitButtons); + pricingUnitsLayout.add(pricingUnitButtons); this._add(pricingUnitsLayout); } else { - this._add(unitButtons); + this._add(pricingUnitButtons); } - unitButtons.addListener("changeSelectedUnitId", e => { - unitButtons.setEnabled(false); - const selectedPricingUnitId = e.getData(); - this.self().pricingUnitSelected(this.__studyId, this.__nodeId, pricingPlans["pricingPlanId"], selectedPricingUnitId) - .finally(() => unitButtons.setEnabled(true)); + pricingUnitButtons.addListener("changeSelectedUnitId", e => { + if (this.isPatchNode()) { + pricingUnitButtons.setEnabled(false); + const pricingPlanId = this.getPricingPlanId(); + const selectedPricingUnitId = e.getData(); + this.self().patchPricingUnitSelection(studyId, nodeId, pricingPlanId, selectedPricingUnitId) + .finally(() => pricingUnitButtons.setEnabled(true)); + } }); } }) @@ -110,6 +144,10 @@ qx.Class.define("osparc.study.NodePricingUnits", { } }); }); - } + }, + + getPricingUnits: function() { + return this.__pricingUnits; + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/study/StudyOptions.js b/services/static-webserver/client/source/class/osparc/study/StudyOptions.js index 9922ec017e3..5b0fd30cadb 100644 --- a/services/static-webserver/client/source/class/osparc/study/StudyOptions.js +++ b/services/static-webserver/client/source/class/osparc/study/StudyOptions.js @@ -22,8 +22,11 @@ qx.Class.define("osparc.study.StudyOptions", { this.base(arguments); this._setLayout(new qx.ui.layout.VBox(15)); + this.__buildLayout(); - this.setStudyId(studyId); + if (studyId) { + this.setStudyId(studyId); + } }, properties: { @@ -40,7 +43,14 @@ qx.Class.define("osparc.study.StudyOptions", { nullable: true, event: "changeWallet", apply: "__applyWallet" - } + }, + + patchStudy: { + check: "Boolean", + init: true, + nullable: false, + event: "changePatchStudy", + }, }, events: { @@ -78,7 +88,31 @@ qx.Class.define("osparc.study.StudyOptions", { }); box.setLayout(new qx.ui.layout.VBox(5)); return box; - } + }, + + updateName: function(studyData, name) { + return osparc.info.StudyUtils.patchStudyData(studyData, "name", name) + .catch(err => { + console.error(err); + const msg = err.message || qx.locale.Manager.tr("Something went wrong Renaming"); + osparc.FlashMessenger.logAs(msg, "ERROR"); + }); + }, + + updateWallet: function(studyId, walletId) { + const params = { + url: { + studyId, + walletId, + } + }; + return osparc.data.Resources.fetch("studies", "selectWallet", params) + .catch(err => { + console.error(err); + const msg = err.message || qx.locale.Manager.tr("Error selecting Credit Account"); + osparc.FlashMessenger.getInstance().logAs(msg, "ERROR"); + }); + }, }, members: { @@ -147,6 +181,27 @@ qx.Class.define("osparc.study.StudyOptions", { control = this.self().createGroupBox(this.tr("Tiers")); this.getChildControl("options-layout").add(control); break; + case "study-pricing-units": { + control = new osparc.study.StudyPricingUnits(); + const loadingImage = this.getChildControl("loading-units-spinner"); + const unitsBoxesLayout = this.getChildControl("services-resources-layout"); + const unitsLoading = () => { + loadingImage.show(); + unitsBoxesLayout.exclude(); + }; + const unitsReady = () => { + loadingImage.exclude(); + unitsBoxesLayout.show(); + control.getNodePricingUnits().forEach(nodePricingUnits => { + this.bind("patchStudy", nodePricingUnits, "patchNode"); + }); + }; + unitsLoading(); + control.addListener("loadingUnits", () => unitsLoading()); + control.addListener("unitsReady", () => unitsReady()); + unitsBoxesLayout.add(control); + break; + } case "buttons-layout": control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({ alignX: "right" @@ -192,7 +247,7 @@ qx.Class.define("osparc.study.StudyOptions", { ]) .then(values => { const studyData = values[0]; - this.__studyData = osparc.data.model.Study.deepCloneStudyObject(studyData); + this.setStudyData(studyData); if (values[1] && "walletId" in values[1]) { this.__studyWalletId = values[1]["walletId"]; @@ -201,6 +256,16 @@ qx.Class.define("osparc.study.StudyOptions", { }); }, + setStudyData: function(studyData) { + this.__studyData = osparc.data.model.Study.deepCloneStudyObject(studyData); + + const titleField = this.getChildControl("title-field"); + titleField.setValue(this.__studyData["name"]); + + const studyPricingUnits = this.getChildControl("study-pricing-units"); + studyPricingUnits.setStudyData(this.__studyData); + }, + __applyWallet: function(wallet) { if (wallet) { const walletSelector = this.getChildControl("wallet-selector"); @@ -224,9 +289,6 @@ qx.Class.define("osparc.study.StudyOptions", { const store = osparc.store.Store.getInstance(); const titleField = this.getChildControl("title-field"); - if (this.__studyData) { - titleField.setValue(this.__studyData["name"]); - } titleField.addListener("appear", () => { titleField.focus(); titleField.activate(); @@ -261,21 +323,7 @@ qx.Class.define("osparc.study.StudyOptions", { }, __buildOptionsLayout: function() { - const loadingImage = this.getChildControl("loading-units-spinner"); - const unitsBoxesLayout = this.getChildControl("services-resources-layout"); - const unitsLoading = () => { - loadingImage.show(); - unitsBoxesLayout.exclude(); - }; - const unitsReady = () => { - loadingImage.exclude(); - unitsBoxesLayout.show(); - }; - unitsLoading(); - const studyPricingUnits = new osparc.study.StudyPricingUnits(this.__studyData); - studyPricingUnits.addListener("loadingUnits", () => unitsLoading()); - studyPricingUnits.addListener("unitsReady", () => unitsReady()); - unitsBoxesLayout.add(studyPricingUnits); + this.getChildControl("study-pricing-units"); }, __buildButtons: function() { @@ -291,48 +339,34 @@ qx.Class.define("osparc.study.StudyOptions", { const openButton = this.getChildControl("open-button"); openButton.setFetching(true); - // first, update the name if necessary - const titleSelection = this.getChildControl("title-field").getValue(); - if (this.__studyData && this.__studyData["name"] !== titleSelection) { - await this.__updateName(this.__studyData, titleSelection); - } + if (this.isPatchStudy()) { + // first, update the name if necessary + const titleSelection = this.getChildControl("title-field").getValue(); + if (this.__studyData["name"] !== titleSelection) { + await this.self().updateName(this.__studyData, titleSelection); + } - // second, update the wallet if necessary - const store = osparc.store.Store.getInstance(); - const walletSelection = this.getChildControl("wallet-selector").getSelection(); - const studyId = this.getStudyId(); - if (studyId && walletSelection.length && walletSelection[0]["walletId"]) { - const params = { - url: { - studyId, - "walletId": walletSelection[0]["walletId"] - } - }; - osparc.data.Resources.fetch("studies", "selectWallet", params) - .then(() => { - store.setActiveWallet(this.getWallet()); - this.fireEvent("startStudy"); - }) - .catch(err => { - console.error(err); - const msg = err.message || this.tr("Error selecting Credit Account"); - osparc.FlashMessenger.getInstance().logAs(msg, "ERROR"); - }) - .finally(() => openButton.setFetching(false)); + // second, update the wallet if necessary + const store = osparc.store.Store.getInstance(); + const walletSelection = this.getChildControl("wallet-selector").getSelection(); + if (walletSelection.length && walletSelection[0]["walletId"]) { + const studyId = this.getStudyId(); + const walletId = walletSelection[0]["walletId"]; + this.self().updateWallet(studyId, walletId) + .then(() => { + store.setActiveWallet(this.getWallet()); + this.fireEvent("startStudy"); + }) + .finally(() => openButton.setFetching(false)); + } else { + store.setActiveWallet(this.getWallet()); + this.fireEvent("startStudy"); + openButton.setFetching(false); + } } else { - store.setActiveWallet(this.getWallet()); this.fireEvent("startStudy"); openButton.setFetching(false); } }, - - __updateName: function(studyData, name) { - return osparc.info.StudyUtils.patchStudyData(studyData, "name", name) - .catch(err => { - console.error(err); - const msg = this.tr("Something went wrong Renaming"); - osparc.FlashMessenger.logAs(msg, "ERROR"); - }); - } } }); diff --git a/services/static-webserver/client/source/class/osparc/study/StudyPricingUnits.js b/services/static-webserver/client/source/class/osparc/study/StudyPricingUnits.js index 793fee5cb34..e3e8514fbaf 100644 --- a/services/static-webserver/client/source/class/osparc/study/StudyPricingUnits.js +++ b/services/static-webserver/client/source/class/osparc/study/StudyPricingUnits.js @@ -25,9 +25,11 @@ qx.Class.define("osparc.study.StudyPricingUnits", { layout: new qx.ui.layout.VBox(5) }); - this.__studyData = studyData; + this.__nodePricingUnits = []; - this.__showPricingUnits(); + if (studyData) { + this.setStudyData(studyData); + } }, events: { @@ -35,8 +37,20 @@ qx.Class.define("osparc.study.StudyPricingUnits", { "unitsReady": "qx.event.type.Event" }, + statics: { + includeInList: function(node) { + return !osparc.data.model.Node.isFrontend(node); + }, + }, + members: { __studyData: null, + __nodePricingUnits: null, + + setStudyData: function(studyData) { + this.__studyData = studyData; + this.__showPricingUnits(); + }, __showPricingUnits: function() { const unitsLoading = () => this.fireEvent("loadingUnits"); @@ -48,16 +62,20 @@ qx.Class.define("osparc.study.StudyPricingUnits", { const workbench = this.__studyData["workbench"]; Object.keys(workbench).forEach(nodeId => { const node = workbench[nodeId]; - if (osparc.data.model.Node.isFrontend(node)) { - return; + if (this.self().includeInList(node)) { + const nodePricingUnits = new osparc.study.NodePricingUnits(this.__studyData["uuid"], nodeId, node); + this.__nodePricingUnits.push(nodePricingUnits); + this._add(nodePricingUnits); + promises.push(nodePricingUnits.showPricingUnits()); } - const nodePricingUnits = new osparc.study.NodePricingUnits(this.__studyData["uuid"], nodeId, node); - this._add(nodePricingUnits); - promises.push(nodePricingUnits.showPricingUnits()); }); } Promise.all(promises) .then(() => unitsAdded()); - } + }, + + getNodePricingUnits: function() { + return this.__nodePricingUnits; + }, } }); diff --git a/services/static-webserver/client/source/class/osparc/study/Utils.js b/services/static-webserver/client/source/class/osparc/study/Utils.js index 0240d263e47..66ed40201f4 100644 --- a/services/static-webserver/client/source/class/osparc/study/Utils.js +++ b/services/static-webserver/client/source/class/osparc/study/Utils.js @@ -255,7 +255,7 @@ qx.Class.define("osparc.study.Utils", { }, this); task.addListener("resultReceived", e => { const studyData = e.getData(); - resolve(studyData["uuid"]); + resolve(studyData); }, this); task.addListener("pollingError", e => { const err = e.getData();