diff --git a/services/web/client/source/class/osparc/Application.js b/services/web/client/source/class/osparc/Application.js index 7453e317276..a271bbfa07f 100644 --- a/services/web/client/source/class/osparc/Application.js +++ b/services/web/client/source/class/osparc/Application.js @@ -47,7 +47,7 @@ qx.Class.define("osparc.Application", { window.localStorage.getItem("themeName") !== qx.theme.manager.Meta.getInstance().getTheme().name) { const preferredTheme = qx.Theme.getByName(window.localStorage.getItem("themeName")); const themes = qx.Theme.getAll(); - if (Object.keys(themes).includes(preferredTheme)) { + if (preferredTheme && Object.keys(themes).includes(preferredTheme.name)) { qx.theme.manager.Meta.getInstance().setTheme(preferredTheme); } } diff --git a/services/web/client/source/class/osparc/component/node/FilePickerNodeView.js b/services/web/client/source/class/osparc/component/node/FilePickerNodeView.js index bcab9db6ff1..9617a12c161 100644 --- a/services/web/client/source/class/osparc/component/node/FilePickerNodeView.js +++ b/services/web/client/source/class/osparc/component/node/FilePickerNodeView.js @@ -22,17 +22,6 @@ qx.Class.define("osparc.component.node.FilePickerNodeView", { extend: osparc.component.node.BaseNodeView, - /** - * @param node {osparc.data.model.Node} Node owning the widget - */ - construct: function(node) { - this.base(arguments); - - this.set({ - node - }); - }, - members: { __filePicker: null, @@ -58,11 +47,18 @@ qx.Class.define("osparc.component.node.FilePickerNodeView", { // overridden _applyNode: function(node) { - return; + if (!node.isFilePicker()) { + console.error("Only file picker nodes are supported"); + } }, __buildMyLayout: function() { - const filePicker = this.__filePicker = new osparc.file.FilePicker(this.getNode()); + const node = this.getNode(); + if (!node) { + return; + } + + const filePicker = this.__filePicker = new osparc.file.FilePicker(node); filePicker.buildLayout(); filePicker.init(); diff --git a/services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js b/services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js new file mode 100644 index 00000000000..61715dc4843 --- /dev/null +++ b/services/web/client/source/class/osparc/component/widget/BreadcrumbNavigation.js @@ -0,0 +1,148 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2020 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +/** + * + */ + +qx.Class.define("osparc.component.widget.BreadcrumbNavigation", { + 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: { + populateButtons: function(nodesIds = [], shape = "slash") { + const btns = []; + if (shape === "slash") { + for (let i=0; i { + this.fireDataEvent("nodeSelected", nodeId); + }, this); + return btn; + }, + + __createNodePathBtn: function(nodeId) { + const btn = this.__createNodeBtn(nodeId); + const study = osparc.store.Store.getInstance().getCurrentStudy(); + if (nodeId === study.getUuid()) { + study.bind("name", btn, "label"); + study.bind("name", btn, "toolTipText"); + } else { + const node = study.getWorkbench().getNode(nodeId); + if (node) { + node.bind("label", btn, "label"); + node.bind("label", btn, "toolTipText"); + } + } + return btn; + }, + + __createNodeSlideBtn: function(nodeId) { + const btn = this.__createNodeBtn(nodeId); + const study = osparc.store.Store.getInstance().getCurrentStudy(); + const slideShow = study.getUi().getSlideshow(); + const node = study.getWorkbench().getNode(nodeId); + if (node && nodeId in slideShow) { + const pos = slideShow[nodeId].position; + node.bind("label", btn, "label", { + converter: val => (pos+1).toString() + "- " + val + }); + node.bind("label", btn, "toolTipText"); + } + return btn; + }, + + __buttonsToBreadcrumb: function(btns, shape = "slash") { + this._removeAll(); + for (let i=0; i { + breadcrumbSplitter.setLeftWidget(thisBtn); + if (nextBtn) { + breadcrumbSplitter.setRightWidget(nextBtn); + } + }, this); + } + this._add(breadcrumbSplitter); + } + } + } +}); diff --git a/services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js b/services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js new file mode 100644 index 00000000000..cff1278ba13 --- /dev/null +++ b/services/web/client/source/class/osparc/component/widget/BreadcrumbSplitter.js @@ -0,0 +1,233 @@ +/* ************************************************************************ + + osparc - the simcore frontend + + https://osparc.io + + Copyright: + 2020 IT'IS Foundation, https://itis.swiss + + License: + MIT: https://opensource.org/licenses/MIT + + Authors: + * Odei Maiz (odeimaiz) + +************************************************************************ */ + +/** + * + */ + +qx.Class.define("osparc.component.widget.BreadcrumbSplitter", { + extend: qx.ui.core.Widget, + + construct: function(w, h) { + this.base(arguments); + + this.set({ + width: w, + height: h + }); + + 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 = new osparc.wrapper.Svg(); + svgWrapper.addListener("svgLibReady", () => { + this.__canvas = svgWrapper.createEmptyCanvas(randomID); + this.setReady(true); + this.fireDataEvent("SvgWidgetReady", true); + }); + svgWrapper.init(); + }); + }, + + properties: { + ready: { + check: "Boolean", + init: false + }, + + shape: { + check: ["slash", "arrow"], + nullable: true, + init: "slash" + }, + + leftWidget: { + check: "qx.ui.core.Widget", + nullable: true, + apply: "_applyLeftWidget" + }, + + rightWidget: { + check: "qx.ui.core.Widget", + nullable: true, + apply: "_applyRightWidget" + } + }, + + events: { + "SvgWidgetReady": "qx.event.type.Data" + }, + + statics: { + getTriangleControlsLeft: function(w = 16, h = 32) { + return [ + [0, 0], + [0, h], + [w, 0] + ]; + }, + + getTriangleControlsRight: function(w = 16, h = 32) { + return [ + [0, h], + [w, 0], + [w, h] + ]; + }, + + getSlashControls: function(w = 16, h = 32) { + const offset = 3; + return [ + [w-offset, offset], + [offset, h-offset] + ]; + }, + + getArrowControlsLeft: function(w = 16, h = 32) { + return [ + [0, 0], + [w, h/2], + [0, h] + ]; + }, + + getArrowControlsRight: function(w = 16, h = 32) { + return [ + [w, 0], + [0, 0], + [w, h/2], + [0, h], + [w, h] + ]; + }, + + getArrowControls: function(w = 16, h = 32) { + return [ + [0, 0], + [w, h/2], + [0, h] + ]; + } + }, + + members: { + __canvas: null, + __leftPart: null, + __rightPart: null, + + __getTextColor: function() { + return qx.theme.manager.Color.getInstance().resolve("text"); + }, + + __getBGColor: function(decoratorName) { + const decorator = qx.theme.manager.Decoration.getInstance().resolve(decoratorName); + if (decorator) { + const decoratorBG = decorator.getBackgroundColor(); + return qx.theme.manager.Color.getInstance().resolve(decoratorBG); + } + return null; + }, + + _applyLeftWidget: function(leftWidget) { + const bounds = leftWidget.getBounds(); + this.set({ + zIndex: leftWidget.getZIndex()+1, + marginTop: bounds.top + }); + + let controls; + switch (this.getShape()) { + case "slash": { + controls = this.self().getTriangleControlsLeft(16, bounds.height); + break; + } + case "arrow": { + controls = this.self().getArrowControlsLeft(16, bounds.height); + break; + } + } + if (controls) { + this.__leftPart = osparc.wrapper.Svg.drawPolygon(this.__canvas, controls); + const color = this.__getBGColor(leftWidget.getDecorator()); + if (color) { + osparc.wrapper.Svg.updatePolygonColor(this.__leftPart, color); + } + leftWidget.addListener("changeDecorator", e => { + const newColor = this.__getBGColor(leftWidget.getDecorator()); + if (newColor) { + osparc.wrapper.Svg.updatePolygonColor(this.__leftPart, newColor); + } + }, this); + } + }, + + _applyRightWidget: function(rightWidget) { + const bounds = rightWidget.getBounds(); + this.set({ + zIndex: rightWidget.getZIndex()+1, + marginTop: bounds.top + }); + + let controls; + switch (this.getShape()) { + case "slash": { + controls = this.self().getTriangleControlsRight(16, bounds.height); + break; + } + case "arrow": { + controls = this.self().getArrowControlsRight(16, bounds.height); + break; + } + } + if (controls) { + this.__rightPart = osparc.wrapper.Svg.drawPolygon(this.__canvas, controls); + const color = this.__getBGColor(rightWidget.getDecorator()); + if (color) { + osparc.wrapper.Svg.updatePolygonColor(this.__rightPart, color); + } + rightWidget.addListener("changeDecorator", e => { + const newColor = this.__getBGColor(rightWidget.getDecorator()); + if (newColor) { + osparc.wrapper.Svg.updatePolygonColor(this.__rightPart, newColor); + } + }, this); + } + + let plControls; + switch (this.getShape()) { + case "slash": { + plControls = this.self().getSlashControls(16, bounds.height); + break; + } + case "arrow": { + plControls = this.self().getArrowControls(16, bounds.height); + break; + } + } + if (plControls) { + const polyline = osparc.wrapper.Svg.drawPolyline(this.__canvas, plControls); + const color = this.__getTextColor(); + osparc.wrapper.Svg.updatePolylineColor(polyline, color); + rightWidget.addListener("changeDecorator", e => { + const newColor = this.__getTextColor(); + osparc.wrapper.Svg.updatePolylineColor(polyline, newColor); + }, this); + } + } + } +}); diff --git a/services/web/client/source/class/osparc/component/widget/NodesTree.js b/services/web/client/source/class/osparc/component/widget/NodesTree.js index 014b650afd6..5fea5bf5574 100644 --- a/services/web/client/source/class/osparc/component/widget/NodesTree.js +++ b/services/web/client/source/class/osparc/component/widget/NodesTree.js @@ -51,7 +51,7 @@ qx.Class.define("osparc.component.widget.NodesTree", { events: { "slidesEdit": "qx.event.type.Event", - "nodeDoubleClicked": "qx.event.type.Data", + "nodeSelected": "qx.event.type.Data", "removeNode": "qx.event.type.Data", "exportNode": "qx.event.type.Data", "changeSelectedNode": "qx.event.type.Data" @@ -316,7 +316,7 @@ qx.Class.define("osparc.component.widget.NodesTree", { __openItem: function(nodeId) { if (nodeId) { - this.fireDataEvent("nodeDoubleClicked", nodeId); + this.fireDataEvent("nodeSelected", nodeId); } }, 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 d3a9951a980..7d1c0c81830 100644 --- a/services/web/client/source/class/osparc/component/workbench/SvgWidget.js +++ b/services/web/client/source/class/osparc/component/workbench/SvgWidget.js @@ -43,13 +43,13 @@ qx.Class.define("osparc.component.workbench.SvgWidget", { this.addListenerOnce("appear", () => { let el = this.getContentElement().getDomElement(); qx.bom.element.Attribute.set(el, "id", svgLayerId); - this.__svgWrapper = new osparc.wrapper.Svg(); - this.__svgWrapper.addListener(("svgLibReady"), () => { - this.__canvas = this.__svgWrapper.createEmptyCanvas(svgLayerId); + const svgWrapper = new osparc.wrapper.Svg(); + svgWrapper.addListener("svgLibReady", () => { + this.__canvas = svgWrapper.createEmptyCanvas(svgLayerId); this.setReady(true); this.fireDataEvent("SvgWidgetReady", true); }); - this.__svgWrapper.init(); + svgWrapper.init(); }); }, @@ -64,11 +64,8 @@ qx.Class.define("osparc.component.workbench.SvgWidget", { "SvgWidgetReady": "qx.event.type.Data" }, - members: { - __svgWrapper: null, - __canvas: null, - - __getControls: function(x1, y1, x2, y2, offset = 60) { + statics: { + getCurveControls: function(x1, y1, x2, y2, offset = 60) { return [{ x: x1, y: y1 @@ -84,34 +81,38 @@ qx.Class.define("osparc.component.workbench.SvgWidget", { }]; }, - drawCurve: function(x1, y1, x2, y2, dashed = false) { - const controls = this.__getControls(x1, y1, x2, y2); - return this.__svgWrapper.drawCurve(this.__canvas, controls, dashed); - }, - updateCurve: function(curve, x1, y1, x2, y2, dashed = false) { - const controls = this.__getControls(x1, y1, x2, y2); - this.__svgWrapper.updateCurve(curve, controls, dashed); + const controls = osparc.component.workbench.SvgWidget.getCurveControls(x1, y1, x2, y2); + osparc.wrapper.Svg.updateCurve(curve, controls, dashed); }, removeCurve: function(curve) { - this.__svgWrapper.removeCurve(curve); - }, - - drawDashedRect: function(width, height, x, y) { - return this.__svgWrapper.drawDashedRect(this.__canvas, width, height, x, y); + osparc.wrapper.Svg.removeCurve(curve); }, updateRect: function(rect, x, y) { - this.__svgWrapper.updateRect(rect, x, y); + osparc.wrapper.Svg.updateRect(rect, x, y); }, removeRect: function(rect) { - this.__svgWrapper.removeRect(rect); + osparc.wrapper.Svg.removeRect(rect); }, - updateColor: function(curve, color) { - this.__svgWrapper.updateColor(curve, color); + updateCurveColor: function(curve, color) { + osparc.wrapper.Svg.updateCurveColor(curve, color); + } + }, + + members: { + __canvas: null, + + drawCurve: function(x1, y1, x2, y2, dashed = false) { + const controls = this.self().getCurveControls(x1, y1, x2, y2); + return osparc.wrapper.Svg.drawCurve(this.__canvas, controls, dashed); + }, + + drawDashedRect: function(width, height, x, y) { + return osparc.wrapper.Svg.drawDashedRect(this.__canvas, width, height, x, y); } } }); 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 607a96f4fe0..1b019a12aa9 100644 --- a/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js +++ b/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js @@ -125,7 +125,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { }, events: { - "nodeDoubleClicked": "qx.event.type.Data", + "nodeSelected": "qx.event.type.Data", "removeEdge": "qx.event.type.Data", "changeSelectedNode": "qx.event.type.Data" }, @@ -280,7 +280,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { }, this); nodeUI.addListener("dbltap", e => { - this.__nodeSelected(nodeUI.getNodeId()); + this.fireDataEvent("nodeSelected", nodeUI.getNodeId()); e.stopPropagation(); }, this); @@ -596,7 +596,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { const y1 = pointList[0][1]; const x2 = pointList[1][0]; const y2 = pointList[1][1]; - this.__svgWidgetLinks.updateCurve(edgeUI.getRepresentation(), x1, y1, x2, y2, !edgeUI.getEdge().getIsPortConnected()); + osparc.component.workbench.SvgWidget.updateCurve(edgeUI.getRepresentation(), x1, y1, x2, y2, !edgeUI.getEdge().getIsPortConnected()); } }); }, @@ -659,13 +659,13 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { if (this.__tempEdgeRepr === null) { this.__tempEdgeRepr = this.__svgWidgetLinks.drawCurve(x1, y1, x2, y2); } else { - this.__svgWidgetLinks.updateCurve(this.__tempEdgeRepr, x1, y1, x2, y2); + osparc.component.workbench.SvgWidget.updateCurve(this.__tempEdgeRepr, x1, y1, x2, y2); } }, __removeTempEdge: function() { if (this.__tempEdgeRepr !== null) { - this.__svgWidgetLinks.removeCurve(this.__tempEdgeRepr); + osparc.component.workbench.SvgWidget.removeCurve(this.__tempEdgeRepr); } this.__tempEdgeRepr = null; this.__tempEdgeNodeId = null; @@ -736,7 +736,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { __clearEdge: function(edge) { if (edge) { - this.__svgWidgetLinks.removeCurve(edge.getRepresentation()); + osparc.component.workbench.SvgWidget.removeCurve(edge.getRepresentation()); const index = this.__edgesUI.indexOf(edge); if (index > -1) { this.__edgesUI.splice(index, 1); @@ -834,7 +834,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { if (this.__isSelectedItemAnEdge()) { const unselectedEdge = this.__getEdgeUI(oldId); const unselectedColor = qx.theme.manager.Color.getInstance().getTheme().colors["workbench-edge-comp-active"]; - this.__svgWidgetLinks.updateColor(unselectedEdge.getRepresentation(), unselectedColor); + osparc.component.workbench.SvgWidget.updateCurveColor(unselectedEdge.getRepresentation(), unselectedColor); } } @@ -842,7 +842,7 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { if (this.__isSelectedItemAnEdge()) { const selectedEdge = this.__getEdgeUI(newID); const selectedColor = qx.theme.manager.Color.getInstance().getTheme().colors["workbench-edge-selected"]; - this.__svgWidgetLinks.updateColor(selectedEdge.getRepresentation(), selectedColor); + osparc.component.workbench.SvgWidget.updateCurveColor(selectedEdge.getRepresentation(), selectedColor); } else if (newID) { this.fireDataEvent("changeSelectedNode", newID); } @@ -850,10 +850,6 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { this.__unlinkButton.setVisibility(this.__isSelectedItemAnEdge() ? "visible" : "excluded"); }, - __nodeSelected: function(nodeId) { - this.fireDataEvent("nodeDoubleClicked", nodeId); - }, - __isSelectedItemAnEdge: function() { return Boolean(this.__getEdgeUI(this.__selectedItemId)); }, @@ -976,10 +972,10 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", { left: posX + parseInt(nodeWidth/2) - parseInt(dropBounds.width/2), top: posY + parseInt(nodeHeight/2) - parseInt(dropBounds.height/2) }); - this.__svgWidgetDrop.updateRect(this.__dropHint.rect, posX, posY); + osparc.component.workbench.SvgWidget.updateRect(this.__dropHint.rect, posX, posY); } else { this.__dropHint.setVisibility("excluded"); - this.__svgWidgetDrop.removeRect(this.__dropHint.rect); + osparc.component.workbench.SvgWidget.removeRect(this.__dropHint.rect); this.__dropHint = null; } }, diff --git a/services/web/client/source/class/osparc/data/model/Edge.js b/services/web/client/source/class/osparc/data/model/Edge.js index 98bbc89daf8..fd2090706db 100644 --- a/services/web/client/source/class/osparc/data/model/Edge.js +++ b/services/web/client/source/class/osparc/data/model/Edge.js @@ -45,7 +45,7 @@ qx.Class.define("osparc.data.model.Edge", { this.setEdgeId(edgeId || osparc.utils.Utils.uuidv4()); this.setInputNode(node1); this.setOutputNode(node2); - this.setIsPortConnected(node2.getPropsForm().hasAnyPortConnected()); + this.__checkIsPortConnected(node2); }, properties: { @@ -82,10 +82,28 @@ qx.Class.define("osparc.data.model.Edge", { }, _applyOutputNode: function(node) { - node.getPropsForm().addListener("linkFieldModified", () => { - this.setIsPortConnected(node.getPropsForm().hasAnyPortConnected()); - }); - this.setIsPortConnected(node.getPropsForm().hasAnyPortConnected()); + if (node.getPropsForm()) { + node.getPropsForm().addListener("linkFieldModified", () => { + this.__checkIsPortConnected(node); + }); + this.__checkIsPortConnected(node); + } + }, + + __checkIsPortConnected: function(node2) { + if (node2.getPropsForm()) { + this.setIsPortConnected(node2.getPropsForm().hasAnyPortConnected()); + } + if (node2.isContainer()) { + const innerNodes = node2.getInnerNodes(); + for (const innerNodeId in innerNodes) { + const innerNode = innerNodes[innerNodeId]; + if (innerNode.getPropsForm()) { + this.setIsPortConnected(innerNode.getPropsForm().hasAnyPortConnected()); + } + break; + } + } } } }); diff --git a/services/web/client/source/class/osparc/data/model/Node.js b/services/web/client/source/class/osparc/data/model/Node.js index 88a08eabe41..0602d1abe10 100644 --- a/services/web/client/source/class/osparc/data/model/Node.js +++ b/services/web/client/source/class/osparc/data/model/Node.js @@ -177,6 +177,10 @@ qx.Class.define("osparc.data.model.Node", { }, statics: { + isContainer: function(metaData) { + return (metaData && metaData.key && metaData.key.includes("nodes-group")); + }, + isDynamic: function(metaData) { return (metaData && metaData.type && metaData.type === "dynamic"); }, @@ -224,7 +228,7 @@ qx.Class.define("osparc.data.model.Node", { }, isContainer: function() { - return this.getKey().includes("nodes-group"); + return osparc.data.model.Node.isContainer(this.getMetaData()); }, isDynamic: function() { 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 4a0fc8dd7fc..7ad7b400b29 100644 --- a/services/web/client/source/class/osparc/data/model/StudyUI.js +++ b/services/web/client/source/class/osparc/data/model/StudyUI.js @@ -29,14 +29,14 @@ qx.Class.define("osparc.data.model.StudyUI", { this.base(arguments); this.set({ - workbech: studyDataUI.workbench || {}, + workbench: studyDataUI.workbench || {}, slideshow: studyDataUI.slideshow || {}, currentNodeId: studyDataUI.currentNodeId || null }); }, properties: { - workbech: { + workbench: { check: "Object", nullable: true }, @@ -58,7 +58,7 @@ qx.Class.define("osparc.data.model.StudyUI", { serialize: function() { const currentStudy = osparc.store.Store.getInstance().getCurrentStudy(); let jsonObject = {}; - jsonObject["workbench"] = currentStudy.getWorkbench().serializeUI(); + jsonObject["workbench"] = currentStudy ? currentStudy.getWorkbench().serializeUI() : this.getWorkbench(); jsonObject["slideshow"] = this.getSlideshow(); jsonObject["currentNodeId"] = this.getCurrentNodeId(); return jsonObject; diff --git a/services/web/client/source/class/osparc/desktop/ControlsBar.js b/services/web/client/source/class/osparc/desktop/ControlsBar.js index 6849ae0160f..4cf843ea82c 100644 --- a/services/web/client/source/class/osparc/desktop/ControlsBar.js +++ b/services/web/client/source/class/osparc/desktop/ControlsBar.js @@ -216,7 +216,7 @@ qx.Class.define("osparc.desktop.ControlsBar", { if (selectedNodes.length) { groupBtnVisibility = "visible"; } - if (selectedNodes.length === 1 && selectedNodes[0].getMetaData().type === "group") { + if (selectedNodes.length === 1 && selectedNodes[0].isContainer()) { ungroupBtnVisibility = "visible"; } this.__groupButton.setVisibility(groupBtnVisibility); diff --git a/services/web/client/source/class/osparc/desktop/NavigationBar.js b/services/web/client/source/class/osparc/desktop/NavigationBar.js index c7c36e77523..d66cfbe39a3 100644 --- a/services/web/client/source/class/osparc/desktop/NavigationBar.js +++ b/services/web/client/source/class/osparc/desktop/NavigationBar.js @@ -116,8 +116,8 @@ qx.Class.define("osparc.desktop.NavigationBar", { __startSlidesBtn: null, __stopSlidesBtn: null, __studyTitle: null, - __workbenchNodesLayout: null, - __guidedNodesLayout: null, + __navNodes: null, + __navNodesLayout: null, buildLayout: function() { this.getChildControl("logo"); @@ -157,8 +157,7 @@ qx.Class.define("osparc.desktop.NavigationBar", { } }, this); - this.__workbenchNodesLayout = this.getChildControl("workbench-nodes-path-container"); - this.__guidedNodesLayout = this.getChildControl("guided-nodes-path-container"); + this.__navNodesLayout = this.getChildControl("navigation-nodes-path-container"); this._add(new qx.ui.core.Spacer(), { flex: 1 @@ -214,18 +213,18 @@ qx.Class.define("osparc.desktop.NavigationBar", { }); this._add(control); break; - case "workbench-nodes-path-container": - control = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({ - alignY: "middle" - })); - this._add(control); - break; - case "guided-nodes-path-container": - control = new qx.ui.toolbar.Part().set({ - alignY: "middle" + 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 }); - this._add(control); break; + } case "manual": control = this.__createManualMenuBtn(); control.set(this.self().BUTTON_OPTIONS); @@ -255,118 +254,40 @@ qx.Class.define("osparc.desktop.NavigationBar", { return this.__dashboardBtn; }, - __createNodePathBtn: function(nodeId) { - const study = osparc.store.Store.getInstance().getCurrentStudy(); - const btn = new qx.ui.form.Button().set({ - ...this.self().BUTTON_OPTIONS, - maxWidth: 200 - }); - if (nodeId === study.getUuid()) { - study.bind("name", btn, "label"); - study.bind("name", btn, "toolTipText"); - } else { - const node = study.getWorkbench().getNode(nodeId); - if (node) { - node.bind("label", btn, "label"); - node.bind("label", btn, "toolTipText"); - } - } - btn.addListener("execute", () => { - this.fireDataEvent("nodeSelected", nodeId); - }, this); - return btn; - }, - - __createNodeSlideBtn: function(nodeId, pos) { - const study = osparc.store.Store.getInstance().getCurrentStudy(); - const btn = new qx.ui.toolbar.RadioButton().set({ - ...this.self().BUTTON_OPTIONS, - maxWidth: 200 - }); - const node = study.getWorkbench().getNode(nodeId); - if (node) { - node.bind("label", btn, "label", { - converter: val => (pos+1).toString() + " - " + val - }); - node.bind("label", btn, "toolTipText"); - } - btn.addListener("execute", () => { - this.fireDataEvent("nodeSelected", nodeId); - }, this); - return btn; - }, - - __setPathButtons: function(nodeIds) { - if (this.getPageContext() === "workbench") { - this.__setWorkbenchBtnsVis(true); - this.__setSlidesBtnsVis(false); - - if (nodeIds.length > 1) { - this.__studyTitle.exclude(); - this.__workbenchNodesLayout.show(); - } else { - this.__studyTitle.show(); - this.__workbenchNodesLayout.exclude(); - } - } else { - this.__setWorkbenchBtnsVis(false); - this.__setSlidesBtnsVis(true); - } - }, - __populateWorkbenchNodesLayout: function() { const study = this.getStudy(); const nodeIds = study.getWorkbench().getPathIds(study.getUi().getCurrentNodeId()); - this.__setPathButtons(nodeIds); - - this.__workbenchNodesLayout.removeAll(); - for (let i=0; i").set({ - font: "text-14" - }); - this.__workbenchNodesLayout.add(arrow); - } - if (i === nodeIds.length-1) { - btn.setFont("title-14"); - } + 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(); - if (study) { - this.__guidedNodesLayout.removeAll(); - const radioGroup = new qx.ui.form.RadioGroup(); - const currentNodeId = study.getUi().getCurrentNodeId(); - 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); - let selectedBtn = null; - nodes.forEach(node => { - const btn = this.__createNodeSlideBtn(node.nodeId, node.position); - if (node.nodeId === currentNodeId) { - selectedBtn = btn; - } - this.__guidedNodesLayout.add(btn); - radioGroup.add(btn); + const slideShow = study.getUi().getSlideshow(); + const nodes = []; + for (let nodeId in slideShow) { + const node = slideShow[nodeId]; + nodes.push({ + ...node, + nodeId }); - if (selectedBtn) { - radioGroup.setSelection([selectedBtn]); - } - radioGroup.setAllowEmptySelection(false); } + 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) { @@ -374,30 +295,26 @@ qx.Class.define("osparc.desktop.NavigationBar", { case "dashboard": this.__dashboardLabel.show(); this.__dashboardBtn.exclude(); - this.__resetSlideBtnsVis(false); - this.__setWorkbenchBtnsVis(false); - this.__setSlidesBtnsVis(false); + this.__resetSlideCtrlBtnsVis(false); + this.__studyTitle.exclude(); + this.__navNodesLayout.exclude(); break; case "workbench": this.__dashboardLabel.exclude(); this.__dashboardBtn.show(); - this.__resetSlideBtnsVis(true); - this.__setWorkbenchBtnsVis(true); - this.__setSlidesBtnsVis(false); + this.__resetSlideCtrlBtnsVis(true); this.__populateWorkbenchNodesLayout(); break; case "slideshow": this.__dashboardLabel.exclude(); this.__dashboardBtn.show(); - this.__resetSlideBtnsVis(true); - this.__setWorkbenchBtnsVis(false); - this.__setSlidesBtnsVis(true); + this.__resetSlideCtrlBtnsVis(true); this.__populateGuidedNodesLayout(); break; } }, - __resetSlideBtnsVis: function() { + __resetSlideCtrlBtnsVis: function() { this.self().areSlidesEnabled() .then(areSlidesEnabled => { const context = ["workbench", "slideshow"].includes(this.getPageContext()); @@ -419,24 +336,6 @@ qx.Class.define("osparc.desktop.NavigationBar", { }); }, - __setWorkbenchBtnsVis: function(show) { - if (show) { - this.__studyTitle.show(); - this.__workbenchNodesLayout.show(); - } else { - this.__studyTitle.exclude(); - this.__workbenchNodesLayout.exclude(); - } - }, - - __setSlidesBtnsVis: function(show) { - if (show) { - this.__guidedNodesLayout.show(); - } else { - this.__guidedNodesLayout.exclude(); - } - }, - __createSlideStartBtn: function() { const startBtn = new qx.ui.form.Button(this.tr("Start Guided mode"), "@FontAwesome5Solid/caret-square-right/16").set({ ...this.self().BUTTON_OPTIONS @@ -634,7 +533,7 @@ qx.Class.define("osparc.desktop.NavigationBar", { if (study) { study.bind("name", this.__studyTitle, "value"); study.getUi().addListener("changeSlideshow", () => { - this.__resetSlideBtnsVis(); + this.__resetSlideCtrlBtnsVis(); }); study.getUi().addListener("changeCurrentNodeId", () => { if (this.getPageContext() === "workbench") { diff --git a/services/web/client/source/class/osparc/desktop/SlideShowView.js b/services/web/client/source/class/osparc/desktop/SlideShowView.js index 7af8836500c..875e203c935 100644 --- a/services/web/client/source/class/osparc/desktop/SlideShowView.js +++ b/services/web/client/source/class/osparc/desktop/SlideShowView.js @@ -36,7 +36,6 @@ qx.Class.define("osparc.desktop.SlideShowView", { }, members: { - __nodeView: null, __controlsBar: null, __prvsBtn: null, __nextBtn: null, @@ -73,10 +72,21 @@ qx.Class.define("osparc.desktop.SlideShowView", { const node = this.getStudy().getWorkbench().getNode(nodeId); if (node) { - this.__nodeView.setNode(node); - this.__nodeView.populateLayout(); - this.__nodeView.getInputsView().exclude(); - this.__nodeView.getOutputsView().exclude(); + let view; + if (node.isContainer()) { + view = new osparc.component.node.GroupNodeView(); + } else if (node.isFilePicker()) { + view = new osparc.component.node.FilePickerNodeView(); + } else { + view = new osparc.component.node.NodeView(); + } + if (view) { + view.setNode(node); + view.populateLayout(); + view.getInputsView().exclude(); + view.getOutputsView().exclude(); + this.__showInMainView(view); + } } this.getStudy().getUi().setCurrentNodeId(nodeId); }, @@ -96,11 +106,10 @@ qx.Class.define("osparc.desktop.SlideShowView", { __initViews: function() { this._removeAll(); - const nodeView = this.__nodeView = new osparc.component.node.NodeView(); - this._add(nodeView, { - flex: 1 - }); + this.__createControlsBar(); + }, + __createControlsBar: function() { const controlsBar = this.__controlsBar = new qx.ui.container.Composite(new qx.ui.layout.HBox(10)).set({ minHeight: 40, padding: 5 @@ -110,7 +119,7 @@ qx.Class.define("osparc.desktop.SlideShowView", { flex: 1 }); - const prvsBtn = this.__prvsBtn = new qx.ui.form.Button(this.tr("Previuos")).set({ + const prvsBtn = this.__prvsBtn = new qx.ui.form.Button(this.tr("Previous")).set({ allowGrowX: false }); prvsBtn.addListener("execute", () => { @@ -129,6 +138,18 @@ qx.Class.define("osparc.desktop.SlideShowView", { this._add(controlsBar); }, + __showInMainView: function(nodeView) { + const children = this._getChildren(); + for (let i=0; i { this.__lastSavedStudy = osparc.wrapper.JsonDiffPatch.getInstance().clone(newObj); }).catch(error => { + console.error(error); this.getLogger().error(null, "Error updating pipeline"); // Need to throw the error to be able to handle it later throw error; diff --git a/services/web/client/source/class/osparc/desktop/WorkbenchView.js b/services/web/client/source/class/osparc/desktop/WorkbenchView.js index 1b3caa8234d..2071ddf5af3 100644 --- a/services/web/client/source/class/osparc/desktop/WorkbenchView.js +++ b/services/web/client/source/class/osparc/desktop/WorkbenchView.js @@ -102,7 +102,8 @@ qx.Class.define("osparc.desktop.WorkbenchView", { this.__workbenchUI.loadModel(node); this.__groupNodeView.populateLayout(); } else if (node.isFilePicker()) { - const nodeView = new osparc.component.node.FilePickerNodeView(node); + const nodeView = new osparc.component.node.FilePickerNodeView(); + nodeView.setNode(node); this.__showInMainView(nodeView, nodeId); nodeView.populateLayout(); } else { @@ -550,7 +551,7 @@ qx.Class.define("osparc.desktop.WorkbenchView", { nodesTree, workbenchUI ].forEach(widget => { - widget.addListener("nodeDoubleClicked", e => { + widget.addListener("nodeSelected", e => { const nodeId = e.getData(); this.nodeSelected(nodeId); }, this); diff --git a/services/web/client/source/class/osparc/utils/Utils.js b/services/web/client/source/class/osparc/utils/Utils.js index 0adf603faa7..383b6ce537f 100644 --- a/services/web/client/source/class/osparc/utils/Utils.js +++ b/services/web/client/source/class/osparc/utils/Utils.js @@ -46,7 +46,7 @@ qx.Class.define("osparc.utils.Utils", { logoPath = "osparc/s4l_logo.png"; break; case "tis": - logoPath = "osparc/ti-solutions.svg"; + logoPath = "osparc/ti-tp.svg"; break; default: { const colorManager = qx.theme.manager.Color.getInstance(); diff --git a/services/web/client/source/class/osparc/wrapper/Svg.js b/services/web/client/source/class/osparc/wrapper/Svg.js index 4c62a6d8de2..24f8177339f 100644 --- a/services/web/client/source/class/osparc/wrapper/Svg.js +++ b/services/web/client/source/class/osparc/wrapper/Svg.js @@ -31,12 +31,6 @@ qx.Class.define("osparc.wrapper.Svg", { extend: qx.core.Object, - statics: { - NAME: "svg.js", - VERSION: "2.7.1", - URL: "https://github.com/svgdotjs/svg.js" - }, - construct: function() { }, @@ -52,36 +46,12 @@ qx.Class.define("osparc.wrapper.Svg", { "svgLibReady": "qx.event.type.Data" }, - members: { - init: function() { - // initialize the script loading - let svgPath = "svg/svg.js"; - let svgPathPath = "svg/svg.path.js"; - let dynLoader = new qx.util.DynamicScriptLoader([ - svgPath, - svgPathPath - ]); - - dynLoader.addListenerOnce("ready", e => { - console.log(svgPath + " loaded"); - this.setLibReady(true); - this.fireDataEvent("svgLibReady", true); - }, this); - - dynLoader.addListener("failed", e => { - let data = e.getData(); - console.error("failed to load " + data.script); - this.fireDataEvent("svgLibReady", false); - }, this); - - dynLoader.start(); - }, - - createEmptyCanvas: function(id) { - return SVG(id); - }, + statics: { + NAME: "svg.js", + VERSION: "2.7.1", + URL: "https://github.com/svgdotjs/svg.js", - __curateControls: function(controls) { + curateCurveControls: function(controls) { [ controls[0], controls[1], @@ -100,7 +70,7 @@ qx.Class.define("osparc.wrapper.Svg", { drawCurve: function(draw, controls, dashed, edgeWidth = 3, portSphereDiameter = 4, arrowSize = 4) { const edgeColor = qx.theme.manager.Color.getInstance().getTheme().colors["workbench-edge-comp-active"]; - this.__curateControls(controls); + osparc.wrapper.Svg.curateCurveControls(controls); const path = draw.path() .M(controls[0].x, controls[0].y) @@ -172,7 +142,7 @@ qx.Class.define("osparc.wrapper.Svg", { rect.remove(); }, - updateColor: function(curve, color) { + updateCurveColor: function(curve, color) { if (curve.type === "path") { curve.attr({ stroke: color @@ -185,6 +155,65 @@ qx.Class.define("osparc.wrapper.Svg", { }); } } + }, + + drawPolygon: function(draw, controls) { + const polygon = draw.polygon(controls.join()) + .fill("none") + .stroke({ + width: 0 + }) + .move(0, 0); + return polygon; + }, + + updatePolygonColor: function(polygon, color) { + polygon.fill(color); + }, + + drawPolyline: function(draw, controls) { + const polyline = draw.polyline(controls.join()) + .fill("none") + .stroke({ + color: "#BFBFBF", + width: 1 + }); + return polyline; + }, + + updatePolylineColor: function(polyline, color) { + polyline.stroke({ + color: color + }); + } + }, + + members: { + init: function() { + // initialize the script loading + let svgPath = "svg/svg.js"; + let svgPathPath = "svg/svg.path.js"; + let dynLoader = new qx.util.DynamicScriptLoader([ + svgPath, + svgPathPath + ]); + + dynLoader.addListenerOnce("ready", () => { + this.setLibReady(true); + this.fireDataEvent("svgLibReady", true); + }, this); + + dynLoader.addListener("failed", e => { + let data = e.getData(); + console.error("failed to load " + data.script); + this.fireDataEvent("svgLibReady", false); + }, this); + + dynLoader.start(); + }, + + createEmptyCanvas: function(id) { + return SVG(id); } } }); diff --git a/services/web/client/source/resource/osparc/ti-tp.svg b/services/web/client/source/resource/osparc/ti-tp.svg new file mode 100644 index 00000000000..f8017fe1e97 --- /dev/null +++ b/services/web/client/source/resource/osparc/ti-tp.svg @@ -0,0 +1,27 @@ + + + + + + + background + + + + Layer 1 + + + + + + + + + + + + + + + + \ No newline at end of file