diff --git a/services/web/client/source/class/explorer/NavigationBar.js b/services/web/client/source/class/explorer/NavigationBar.js index c4587e68450..81e0f0f3f7b 100644 --- a/services/web/client/source/class/explorer/NavigationBar.js +++ b/services/web/client/source/class/explorer/NavigationBar.js @@ -16,7 +16,7 @@ ************************************************************************ */ qx.Class.define("explorer.NavigationBar", { - extend: osparc.desktop.NavigationBar, + extend: osparc.navigation.NavigationBar, members: { buildLayout: function() { diff --git a/services/web/client/source/class/osparc/component/metadata/QualityEditor.js b/services/web/client/source/class/osparc/component/metadata/QualityEditor.js index 91eda703d3d..c4a8d174b80 100644 --- a/services/web/client/source/class/osparc/component/metadata/QualityEditor.js +++ b/services/web/client/source/class/osparc/component/metadata/QualityEditor.js @@ -594,10 +594,12 @@ qx.Class.define("osparc.component.metadata.QualityEditor", { __isUserOwner: function() { const myGid = osparc.auth.Data.getInstance().getGroupId(); if (myGid) { - if (osparc.utils.Resources.isService(this.__resourceData)) { + if ("access_rights" in this.__resourceData) { return osparc.component.export.ServicePermissions.canGroupWrite(this.__resourceData["access_rights"], myGid); } - return osparc.component.export.StudyPermissions.canGroupWrite(this.__resourceData["accessRights"], myGid); + if ("accessRights" in this.__resourceData) { + return osparc.component.export.StudyPermissions.canGroupWrite(this.__resourceData["accessRights"], myGid); + } } return false; } diff --git a/services/web/client/source/class/osparc/component/widget/Thumbnail.js b/services/web/client/source/class/osparc/component/widget/Thumbnail.js index 582313a4ef8..d36fc310a97 100644 --- a/services/web/client/source/class/osparc/component/widget/Thumbnail.js +++ b/services/web/client/source/class/osparc/component/widget/Thumbnail.js @@ -57,11 +57,7 @@ qx.Class.define("osparc.component.widget.Thumbnail", { }); }); - const image = this.getChildControl("image").set({ - scale: true, - allowStretchX: true, - allowStretchY: true - }); + const image = this.getChildControl("image"); if (source) { image.setSource(source); @@ -91,6 +87,9 @@ qx.Class.define("osparc.component.widget.Thumbnail", { switch (id) { case "image": control = new qx.ui.basic.Image().set({ + scale: true, + allowStretchX: true, + allowStretchY: true, alignX: "center", alignY: "middle" }); diff --git a/services/web/client/source/class/osparc/component/workbench/SvgWidget.js b/services/web/client/source/class/osparc/component/workbench/SvgWidget.js index f480da26297..3d3af0e1a7b 100644 --- a/services/web/client/source/class/osparc/component/workbench/SvgWidget.js +++ b/services/web/client/source/class/osparc/component/workbench/SvgWidget.js @@ -38,14 +38,12 @@ qx.Class.define("osparc.component.workbench.SvgWidget", { construct: function() { this.base(); this.addListenerOnce("appear", () => { - const randomID = Math.random().toString(36).substring(7); const el = this.getContentElement().getDomElement(); - qx.bom.element.Attribute.set(el, "id", randomID); const svgWrapper = osparc.wrapper.Svg.getInstance(); svgWrapper.init() .then(() => { if (this.__canvas === null) { - this.__canvas = svgWrapper.createEmptyCanvas(randomID); + this.__canvas = svgWrapper.createEmptyCanvas(el); this.setReady(true); this.fireDataEvent("SvgWidgetReady", true); } diff --git a/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js b/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js index 81e68353823..3cff2671740 100644 --- a/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js +++ b/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js @@ -137,6 +137,8 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { return borderStyle; }, + TOP_OFFSET: 50 + 46, + ZoomValues: [0.25, 0.4, 0.5, 0.6, 0.8, 1, 1.25, 1.5, 2, 3] }, @@ -282,7 +284,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { const maxHeight = this.getBounds().height - osparc.component.workbench.ServiceCatalog.Height; const posX = Math.min(winPos.x, maxLeft); const posY = Math.min(winPos.y, maxHeight); - srvCat.moveTo(posX + this.__getSidePanelWidth(), posY + 50); + srvCat.moveTo(posX + this.__getSidePanelWidth(), posY + this.self().TOP_OFFSET); srvCat.addListener("addService", e => { this.__addServiceFromCatalog(e.getData(), srvPos); }, this); @@ -410,6 +412,14 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { return this.__selectedNodes; }, + getSelectedNodeIDs: function() { + const selectedNodeIDs = []; + this.__selectedNodes.forEach(nodeUI => { + selectedNodeIDs.push(nodeUI.getNodeId()); + }); + return selectedNodeIDs; + }, + resetSelectedNodes: function() { this.__selectedNodes.forEach(node => node.removeState("selected")); this.__selectedNodes = []; @@ -725,11 +735,10 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { }, __pointerEventToWorkbenchPos: function(pointerEvent, scale = false) { - const topOffset = 50; const leftOffset = this.__getSidePanelWidth(); const inputNodesLayoutWidth = this.__inputNodesLayout.isVisible() ? this.__inputNodesLayout.getWidth() : 0; const x = pointerEvent.getDocumentLeft() - leftOffset - inputNodesLayoutWidth; - const y = pointerEvent.getDocumentTop() - topOffset; + const y = pointerEvent.getDocumentTop() - this.self().TOP_OFFSET; if (scale) { return this.__scaleCoordinates(x, y); } @@ -1105,9 +1114,9 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { const commandDel = new qx.ui.command.Command("Delete"); commandDel.addListener("execute", () => { - const selectedNodes = this.getSelectedNodes(); - if (selectedNodes.length === 1) { - this.fireDataEvent("removeNode", selectedNodes[0].getNodeId()); + const selectedNodeIDs = this.getSelectedNodeIDs(); + if (selectedNodeIDs.length === 1) { + this.fireDataEvent("removeNode", selectedNodeIDs[0]); } }); diff --git a/services/web/client/source/class/osparc/dashboard/ExploreBrowser.js b/services/web/client/source/class/osparc/dashboard/ExploreBrowser.js index c7d3d02944e..0df7f725e61 100644 --- a/services/web/client/source/class/osparc/dashboard/ExploreBrowser.js +++ b/services/web/client/source/class/osparc/dashboard/ExploreBrowser.js @@ -349,7 +349,13 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { this.self().sortTemplateList(tempStudyList); tempStudyList.forEach(tempStudy => { tempStudy["resourceType"] = "template"; - this.__templatesContainer.add(this.__createStudyItem(tempStudy)); + const templateItem = this.__createStudyItem(tempStudy); + templateItem.addListener("updateQualityTemplate", e => { + const updatedTemplateData = e.getData(); + updatedTemplateData["resourceType"] = "template"; + this._resetTemplateItem(updatedTemplateData); + }, this); + this.__templatesContainer.add(templateItem); }); osparc.component.filter.UIFilterController.dispatch("sideSearchFilter"); }, @@ -370,7 +376,13 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { this.__servicesContainer.removeAll(); servicesList.forEach(service => { service["resourceType"] = "service"; - this.__servicesContainer.add(this.__createStudyItem(service)); + const serviceItem = this.__createStudyItem(service); + serviceItem.addListener("updateQualityService", e => { + const updatedServiceData = e.getData(); + updatedServiceData["resourceType"] = "service"; + this._resetServiceItem(updatedServiceData); + }, this); + this.__servicesContainer.add(serviceItem); }); osparc.component.filter.UIFilterController.dispatch("sideSearchFilter"); }, @@ -462,11 +474,7 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { const permissionsButton = new qx.ui.menu.Button(this.tr("Permissions")); permissionsButton.addListener("execute", () => { - if (osparc.utils.Resources.isTemplate(studyData)) { - this.__openTemplatePermissions(studyData); - } else if (osparc.utils.Resources.isService(studyData)) { - this.__openServicePermissions(studyData); - } + this.__openPermissions(studyData); }, this); return permissionsButton; }, @@ -483,27 +491,6 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { return classifiersButton; }, - __openClassifiers: function(studyData) { - const title = this.tr("Classifiers"); - let classifiers = null; - if (osparc.data.model.Study.isOwner(studyData)) { - classifiers = new osparc.component.metadata.ClassifiersEditor(studyData); - osparc.ui.window.Window.popUpInWindow(classifiers, title, 400, 400); - classifiers.addListener("updateResourceClassifiers", e => { - if (osparc.utils.Resources.isTemplate(studyData)) { - const studyId = e.getData(); - this._reloadTemplate(studyId); - } else if (osparc.utils.Resources.isService(studyData)) { - const serviceKey = e.getData(); - this.__reloadService(serviceKey, studyData.version); - } - }, this); - } else { - classifiers = new osparc.component.metadata.ClassifiersViewer(studyData); - } - osparc.ui.window.Window.popUpInWindow(classifiers, title, 400, 400); - }, - __getStudyServicesMenuButton: function(studyData) { if (osparc.utils.Resources.isService(studyData)) { return null; @@ -579,6 +566,14 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { }); }, + __openPermissions: function(studyData) { + if (osparc.utils.Resources.isTemplate(studyData)) { + this.__openTemplatePermissions(studyData); + } else if (osparc.utils.Resources.isService(studyData)) { + this.__openServicePermissions(studyData); + } + }, + __openServicePermissions: function(serviceData) { const permissionsView = new osparc.component.export.ServicePermissions(serviceData); const title = this.tr("Available to"); @@ -600,6 +595,27 @@ qx.Class.define("osparc.dashboard.ExploreBrowser", { }); }, + __openClassifiers: function(studyData) { + const title = this.tr("Classifiers"); + let classifiers = null; + if (osparc.data.model.Study.isOwner(studyData)) { + classifiers = new osparc.component.metadata.ClassifiersEditor(studyData); + osparc.ui.window.Window.popUpInWindow(classifiers, title, 400, 400); + classifiers.addListener("updateResourceClassifiers", e => { + if (osparc.utils.Resources.isTemplate(studyData)) { + const studyId = e.getData(); + this._reloadTemplate(studyId); + } else if (osparc.utils.Resources.isService(studyData)) { + const serviceKey = e.getData(); + this.__reloadService(serviceKey, studyData.version); + } + }, this); + } else { + classifiers = new osparc.component.metadata.ClassifiersViewer(studyData); + } + osparc.ui.window.Window.popUpInWindow(classifiers, title, 400, 400); + }, + __deleteTemplate: function(studyData) { const myGid = osparc.auth.Data.getInstance().getGroupId(); const collabGids = Object.keys(studyData["accessRights"]); diff --git a/services/web/client/source/class/osparc/dashboard/StudyBrowser.js b/services/web/client/source/class/osparc/dashboard/StudyBrowser.js index a4716d7c236..8ded5c6e9be 100644 --- a/services/web/client/source/class/osparc/dashboard/StudyBrowser.js +++ b/services/web/client/source/class/osparc/dashboard/StudyBrowser.js @@ -350,7 +350,13 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { if (osparc.data.model.Study.isStudySecondary(userStudy)) { return; } - this.__userStudyContainer.add(this.__createStudyItem(userStudy)); + const studyItem = this.__createStudyItem(userStudy); + studyItem.addListener("updateQualityStudy", e => { + const updatedStudyData = e.getData(); + updatedStudyData["resourceType"] = "study"; + this._resetStudyItem(updatedStudyData); + }, this); + this.__userStudyContainer.add(studyItem); }); osparc.component.filter.UIFilterController.dispatch("sideSearchFilter"); }, @@ -455,13 +461,7 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { __getPermissionsMenuButton: function(studyData) { const permissionsButton = new qx.ui.menu.Button(this.tr("Permissions")); permissionsButton.addListener("execute", () => { - const permissionsView = new osparc.component.export.StudyPermissions(studyData); - const title = this.tr("Share with Collaborators and Organizations"); - osparc.ui.window.Window.popUpInWindow(permissionsView, title, 400, 300); - permissionsView.addListener("updateStudy", e => { - const studyId = e.getData(); - this._reloadStudy(studyId); - }, this); + this.__openPermissions(studyData); }, this); return permissionsButton; }, @@ -478,6 +478,16 @@ qx.Class.define("osparc.dashboard.StudyBrowser", { return classifiersButton; }, + __openPermissions: function(studyData) { + const permissionsView = new osparc.component.export.StudyPermissions(studyData); + const title = this.tr("Share with Collaborators and Organizations"); + osparc.ui.window.Window.popUpInWindow(permissionsView, title, 400, 300); + permissionsView.addListener("updateStudy", e => { + const studyId = e.getData(); + this._reloadStudy(studyId); + }, this); + }, + __openClassifiers: function(studyData) { const title = this.tr("Classifiers"); let classifiers = null; diff --git a/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonBase.js b/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonBase.js index e1e9a38db6e..a9eb1c8206f 100644 --- a/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonBase.js +++ b/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonBase.js @@ -39,7 +39,10 @@ qx.Class.define("osparc.dashboard.StudyBrowserButtonBase", { this._setLayout(new qx.ui.layout.Canvas()); - const mainLayout = this._mainLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6)); + const mainLayout = this._mainLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(6)).set({ + maxWidth: this.self().ITEM_WIDTH - 2*this.self().PADDING, + maxHeight: this.self().ITEM_HEIGHT - 2*this.self().PADDING + }); this._add(mainLayout, { top: 0, right: 0, @@ -125,7 +128,7 @@ qx.Class.define("osparc.dashboard.StudyBrowserButtonBase", { } case "icon": { const maxWidth = this.self().ITEM_WIDTH - 2*this.self().PADDING; - const image = new osparc.component.widget.Thumbnail(null, maxWidth, 130); + const image = new osparc.component.widget.Thumbnail(null, maxWidth, 124); control = image.getChildControl("image").set({ anonymous: true }); diff --git a/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonItem.js b/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonItem.js index 64b5d7daf21..e16b99c8630 100644 --- a/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonItem.js +++ b/services/web/client/source/class/osparc/dashboard/StudyBrowserButtonItem.js @@ -129,6 +129,12 @@ qx.Class.define("osparc.dashboard.StudyBrowserButtonItem", { } }, + events: { + "updateQualityStudy": "qx.event.type.Data", + "updateQualityTemplate": "qx.event.type.Data", + "updateQualityService": "qx.event.type.Data" + }, + statics: { MENU_BTN_WIDTH: 25, SHARED_USER: "@FontAwesome5Solid/user/14", @@ -428,6 +434,12 @@ qx.Class.define("osparc.dashboard.StudyBrowserButtonItem", { nStars: 4, showScore: true }); + // Stop propagation of the pointer event in case the tag is inside a button that we don't want to trigger + tsrRating.addListener("tap", e => { + e.stopPropagation(); + this.__openQualityEditor(); + }, this); + tsrRating.addListener("pointerdown", e => e.stopPropagation()); } }, @@ -488,6 +500,25 @@ qx.Class.define("osparc.dashboard.StudyBrowserButtonItem", { }); }, + __openQualityEditor: function() { + const resourceData = this.getResourceData(); + const qualityEditor = new osparc.component.metadata.QualityEditor(resourceData); + const title = resourceData.name + " - " + this.tr("Quality Assessment"); + osparc.ui.window.Window.popUpInWindow(qualityEditor, title, 650, 760); + qualityEditor.addListener("updateStudy", e => { + const updatedStudyData = e.getData(); + this.fireDataEvent("updateQualityStudy", updatedStudyData); + }); + qualityEditor.addListener("updateTemplate", e => { + const updatedTemplateData = e.getData(); + this.fireDataEvent("updateQualityTemplate", updatedTemplateData); + }); + qualityEditor.addListener("updateService", e => { + const updatedServiceData = e.getData(); + this.fireDataEvent("updateQualityService", updatedServiceData); + }); + }, + __filterText: function(text) { if (text) { const checks = [ diff --git a/services/web/client/source/class/osparc/data/model/StudyUI.js b/services/web/client/source/class/osparc/data/model/StudyUI.js index 653b49a83e6..efbd8ec602a 100644 --- a/services/web/client/source/class/osparc/data/model/StudyUI.js +++ b/services/web/client/source/class/osparc/data/model/StudyUI.js @@ -57,6 +57,22 @@ qx.Class.define("osparc.data.model.StudyUI", { } }, + statics: { + getSortedNodes: function(study) { + const slideShow = study.getUi().getSlideshow(); + const nodes = []; + for (let nodeId in slideShow) { + const node = slideShow[nodeId]; + nodes.push({ + ...node, + nodeId + }); + } + nodes.sort((a, b) => (a.position > b.position) ? 1 : -1); + return nodes; + } + }, + members: { serialize: function() { const currentStudy = osparc.store.Store.getInstance().getCurrentStudy(); diff --git a/services/web/client/source/class/osparc/desktop/ControlsBar.js b/services/web/client/source/class/osparc/desktop/ControlsBar.js index 222fc420c27..8f1d743f711 100644 --- a/services/web/client/source/class/osparc/desktop/ControlsBar.js +++ b/services/web/client/source/class/osparc/desktop/ControlsBar.js @@ -46,9 +46,7 @@ qx.Class.define("osparc.desktop.ControlsBar", { "showWorkbench": "qx.event.type.Event", "showSettings": "qx.event.type.Event", "groupSelection": "qx.event.type.Event", - "ungroupSelection": "qx.event.type.Event", - "startPipeline": "qx.event.type.Event", - "stopPipeline": "qx.event.type.Event" + "ungroupSelection": "qx.event.type.Event" }, members: { @@ -61,17 +59,6 @@ qx.Class.define("osparc.desktop.ControlsBar", { __ungroupButton: null, __iterationCtrls: null, __parametersButton: null, - __startButton: null, - __stopButton: null, - __pipelineCtrls: null, - - getStartButton: function() { - return this.__startButton; - }, - - getStopButton: function() { - return this.__stopButton; - }, setWorkbenchVisibility: function(isWorkbenchContext) { this.__serviceFilters.setVisibility(isWorkbenchContext ? "visible" : "excluded"); @@ -118,45 +105,6 @@ qx.Class.define("osparc.desktop.ControlsBar", { } }); this.add(moreCtrls); - - const pipelineCtrls = this.__pipelineCtrls = new qx.ui.toolbar.Part(); - const stopButton = this.__createStopButton(); - stopButton.setEnabled(false); - pipelineCtrls.add(stopButton); - const startButton = this.__createStartButton(); - pipelineCtrls.add(startButton); - this.add(pipelineCtrls); - - osparc.store.Store.getInstance().addListener("changeCurrentStudy", e => { - const study = e.getData(); - this.__updateRunButtonsStatus(study); - }); - }, - - __updateRunButtonsStatus: function(study) { - if (study) { - const startButton = this.__startButton; - const stopButton = this.__stopButton; - if (study.getState() && study.getState().state) { - const pipelineState = study.getState().state; - switch (pipelineState.value) { - case "PENDING": - case "PUBLISHED": - case "STARTED": - startButton.setFetching(true); - stopButton.setEnabled(true); - break; - case "NOT_STARTED": - case "SUCCESS": - case "FAILED": - default: - startButton.setFetching(false); - stopButton.setEnabled(false); - break; - } - } - this.__pipelineCtrls.setVisibility(study.isReadOnly() ? "excluded" : "visible"); - } }, __createShowSweeperButton: function() { @@ -194,15 +142,6 @@ qx.Class.define("osparc.desktop.ControlsBar", { ); }, - __createStartButton: function() { - const startButton = this.__startButton = this.__createButton(this.tr("Run"), "play", "runStudyBtn", "startPipeline"); - return startButton; - }, - __createStopButton: function() { - const stopButton = this.__stopButton = this.__createButton(this.tr("Stop"), "stop", "stopStudyBtn", "stopPipeline"); - return stopButton; - }, - __createRadioButton: function(label, icon, widgetId, singalName) { const button = new qx.ui.toolbar.RadioButton(label); // button.setIcon("@FontAwesome5Solid/"+icon+"/14"); @@ -228,13 +167,6 @@ qx.Class.define("osparc.desktop.ControlsBar", { const selectedNodes = msg.getData(); this.__groupButton.setVisibility(selectedNodes.length ? "visible" : "excluded"); this.__ungroupButton.setVisibility((selectedNodes.length === 1 && selectedNodes[0].isContainer()) ? "visible" : "excluded"); - if (!this.__startButton.isFetching()) { - if (selectedNodes.length) { - this.__startButton.setLabel(this.tr("Run selection")); - } else { - this.__startButton.setLabel(this.tr("Run")); - } - } }, __attachEventHandlers: function() { diff --git a/services/web/client/source/class/osparc/desktop/MainPage.js b/services/web/client/source/class/osparc/desktop/MainPage.js index 5685c4133ad..6dcd3f2f321 100644 --- a/services/web/client/source/class/osparc/desktop/MainPage.js +++ b/services/web/client/source/class/osparc/desktop/MainPage.js @@ -39,7 +39,7 @@ qx.Class.define("osparc.desktop.MainPage", { construct: function() { this.base(); - this._setLayout(new qx.ui.layout.VBox()); + this._setLayout(new qx.ui.layout.VBox(null, null, "separator-vertical")); const navBar = this.__navBar = this.__createNavigationBar(); this._add(navBar); @@ -61,7 +61,7 @@ qx.Class.define("osparc.desktop.MainPage", { __studyEditor: null, __createNavigationBar: function() { - const navBar = new osparc.desktop.NavigationBar(); + const navBar = new osparc.navigation.NavigationBar(); navBar.addListener("dashboardPressed", () => { if (!osparc.data.Permissions.getInstance().canDo("studies.user.create", true)) { @@ -90,22 +90,15 @@ qx.Class.define("osparc.desktop.MainPage", { navBar.addListener("slidesStart", () => { if (this.__studyEditor) { - navBar.setPageContext(osparc.desktop.NavigationBar.PAGE_CONTEXT[2]); - this.__studyEditor.setPageContext(osparc.desktop.NavigationBar.PAGE_CONTEXT[2]); + navBar.setPageContext(osparc.navigation.NavigationBar.PAGE_CONTEXT[2]); + this.__studyEditor.setPageContext(osparc.navigation.NavigationBar.PAGE_CONTEXT[2]); } }, this); navBar.addListener("slidesStop", () => { if (this.__studyEditor) { - navBar.setPageContext(osparc.desktop.NavigationBar.PAGE_CONTEXT[1]); - this.__studyEditor.setPageContext(osparc.desktop.NavigationBar.PAGE_CONTEXT[1]); - } - }, this); - - navBar.addListener("nodeSelected", e => { - if (this.__studyEditor) { - let nodeId = e.getData(); - this.__studyEditor.nodeSelected(nodeId); + navBar.setPageContext(osparc.navigation.NavigationBar.PAGE_CONTEXT[1]); + this.__studyEditor.setPageContext(osparc.navigation.NavigationBar.PAGE_CONTEXT[1]); } }, this); diff --git a/services/web/client/source/class/osparc/desktop/MainPanel.js b/services/web/client/source/class/osparc/desktop/MainPanel.js index 9bbfe42ceea..06161e10d7c 100644 --- a/services/web/client/source/class/osparc/desktop/MainPanel.js +++ b/services/web/client/source/class/osparc/desktop/MainPanel.js @@ -40,6 +40,9 @@ qx.Class.define("osparc.desktop.MainPanel", { this._setLayout(new qx.ui.layout.VBox()); + const wbToolbar = this.__wbToolbar = new osparc.desktop.WorkbenchToolbar(); + this._add(wbToolbar); + const hBox = this.__mainView = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({ allowGrowY: true }); @@ -60,6 +63,7 @@ qx.Class.define("osparc.desktop.MainPanel", { }, members: { + __wbToolbar: null, __mainView: null, __controlsBar: null, @@ -70,6 +74,10 @@ qx.Class.define("osparc.desktop.MainPanel", { }); }, + getToolbar: function() { + return this.__wbToolbar; + }, + getControls: function() { return this.__controlsBar; } diff --git a/services/web/client/source/class/osparc/desktop/SidePanel.js b/services/web/client/source/class/osparc/desktop/SidePanel.js index c6803cc0f94..3471ed39e26 100644 --- a/services/web/client/source/class/osparc/desktop/SidePanel.js +++ b/services/web/client/source/class/osparc/desktop/SidePanel.js @@ -40,7 +40,7 @@ qx.Class.define("osparc.desktop.SidePanel", { this.setAppearance("sidepanel"); - this._setLayout(new qx.ui.layout.VBox()); + this._setLayout(new qx.ui.layout.VBox(null, null, "separator-vertical")); this.__attachEventHandlers(); }, diff --git a/services/web/client/source/class/osparc/desktop/SlideShowToolbar.js b/services/web/client/source/class/osparc/desktop/SlideShowToolbar.js new file mode 100644 index 00000000000..fb95e24471a --- /dev/null +++ b/services/web/client/source/class/osparc/desktop/SlideShowToolbar.js @@ -0,0 +1,73 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2021 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.desktop.SlideShowToolbar", { + extend: osparc.desktop.Toolbar, + + members: { + __prevNextBtns: null, + + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "prev-next-btns": { + control = new osparc.navigation.PrevNextButtons(); + control.addListener("nodeSelected", e => { + this.fireDataEvent("nodeSelected", e.getData()); + }, this); + this._add(control); + break; + } + } + return control || this.base(arguments, id); + }, + + // overriden + _buildLayout: function() { + this.getChildControl("breadcrumb-navigation"); + this.__prevNextBtns = this.getChildControl("prev-next-btns"); + + this._add(new qx.ui.core.Spacer(20)); + + this._startStopBtns = this.getChildControl("start-stop-btns"); + }, + + // overriden + _populateGuidedNodesLayout: function() { + const study = this.getStudy(); + if (study) { + const slideShow = study.getUi().getSlideshow(); + const nodes = []; + for (let nodeId in slideShow) { + const node = slideShow[nodeId]; + nodes.push({ + ...node, + nodeId + }); + } + nodes.sort((a, b) => (a.position > b.position) ? 1 : -1); + const nodeIds = []; + nodes.forEach(node => { + nodeIds.push(node.nodeId); + }); + + this._navNodes.populateButtons(nodeIds, "arrow"); + this.__prevNextBtns.populateButtons(nodeIds); + } + } + } +}); diff --git a/services/web/client/source/class/osparc/desktop/SlideShowView.js b/services/web/client/source/class/osparc/desktop/SlideShowView.js index b82456e4a2d..8b53c0eeb17 100644 --- a/services/web/client/source/class/osparc/desktop/SlideShowView.js +++ b/services/web/client/source/class/osparc/desktop/SlideShowView.js @@ -15,10 +15,6 @@ ************************************************************************ */ -/** - * - */ - qx.Class.define("osparc.desktop.SlideShowView", { extend: qx.ui.core.Widget, @@ -26,6 +22,13 @@ qx.Class.define("osparc.desktop.SlideShowView", { this.base(arguments, "horizontal"); this._setLayout(new qx.ui.layout.VBox()); + + const slideShowToolbar = this.__slideShowToolbar = new osparc.desktop.SlideShowToolbar(); + slideShowToolbar.addListener("nodeSelected", e => { + const nodeId = e.getData(); + this.nodeSelected(nodeId); + }, this); + this._add(slideShowToolbar); }, properties: { @@ -36,27 +39,18 @@ qx.Class.define("osparc.desktop.SlideShowView", { } }, - statics: { - getSortedNodes: function(study) { - const slideShow = study.getUi().getSlideshow(); - const nodes = []; - for (let nodeId in slideShow) { - const node = slideShow[nodeId]; - nodes.push({ - ...node, - nodeId - }); - } - nodes.sort((a, b) => (a.position > b.position) ? 1 : -1); - return nodes; - } - }, - members: { - __controlsBar: null, - __prvsBtn: null, - __nextBtn: null, __currentNodeId: null, + __slideShowToolbar: null, + __lastView: null, + + getStartStopButtons: function() { + return this.__slideShowToolbar.getStartStopButtons(); + }, + + getSelectedNodeIDs: function() { + return [this.__currentNodeId]; + }, nodeSelected: function(nodeId) { this.__currentNodeId = nodeId; @@ -73,15 +67,22 @@ qx.Class.define("osparc.desktop.SlideShowView", { view = new osparc.component.node.NodeView(); } if (view) { + if (this.__lastView) { + this._remove(this.__lastView); + } view.setNode(node); view.populateLayout(); view.getInputsView().exclude(); view.getOutputsView().exclude(); - this.__showInMainView(view); - this.__syncButtons(); + this._add(view, { + flex: 1 + }); + this.__lastView = view; } } this.getStudy().getUi().setCurrentNodeId(nodeId); + + this.getStartStopButtons().nodeSelectionChanged([nodeId]); }, startSlides: function() { @@ -98,103 +99,18 @@ qx.Class.define("osparc.desktop.SlideShowView", { _applyStudy: function(study) { if (study) { - this.__initViews(); - } - }, - - __initViews: function() { - this._removeAll(); - this.__createControlsBar(); - }, - - __createControlsBar: function() { - const controlsBar = this.__controlsBar = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)).set({ - minHeight: 40, - padding: 5 - }); - - controlsBar.add(new qx.ui.core.Spacer(), { - flex: 1 - }); - - const prvsBtn = this.__prvsBtn = new qx.ui.form.Button(this.tr("Previous")).set({ - allowGrowX: false - }); - prvsBtn.addListener("execute", () => { - this.__previous(); - }, this); - controlsBar.add(prvsBtn); - - const nextBtn = this.__nextBtn = new qx.ui.form.Button(this.tr("Next")).set({ - allowGrowX: false - }); - nextBtn.addListener("execute", () => { - this.__next(); - }, this); - controlsBar.add(nextBtn); - - this._add(controlsBar); - }, - - __showInMainView: function(nodeView) { - const children = this._getChildren(); - for (let i=0; i node.nodeId === this.__currentNodeId); - if (idx > -1 && idx+1 < nodes.length) { - this.nodeSelected(nodes[idx+1].nodeId); - } - } - }, - - __previous: function() { - const study = this.getStudy(); - if (study) { - const nodes = this.self().getSortedNodes(study); - const idx = nodes.findIndex(node => node.nodeId === this.__currentNodeId); - if (idx > -1 && idx-1 > -1) { - this.nodeSelected(nodes[idx-1].nodeId); - } - } } } }); diff --git a/services/web/client/source/class/osparc/desktop/StartStopButtons.js b/services/web/client/source/class/osparc/desktop/StartStopButtons.js new file mode 100644 index 00000000000..aca5eb1aeaf --- /dev/null +++ b/services/web/client/source/class/osparc/desktop/StartStopButtons.js @@ -0,0 +1,158 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2021 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +/** + * Widget that shows the run and stop study button. + * + * *Example* + * + * Here is a little example of how to use the widget. + * + *
+ *   let startStopButtons = new osparc.desktop.StartStopButtons();
+ *   this.getRoot().add(startStopButtons);
+ * 
+ */ + +qx.Class.define("osparc.desktop.StartStopButtons", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.HBox(5)); + + this.setAppearance("sidepanel"); + + this.__initDefault(); + }, + + events: { + "startPipeline": "qx.event.type.Event", + "startPartialPipeline": "qx.event.type.Event", + "stopPipeline": "qx.event.type.Event" + }, + + members: { + __startButton: null, + __startSelectionButton: null, + __startAllButton: null, + __stopButton: null, + + setRunning: function(running) { + const startButtons = [this.__startButton, this.__startSelectionButton.getChildControl("button"), this.__startAllButton]; + startButtons.forEach(startButton => startButton.setFetching(running)); + this.__stopButton.setFetching(!running); + }, + + nodeSelectionChanged: function(selectedNodes) { + if (!this.__startButton.isFetching()) { + if (selectedNodes.length) { + this.__startButton.exclude(); + this.__startSelectionButton.show(); + } else { + this.__startButton.show(); + this.__startSelectionButton.exclude(); + } + } + }, + + __initDefault: function() { + const stopButton = this.__createStopButton(); + stopButton.setEnabled(false); + this._add(stopButton); + + const startButton = this.__createStartButton(); + this._add(startButton); + + const startSplitButton = this.__createStartSplitButton().set({ + visibility: "excluded" + }); + this._add(startSplitButton); + + osparc.store.Store.getInstance().addListener("changeCurrentStudy", e => { + const study = e.getData(); + this.__updateRunButtonsStatus(study); + }); + }, + + __updateRunButtonsStatus: function(study) { + if (study) { + const startButtons = [this.__startButton, this.__startSelectionButton.getChildControl("button"), this.__startAllButton]; + const stopButton = this.__stopButton; + if (study.getState() && study.getState().state) { + const pipelineState = study.getState().state; + switch (pipelineState.value) { + case "PENDING": + case "PUBLISHED": + case "STARTED": + startButtons.forEach(startButton => startButton.setFetching(true)); + stopButton.setEnabled(true); + break; + case "NOT_STARTED": + case "SUCCESS": + case "FAILED": + default: + startButtons.forEach(startButton => startButton.setFetching(false)); + stopButton.setEnabled(false); + break; + } + } + } + }, + + __createStartButton: function() { + const startButton = this.__startButton = new osparc.ui.toolbar.FetchButton(this.tr("Run"), "@FontAwesome5Solid/play/14"); + osparc.utils.Utils.setIdToWidget(startButton, "runStudyBtn"); + startButton.addListener("execute", () => { + this.fireEvent("startPipeline"); + }, this); + return startButton; + }, + + __createStartSplitButton: function() { + const startSelectionButton = this.__startSelectionButton = new osparc.ui.toolbar.FetchSplitButton(this.tr("Run Node"), "@FontAwesome5Solid/play/14"); + startSelectionButton.addListener("execute", () => { + this.fireEvent("startPartialPipeline"); + }, this); + const splitButtonMenu = this.__createSplitButtonMenu(); + startSelectionButton.setMenu(splitButtonMenu); + return startSelectionButton; + }, + + __createSplitButtonMenu: function() { + const splitButtonMenu = new qx.ui.menu.Menu(); + + const startAllButton = this.__startAllButton = new osparc.ui.menu.FetchButton(this.tr("Run All")); + startAllButton.addListener("execute", () => { + this.fireEvent("startPipeline"); + }); + splitButtonMenu.add(startAllButton); + + return splitButtonMenu; + }, + + __createStopButton: function() { + const stopButton = this.__stopButton = new osparc.ui.toolbar.FetchButton(this.tr("Stop"), "@FontAwesome5Solid/stop/14"); + osparc.utils.Utils.setIdToWidget(stopButton, "stopStudyBtn"); + stopButton.addListener("execute", () => { + this.fireEvent("stopPipeline"); + }, this); + return stopButton; + } + } +}); diff --git a/services/web/client/source/class/osparc/desktop/StudyEditor.js b/services/web/client/source/class/osparc/desktop/StudyEditor.js index c42f457a9a8..daf8b6f2b17 100644 --- a/services/web/client/source/class/osparc/desktop/StudyEditor.js +++ b/services/web/client/source/class/osparc/desktop/StudyEditor.js @@ -24,14 +24,25 @@ qx.Class.define("osparc.desktop.StudyEditor", { this._setLayout(new qx.ui.layout.VBox(10)); const viewsStack = this.__viewsStack = new qx.ui.container.Stack(); + const workbenchView = this.__workbenchView = new osparc.desktop.WorkbenchView(); workbenchView.addListener("startStudy", e => { this.fireDataEvent("startStudy", e.getData()); }); viewsStack.add(workbenchView); + const slideshowView = this.__slideshowView = new osparc.desktop.SlideShowView(); viewsStack.add(slideshowView); + [ + workbenchView.getStartStopButtons(), + slideshowView.getStartStopButtons() + ].forEach(startStopButtons => { + startStopButtons.addListener("startPipeline", this.__startPipeline, this); + startStopButtons.addListener("startPartialPipeline", () => this.__startPipeline(false), this); + startStopButtons.addListener("stopPipeline", this.__stopPipeline, this); + }); + this._add(viewsStack, { flex: 1 }); @@ -120,6 +131,14 @@ qx.Class.define("osparc.desktop.StudyEditor", { this.__workbenchView.openFirstNode(); break; } + + const workbench = study.getWorkbench(); + workbench.addListener("retrieveInputs", e => { + const data = e.getData(); + const node = data["node"]; + const portKey = data["portKey"]; + this.__updatePipelineAndRetrieve(node, portKey); + }, this); }) .catch(err => { if ("status" in err && err["status"] == 423) { // Locked @@ -135,6 +154,153 @@ qx.Class.define("osparc.desktop.StudyEditor", { this.__slideshowView.setStudy(study); }, + + // ------------------ START/STOP PIPELINE ------------------ + __startPipeline: function(runAll = true) { + if (!osparc.data.Permissions.getInstance().canDo("study.start", true)) { + return; + } + + const startStopButtonsWB = this.__workbenchView.getStartStopButtons(); + const startStopButtonsSS = this.__slideshowView.getStartStopButtons(); + startStopButtonsWB.setRunning(true); + startStopButtonsSS.setRunning(true); + this.updateStudyDocument(true) + .then(() => { + this.__doStartPipeline(runAll); + }) + .catch(() => { + this.getLogger().error(null, "Run failed"); + startStopButtonsWB.setRunning(false); + startStopButtonsSS.setRunning(false); + }); + }, + + __doStartPipeline: function(runAll) { + if (this.getStudy().getSweeper().hasSecondaryStudies()) { + const secondaryStudyIds = this.getStudy().getSweeper().getSecondaryStudyIds(); + secondaryStudyIds.forEach(secondaryStudyId => { + this.__requestStartPipeline(secondaryStudyId); + }); + } else if (runAll) { + this.__requestStartPipeline(this.getStudy().getUuid()); + } else { + const selectedNodeIDs = this.getPageContext() === "workbench" ? this.__workbenchView.getSelectedNodeIDs() : this.__slideshowView.getSelectedNodeIDs(); + if (selectedNodeIDs === null || selectedNodeIDs.length === 0) { + this.__requestStartPipeline(this.getStudy().getUuid()); + } else { + this.__requestStartPipeline(this.getStudy().getUuid(), selectedNodeIDs); + } + } + }, + + __requestStartPipeline: function(studyId, selectedNodeIDs = []) { + const url = "/computation/pipeline/" + encodeURIComponent(studyId) + ":start"; + const req = new osparc.io.request.ApiRequest(url, "POST"); + const startStopButtonsWB = this.__workbenchView.getStartStopButtons(); + const startStopButtonsSS = this.__slideshowView.getStartStopButtons(); + req.addListener("success", this.__onPipelinesubmitted, this); + req.addListener("error", e => { + this.getLogger().error(null, "Error submitting pipeline"); + startStopButtonsWB.setRunning(false); + startStopButtonsSS.setRunning(false); + }, this); + req.addListener("fail", e => { + if (e.getTarget().getResponse().error.status == "403") { + this.getLogger().error(null, "Pipeline is already running"); + } else { + this.getLogger().error(null, "Failed submitting pipeline"); + } + startStopButtonsWB.setRunning(false); + startStopButtonsSS.setRunning(false); + }, this); + if (selectedNodeIDs.length) { + req.setRequestData({ + "subgraph": selectedNodeIDs + }); + req.send(); + this.getLogger().info(null, "Starting partial pipeline"); + } else { + req.send(); + this.getLogger().info(null, "Starting pipeline"); + } + + return true; + }, + + __onPipelinesubmitted: function(e) { + const resp = e.getTarget().getResponse(); + const pipelineId = resp.data["pipeline_id"]; + this.getLogger().debug(null, "Pipeline ID " + pipelineId); + const notGood = [null, undefined, -1]; + if (notGood.includes(pipelineId)) { + this.getLogger().error(null, "Submission failed"); + } else { + this.getLogger().info(null, "Pipeline started"); + /* If no projectStateUpdated comes in 60 seconds, client must + check state of pipeline and update button accordingly. */ + const timer = setTimeout(() => { + osparc.store.Store.getInstance().getStudyState(pipelineId); + }, 60000); + const socket = osparc.wrapper.WebSocket.getInstance(); + socket.getSocket().once("projectStateUpdated", jsonStr => { + const study = JSON.parse(jsonStr); + if (study["project_uuid"] === pipelineId) { + clearTimeout(timer); + } + }); + } + }, + + __stopPipeline: function() { + if (!osparc.data.Permissions.getInstance().canDo("study.stop", true)) { + return; + } + + this.__doStopPipeline(); + }, + + __doStopPipeline: function() { + if (this.getStudy().getSweeper().hasSecondaryStudies()) { + const secondaryStudyIds = this.getStudy().getSweeper().getSecondaryStudyIds(); + secondaryStudyIds.forEach(secondaryStudyId => { + this.__requestStopPipeline(secondaryStudyId); + }); + } else { + this.__requestStopPipeline(this.getStudy().getUuid()); + } + }, + + __requestStopPipeline: function(studyId) { + const url = "/computation/pipeline/" + encodeURIComponent(studyId) + ":stop"; + const req = new osparc.io.request.ApiRequest(url, "POST"); + req.addListener("success", e => { + this.getLogger().debug(null, "Pipeline aborting"); + }, this); + req.addListener("error", e => { + this.getLogger().error(null, "Error stopping pipeline"); + }, this); + req.addListener("fail", e => { + this.getLogger().error(null, "Failed stopping pipeline"); + }, this); + req.send(); + + this.getLogger().info(null, "Stopping pipeline"); + return true; + }, + // ------------------ START/STOP PIPELINE ------------------ + + __updatePipelineAndRetrieve: function(node, portKey = null) { + this.updateStudyDocument(false) + .then(() => { + this.getLogger().debug(null, "Retrieveing inputs"); + if (node) { + node.retrieveInputs(portKey); + } + }); + this.getLogger().debug(null, "Updating pipeline"); + }, + // overridden _showMainLayout: function(show) { this.__viewsStack.setVisibility(show ? "visible" : "excluded"); diff --git a/services/web/client/source/class/osparc/desktop/Toolbar.js b/services/web/client/source/class/osparc/desktop/Toolbar.js new file mode 100644 index 00000000000..4a9ae991841 --- /dev/null +++ b/services/web/client/source/class/osparc/desktop/Toolbar.js @@ -0,0 +1,111 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2021 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.desktop.Toolbar", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.HBox(10).set({ + alignY: "middle" + })); + this.setAppearance("sidepanel"); + + this.set({ + height: 46 + }); + + this._buildLayout(); + }, + + events: { + "nodeSelected": "qx.event.type.Data", + "startPipeline": "qx.event.type.Event", + "startPartialPipeline": "qx.event.type.Event", + "stopPipeline": "qx.event.type.Event" + }, + + properties: { + study: { + check: "osparc.data.model.Study", + apply: "__applyStudy", + nullable: false + } + }, + + members: { + _navNodes: null, + _startStopBtns: null, + + getStartStopButtons: function() { + return this._startStopBtns; + }, + + _createChildControlImpl: function(id) { + let control; + switch (id) { + case "breadcrumb-navigation": { + control = new qx.ui.container.Scroll(); + const breadcrumbNavigation = this._navNodes = new osparc.navigation.BreadcrumbNavigation(); + breadcrumbNavigation.addListener("nodeSelected", e => { + this.fireDataEvent("nodeSelected", e.getData()); + }, this); + control.add(breadcrumbNavigation); + this._add(control, { + flex: 1 + }); + break; + } + case "start-stop-btns": { + control = new osparc.desktop.StartStopButtons(); + control.addListener("startPipeline", () => { + this.fireEvent("startPipeline"); + }, this); + control.addListener("startPartialPipeline", () => { + this.fireEvent("startPartialPipeline"); + }, this); + control.addListener("stopPipeline", () => { + this.fireEvent("stopPipeline"); + }, this); + this._add(control); + break; + } + } + return control || this.base(arguments, id); + }, + + __applyStudy: function(study) { + if (study) { + study.getUi().addListener("changeCurrentNodeId", () => { + this._populateGuidedNodesLayout(); + }); + this._startStopBtns.setVisibility(study.isReadOnly() ? "excluded" : "visible"); + + this._populateGuidedNodesLayout(); + } + }, + + _buildLayout: function() { + throw new Error("Abstract method called!"); + }, + + _populateGuidedNodesLayout: function() { + throw new Error("Abstract method called!"); + } + } +}); diff --git a/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js b/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js new file mode 100644 index 00000000000..54c261ffcd7 --- /dev/null +++ b/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js @@ -0,0 +1,52 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2021 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.desktop.WorkbenchToolbar", { + extend: osparc.desktop.Toolbar, + + construct: function() { + this.base(arguments); + + this.__attachEventHandlers(); + }, + + members: { + // overriden + _buildLayout: function() { + this.getChildControl("breadcrumb-navigation"); + this._startStopBtns = this.getChildControl("start-stop-btns"); + }, + + // overriden + _populateGuidedNodesLayout: function() { + const study = this.getStudy(); + if (study) { + const nodeIds = study.getWorkbench().getPathIds(study.getUi().getCurrentNodeId()); + this._navNodes.populateButtons(nodeIds, "slash"); + } + }, + + __workbenchSelectionChanged: function(msg) { + const selectedNodes = msg.getData(); + this.getStartStopButtons().nodeSelectionChanged(selectedNodes); + }, + + __attachEventHandlers: function() { + qx.event.message.Bus.subscribe("changeWorkbenchSelection", this.__workbenchSelectionChanged, this); + } + } +}); diff --git a/services/web/client/source/class/osparc/desktop/WorkbenchView.js b/services/web/client/source/class/osparc/desktop/WorkbenchView.js index c59f2f89790..ebd9905cbcc 100644 --- a/services/web/client/source/class/osparc/desktop/WorkbenchView.js +++ b/services/web/client/source/class/osparc/desktop/WorkbenchView.js @@ -73,6 +73,19 @@ qx.Class.define("osparc.desktop.WorkbenchView", { this.__connectEvents(); this.__attachSocketEventHandlers(); } + this.__mainPanel.getToolbar().setStudy(study); + }, + + getStartStopButtons: function() { + return this.__mainPanel.getToolbar().getStartStopButtons(); + }, + + getSelectedNodes: function() { + return this.__workbenchUI.getSelectedNodes(); + }, + + getSelectedNodeIDs: function() { + return this.__workbenchUI.getSelectedNodeIds(); }, nodeSelected: function(nodeId) { @@ -191,7 +204,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", { return; } - const selectedNodeUIs = this.__workbenchUI.getSelectedNodes(); + const selectedNodeUIs = this.getSelectedNodes(); if (this.__isSelectionEmpty(selectedNodeUIs)) { return; } @@ -216,7 +229,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", { if (!osparc.data.Permissions.getInstance().canDo("study.node.create", true)) { return; } - const selectedNodeUIs = this.__workbenchUI.getSelectedNodes(); + const selectedNodeUIs = this.getSelectedNodes(); if (this.__isSelectionEmpty(selectedNodeUIs)) { return; } @@ -241,134 +254,6 @@ qx.Class.define("osparc.desktop.WorkbenchView", { this.__workbenchUI.resetSelectedNodes(); }, - __startPipeline: function() { - if (!osparc.data.Permissions.getInstance().canDo("study.start", true)) { - return; - } - const runButton = this.__mainPanel.getControls().getStartButton(); - runButton.setFetching(true); - this.updateStudyDocument(true) - .then(() => { - this.__doStartPipeline(); - }) - .catch(() => { - this.getLogger().error(null, "Run failed"); - runButton.setFetching(false); - }); - }, - - __doStartPipeline: function() { - if (this.getStudy().getSweeper().hasSecondaryStudies()) { - const secondaryStudyIds = this.getStudy().getSweeper().getSecondaryStudyIds(); - secondaryStudyIds.forEach(secondaryStudyId => { - this.__requestStartPipeline(secondaryStudyId); - }); - } else { - const selectedNodeUIs = this.__workbenchUI.getSelectedNodes(); - if (this.__isSelectionEmpty(selectedNodeUIs)) { - this.__requestStartPipeline(this.getStudy().getUuid()); - } else { - const selectedNodeIDs = []; - selectedNodeUIs.forEach(nodeUI => { - selectedNodeIDs.push(nodeUI.getNodeId()); - }); - this.__requestStartPipeline(this.getStudy().getUuid(), selectedNodeIDs); - } - } - }, - - __requestStartPipeline: function(studyId, selectedNodeIDs = []) { - const url = "/computation/pipeline/" + encodeURIComponent(studyId) + ":start"; - const req = new osparc.io.request.ApiRequest(url, "POST"); - const runButton = this.__mainPanel.getControls().getStartButton(); - req.addListener("success", this.__onPipelinesubmitted, this); - req.addListener("error", e => { - this.getLogger().error(null, "Error submitting pipeline"); - runButton.setFetching(false); - }, this); - req.addListener("fail", e => { - if (e.getTarget().getResponse().error.status == "403") { - this.getLogger().error(null, "Pipeline is already running"); - } else { - this.getLogger().error(null, "Failed submitting pipeline"); - } - runButton.setFetching(false); - }, this); - if (selectedNodeIDs.length) { - req.setRequestData({ - "subgraph": selectedNodeIDs - }); - req.send(); - this.getLogger().info(null, "Starting partial pipeline"); - } else { - req.send(); - this.getLogger().info(null, "Starting pipeline"); - } - - return true; - }, - - __onPipelinesubmitted: function(e) { - const resp = e.getTarget().getResponse(); - const pipelineId = resp.data["pipeline_id"]; - this.getLogger().debug(null, "Pipeline ID " + pipelineId); - const notGood = [null, undefined, -1]; - if (notGood.includes(pipelineId)) { - this.getLogger().error(null, "Submission failed"); - } else { - this.getLogger().info(null, "Pipeline started"); - /* If no projectStateUpdated comes in 60 seconds, client must - check state of pipeline and update button accordingly. */ - const timer = setTimeout(() => { - osparc.store.Store.getInstance().getStudyState(pipelineId); - }, 60000); - const socket = osparc.wrapper.WebSocket.getInstance(); - socket.getSocket().once("projectStateUpdated", jsonStr => { - const study = JSON.parse(jsonStr); - if (study["project_uuid"] === pipelineId) { - clearTimeout(timer); - } - }); - } - }, - - __stopPipeline: function() { - if (!osparc.data.Permissions.getInstance().canDo("study.stop", true)) { - return; - } - - this.__doStopPipeline(); - }, - - __doStopPipeline: function() { - if (this.getStudy().getSweeper().hasSecondaryStudies()) { - const secondaryStudyIds = this.getStudy().getSweeper().getSecondaryStudyIds(); - secondaryStudyIds.forEach(secondaryStudyId => { - this.__requestStopPipeline(secondaryStudyId); - }); - } else { - this.__requestStopPipeline(this.getStudy().getUuid()); - } - }, - - __requestStopPipeline: function(studyId) { - const url = "/computation/pipeline/" + encodeURIComponent(studyId) + ":stop"; - const req = new osparc.io.request.ApiRequest(url, "POST"); - req.addListener("success", e => { - this.getLogger().debug(null, "Pipeline aborting"); - }, this); - req.addListener("error", e => { - this.getLogger().error(null, "Error stopping pipeline"); - }, this); - req.addListener("fail", e => { - this.getLogger().error(null, "Failed stopping pipeline"); - }, this); - req.send(); - - this.getLogger().info(null, "Stopping pipeline"); - return true; - }, - __maximizeIframe: function(maximize) { this.getBlocker().setStyles({ display: maximize ? "none" : "block" @@ -401,8 +286,6 @@ qx.Class.define("osparc.desktop.WorkbenchView", { controlsBar.addListener("showSettings", this.__showSettings, this); controlsBar.addListener("groupSelection", this.__groupSelection, this); controlsBar.addListener("ungroupSelection", this.__ungroupSelection, this); - controlsBar.addListener("startPipeline", this.__startPipeline, this); - controlsBar.addListener("stopPipeline", this.__stopPipeline, this); }, __initViews: function() { @@ -516,21 +399,6 @@ qx.Class.define("osparc.desktop.WorkbenchView", { } }, - __updatePipelineAndRetrieve: function(node, portKey = null) { - this.updateStudyDocument(false) - .then(() => { - this.__retrieveInputs(node, portKey); - }); - this.getLogger().debug(null, "Updating pipeline"); - }, - - __retrieveInputs: function(node, portKey = null) { - this.getLogger().debug(null, "Retrieveing inputs"); - if (node) { - node.retrieveInputs(portKey); - } - }, - __showInMainView: function(widget, nodeId) { this.__mainPanel.setMainView(widget); @@ -551,13 +419,6 @@ qx.Class.define("osparc.desktop.WorkbenchView", { const workbench = this.getStudy().getWorkbench(); workbench.addListener("workbenchChanged", this.__workbenchChanged, this); - workbench.addListener("retrieveInputs", e => { - const data = e.getData(); - const node = data["node"]; - const portKey = data["portKey"]; - this.__updatePipelineAndRetrieve(node, portKey); - }, this); - workbench.addListener("showInLogger", ev => { const data = ev.getData(); const nodeId = data.nodeId; @@ -566,9 +427,11 @@ qx.Class.define("osparc.desktop.WorkbenchView", { }, this); const workbenchUI = this.__workbenchUI; + const workbenchToolbar = this.__mainPanel.getToolbar(); const nodesTree = this.__nodesTree; [ nodesTree, + workbenchToolbar, workbenchUI ].forEach(widget => { widget.addListener("nodeSelected", e => { @@ -714,36 +577,6 @@ qx.Class.define("osparc.desktop.WorkbenchView", { } else { this.nodeSelected(this.getStudy().getUuid()); } - }, - - updateStudyDocument: function(run = false) { - const myGrpId = osparc.auth.Data.getInstance().getGroupId(); - if (!osparc.component.export.StudyPermissions.canGroupWrite(this.getStudy().getAccessRights(), myGrpId)) { - return new Promise(resolve => { - resolve(); - }); - } - - this.getStudy().setLastChangeDate(new Date()); - const newObj = this.getStudy().serialize(); - const prjUuid = this.getStudy().getUuid(); - - const params = { - url: { - projectId: prjUuid, - run - }, - data: newObj - }; - return new Promise((resolve, reject) => { - osparc.data.Resources.fetch("studies", "put", params) - .then(data => { - resolve(); - }) - .catch(error => { - reject(); - }); - }); } } }); diff --git a/services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js b/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js similarity index 81% rename from services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js rename to services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js index 61715dc4843..299d6f808c6 100644 --- a/services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js +++ b/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js @@ -19,7 +19,7 @@ * */ -qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { +qx.Class.define("osparc.navigation.BreadcrumbNavigation", { extend: qx.ui.core.Widget, construct: function() { @@ -28,21 +28,14 @@ qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { this._setLayout(new qx.ui.layout.HBox(0).set({ alignY: "middle" })); + + this.setPaddingLeft(6); }, events: { "nodeSelected": "qx.event.type.Data" }, - statics: { - BUTTON_OPTIONS: { - font: "text-14", - allowGrowY: false, - minWidth: 32, - minHeight: 32 - } - }, - members: { populateButtons: function(nodesIds = [], shape = "slash") { const btns = []; @@ -72,7 +65,7 @@ qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { __createNodeBtn: function(nodeId) { const btn = new qx.ui.form.ToggleButton().set({ - ...this.self().BUTTON_OPTIONS, + ...osparc.navigation.NavigationBar.BUTTON_OPTIONS, maxWidth: 200 }); btn.addListener("execute", () => { @@ -108,6 +101,22 @@ qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { converter: val => (pos+1).toString() + "- " + val }); node.bind("label", btn, "toolTipText"); + + const nsUI = new osparc.ui.basic.NodeStatusUI(node); + const nsUIIcon = nsUI.getChildControl("icon"); + // Hacky, aber schön + // eslint-disable-next-line no-underscore-dangle + btn._add(nsUIIcon); + const nsUILabel = nsUI.getChildControl("label"); + nsUILabel.addListener("changeValue", e => { + const statusLabel = e.getData(); + if (statusLabel) { + btn.setToolTipText(`${node.getLabel()} - ${statusLabel}`); + } + }, this); + if (nsUILabel.getValue()) { + btn.setToolTipText(`${node.getLabel()} - ${nsUILabel.getValue()}`); + } } return btn; }, @@ -123,7 +132,7 @@ qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { this._add(thisBtn); - const breadcrumbSplitter = new osparc.component.widget.BreadcrumbSplitter(16, 32).set({ + const breadcrumbSplitter = new osparc.navigation.BreadcrumbSplitter(16, 32).set({ shape, marginLeft: -1, marginRight: -1 diff --git a/services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js b/services/web/client/source/class/osparc/navigation/BreadcrumbSplitter.js similarity index 95% rename from services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js rename to services/web/client/source/class/osparc/navigation/BreadcrumbSplitter.js index 8af6e045633..68f3416e621 100644 --- a/services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js +++ b/services/web/client/source/class/osparc/navigation/BreadcrumbSplitter.js @@ -19,7 +19,7 @@ * */ -qx.Class.define("osparc.component.widget.BreadcrumbSplitter", { +qx.Class.define("osparc.navigation.BreadcrumbSplitter", { extend: qx.ui.core.Widget, construct: function(w, h) { @@ -31,14 +31,12 @@ qx.Class.define("osparc.component.widget.BreadcrumbSplitter", { }); this.addListenerOnce("appear", () => { - const randomID = Math.random().toString(36).substring(7); const el = this.getContentElement().getDomElement(); - qx.bom.element.Attribute.set(el, "id", randomID); const svgWrapper = osparc.wrapper.Svg.getInstance(); svgWrapper.init() .then(() => { if (this.__canvas === null) { - this.__canvas = svgWrapper.createEmptyCanvas(randomID); + this.__canvas = svgWrapper.createEmptyCanvas(el); this.setReady(true); this.fireDataEvent("SvgWidgetReady", true); } diff --git a/services/web/client/source/class/osparc/desktop/NavigationBar.js b/services/web/client/source/class/osparc/navigation/NavigationBar.js similarity index 84% rename from services/web/client/source/class/osparc/desktop/NavigationBar.js rename to services/web/client/source/class/osparc/navigation/NavigationBar.js index dbea9552037..57c4337741f 100644 --- a/services/web/client/source/class/osparc/desktop/NavigationBar.js +++ b/services/web/client/source/class/osparc/navigation/NavigationBar.js @@ -31,12 +31,12 @@ * Here is a little example of how to use the widget. * *
- *   let navBar = new osparc.desktop.NavigationBar();
+ *   let navBar = new osparc.navigation.NavigationBar();
  *   this.getRoot().add(navBar);
  * 
*/ -qx.Class.define("osparc.desktop.NavigationBar", { +qx.Class.define("osparc.navigation.NavigationBar", { extend: qx.ui.core.Widget, construct: function() { @@ -62,7 +62,6 @@ qx.Class.define("osparc.desktop.NavigationBar", { }, events: { - "nodeSelected": "qx.event.type.Data", "dashboardPressed": "qx.event.type.Event", "slidesStart": "qx.event.type.Event", "slidesStop": "qx.event.type.Event" @@ -104,8 +103,6 @@ qx.Class.define("osparc.desktop.NavigationBar", { __startSlidesBtn: null, __stopSlidesBtn: null, __studyTitle: null, - __navNodes: null, - __navNodesLayout: null, buildLayout: function() { this.getChildControl("logo"); @@ -147,8 +144,6 @@ qx.Class.define("osparc.desktop.NavigationBar", { } }, this); - this.__navNodesLayout = this.getChildControl("navigation-nodes-path-container"); - this._add(new qx.ui.core.Spacer(), { flex: 1 }); @@ -211,18 +206,6 @@ qx.Class.define("osparc.desktop.NavigationBar", { }); this._add(control); break; - case "navigation-nodes-path-container": { - control = new qx.ui.container.Scroll(); - const breadcrumbNavigation = this.__navNodes = new osparc.component.widget.BreadcrumbNavigation(); - breadcrumbNavigation.addListener("nodeSelected", e => { - this.fireDataEvent("nodeSelected", e.getData()); - }, this); - control.add(breadcrumbNavigation); - this._add(control, { - flex: 1 - }); - break; - } case "manual": control = this.__createManualMenuBtn(); control.set(this.self().BUTTON_OPTIONS); @@ -252,68 +235,26 @@ qx.Class.define("osparc.desktop.NavigationBar", { return this.__dashboardBtn; }, - __populateWorkbenchNodesLayout: function() { - const study = this.getStudy(); - const nodeIds = study.getWorkbench().getPathIds(study.getUi().getCurrentNodeId()); - if (nodeIds.length === 1) { - this.__studyTitle.show(); - this.__navNodesLayout.exclude(); - } else { - this.__studyTitle.exclude(); - this.__navNodesLayout.show(); - this.__navNodes.populateButtons(nodeIds, "slash"); - } - }, - - __populateGuidedNodesLayout: function() { - this.__navNodesLayout.show(); - this.__studyTitle.exclude(); - - const study = this.getStudy(); - const slideShow = study.getUi().getSlideshow(); - const nodes = []; - for (let nodeId in slideShow) { - const node = slideShow[nodeId]; - nodes.push({ - ...node, - nodeId - }); - } - nodes.sort((a, b) => (a.position > b.position) ? 1 : -1); - const nodeIds = []; - nodes.forEach(node => { - nodeIds.push(node.nodeId); - }); - - this.__navNodes.populateButtons(nodeIds, "arrow"); - }, - _applyPageContext: function(newCtxt) { switch (newCtxt) { case "dashboard": this.__dashboardLabel.show(); this.__dashboardBtn.exclude(); this.__readOnlyIcon.exclude(); - this.__resetSlideCtrlBtnsVis(false); + this.__resetSlidesBtnsVis(false); this.__studyTitle.exclude(); - this.__navNodesLayout.exclude(); break; case "workbench": - this.__dashboardLabel.exclude(); - this.__dashboardBtn.show(); - this.__resetSlideCtrlBtnsVis(true); - this.__populateWorkbenchNodesLayout(); - break; case "slideshow": this.__dashboardLabel.exclude(); this.__dashboardBtn.show(); - this.__resetSlideCtrlBtnsVis(true); - this.__populateGuidedNodesLayout(); + this.__resetSlidesBtnsVis(true); + this.__studyTitle.show(); break; } }, - __resetSlideCtrlBtnsVis: function() { + __resetSlidesBtnsVis: function() { const areSlidesEnabled = osparc.data.Permissions.getInstance().canDo("study.slides"); const context = ["workbench", "slideshow"].includes(this.getPageContext()); if (areSlidesEnabled && context) { @@ -334,7 +275,7 @@ qx.Class.define("osparc.desktop.NavigationBar", { }, __createSlideStartBtn: function() { - const startBtn = new qx.ui.form.Button(this.tr("Start Guided mode"), "@FontAwesome5Solid/caret-square-right/16").set({ + const startBtn = new qx.ui.form.Button(this.tr("Guided Mode"), "@FontAwesome5Solid/caret-square-right/16").set({ ...this.self().BUTTON_OPTIONS }); startBtn.addListener("execute", () => { @@ -344,7 +285,7 @@ qx.Class.define("osparc.desktop.NavigationBar", { }, __createSlideStopBtn: function() { - const stopBtn = new qx.ui.form.Button(this.tr("Stop Guided mode"), "@FontAwesome5Solid/stop/16").set({ + const stopBtn = new qx.ui.form.Button(this.tr("Guided Mode"), "@FontAwesome5Solid/stop/16").set({ ...this.self().BUTTON_OPTIONS }); stopBtn.addListener("execute", () => { @@ -543,16 +484,8 @@ qx.Class.define("osparc.desktop.NavigationBar", { study.bind("readOnly", this.__readOnlyIcon, "visibility", { converter: value => value ? "visible" : "excluded" }); - study.getUi().addListener("changeSlideshow", () => { - this.__resetSlideCtrlBtnsVis(); - }); - study.getUi().addListener("changeCurrentNodeId", () => { - if (this.getPageContext() === "workbench") { - this.__populateWorkbenchNodesLayout(); - } else if (this.getPageContext() === "slideshow") { - this.__populateGuidedNodesLayout(); - } + this.__resetSlidesBtnsVis(); }); } } diff --git a/services/web/client/source/class/osparc/navigation/PrevNextButtons.js b/services/web/client/source/class/osparc/navigation/PrevNextButtons.js new file mode 100644 index 00000000000..0bd7be67e40 --- /dev/null +++ b/services/web/client/source/class/osparc/navigation/PrevNextButtons.js @@ -0,0 +1,91 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2021 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +qx.Class.define("osparc.navigation.PrevNextButtons", { + extend: qx.ui.core.Widget, + + construct: function() { + this.base(arguments); + + this._setLayout(new qx.ui.layout.HBox(0).set({ + alignY: "middle" + })); + }, + + events: { + "nodeSelected": "qx.event.type.Data" + }, + + statics: { + BUTTON_OPTIONS: { + font: "text-14", + allowGrowY: false, + minWidth: 32, + minHeight: 32 + } + }, + + members: { + __prvsBtn: null, + __nextBtn: null, + __currentNodeId: null, + + populateButtons: function(nodesIds) { + this.__createButtons(); + + const study = osparc.store.Store.getInstance().getCurrentStudy(); + const currentNodeId = study.getUi().getCurrentNodeId(); + const currentIdx = nodesIds.indexOf(currentNodeId); + + if (currentIdx > 0) { + this.__prvsBtn.addListener("execute", () => { + this.fireDataEvent("nodeSelected", nodesIds[currentIdx-1]); + }, this); + } else { + this.__prvsBtn.setEnabled(false); + } + + if (currentIdx < nodesIds.length-1) { + this.__nextBtn.addListener("execute", () => { + this.fireDataEvent("nodeSelected", nodesIds[currentIdx+1]); + }, this); + } else { + this.__nextBtn.setEnabled(false); + } + }, + + __createButtons: function() { + this._removeAll(); + + const prvsBtn = this.__prvsBtn = new qx.ui.form.Button().set({ + toolTipText: this.tr("Previous"), + icon: "@FontAwesome5Solid/arrow-left/24", + ...osparc.navigation.NavigationBar.BUTTON_OPTIONS, + allowGrowX: false + }); + this._add(prvsBtn); + + const nextBtn = this.__nextBtn = new qx.ui.form.Button().set({ + toolTipText: this.tr("Next"), + icon: "@FontAwesome5Solid/arrow-right/24", + ...osparc.navigation.NavigationBar.BUTTON_OPTIONS, + allowGrowX: false + }); + this._add(nextBtn); + } + } +}); diff --git a/services/web/client/source/class/osparc/ui/menu/FetchButton.js b/services/web/client/source/class/osparc/ui/menu/FetchButton.js new file mode 100644 index 00000000000..9a810b242ba --- /dev/null +++ b/services/web/client/source/class/osparc/ui/menu/FetchButton.js @@ -0,0 +1,15 @@ +/* + * oSPARC - The SIMCORE frontend - https://osparc.io + * Copyright: 2021 IT'IS Foundation - https://itis.swiss + * License: MIT - https://opensource.org/licenses/MIT + * Authors: Odei Maiz (odeimaiz) + */ + +/** + * A toolbar button that serves to fetch or load some data from the server. To indicate that some processing is being done, and + * that the user has to wait, a rotating special icon is shown meanwhile. + */ +qx.Class.define("osparc.ui.menu.FetchButton", { + extend: qx.ui.menu.Button, + include: osparc.ui.mixin.FetchButton +}); diff --git a/services/web/client/source/class/osparc/ui/toolbar/FetchSplitButton.js b/services/web/client/source/class/osparc/ui/toolbar/FetchSplitButton.js new file mode 100644 index 00000000000..df3b00c135c --- /dev/null +++ b/services/web/client/source/class/osparc/ui/toolbar/FetchSplitButton.js @@ -0,0 +1,33 @@ +/* + * oSPARC - The SIMCORE frontend - https://osparc.io + * Copyright: 2021 IT'IS Foundation - https://itis.swiss + * License: MIT - https://opensource.org/licenses/MIT + * Authors: Odei Maiz (odeimaiz) + */ + +/** + * A toolbar split button that serves to fetch or load some data from the server. To indicate that some processing is being done, and + * that the user has to wait, a rotating special icon is shown meanwhile. + */ +qx.Class.define("osparc.ui.toolbar.FetchSplitButton", { + extend: qx.ui.toolbar.SplitButton, + include: osparc.ui.mixin.FetchButton, + + members: { + // overridden + _createChildControlImpl : function(id, hash) { + let control; + + switch (id) { + case "button": + control = new osparc.ui.form.FetchButton(); + control.addListener("execute", this._onButtonExecute, this); + control.setFocusable(false); + this._addAt(control, 0, {flex: 1}); + break; + } + + return control || this.base(arguments, id); + } + } +}); diff --git a/services/web/client/source/class/osparc/viewer/NavigationBar.js b/services/web/client/source/class/osparc/viewer/NavigationBar.js index 6ce53df7b42..6b47cadd1c7 100644 --- a/services/web/client/source/class/osparc/viewer/NavigationBar.js +++ b/services/web/client/source/class/osparc/viewer/NavigationBar.js @@ -16,7 +16,7 @@ ************************************************************************ */ qx.Class.define("osparc.viewer.NavigationBar", { - extend: osparc.desktop.NavigationBar, + extend: osparc.navigation.NavigationBar, members: { buildLayout: function() { diff --git a/services/web/client/source/class/osparc/wrapper/Svg.js b/services/web/client/source/class/osparc/wrapper/Svg.js index 834b2942069..9b1247a1924 100644 --- a/services/web/client/source/class/osparc/wrapper/Svg.js +++ b/services/web/client/source/class/osparc/wrapper/Svg.js @@ -214,8 +214,8 @@ qx.Class.define("osparc.wrapper.Svg", { }); }, - createEmptyCanvas: function(id) { - return SVG(id); + createEmptyCanvas: function(element) { + return SVG(element); } } }); diff --git a/tests/e2e/tests/tags.test.js b/tests/e2e/tests/tags.test.js index 4ba3821eec1..9e65598a4ab 100644 --- a/tests/e2e/tests/tags.test.js +++ b/tests/e2e/tests/tags.test.js @@ -49,12 +49,12 @@ describe('tags testing', () => { // Create new study await waitAndClick(page, '[osparc-test-id="newStudyBtn"]'); // Edit its title and go back to dashboard - await waitAndClick(page, '[qxclass="osparc.desktop.NavigationBar"] [qxclass="osparc.ui.form.EditLabel"]'); + await waitAndClick(page, '[qxclass="osparc.navigation.NavigationBar"] [qxclass="osparc.ui.form.EditLabel"]'); await page.keyboard.type(STUDY_NAME); await page.keyboard.press('Enter'); await page.waitForFunction(studyName => { return document.querySelector( - '[qxclass="osparc.desktop.NavigationBar"] [qxclass="osparc.ui.form.EditLabel"] [qxclass="qx.ui.basic.Label"]' + '[qxclass="osparc.navigation.NavigationBar"] [qxclass="osparc.ui.form.EditLabel"] [qxclass="qx.ui.basic.Label"]' ).innerText === studyName; }, {}, STUDY_NAME); await waitAndClick(page, '[osparc-test-id="dashboardBtn"]');