diff --git a/services/web/client/source/class/osparc/component/node/BaseNodeView.js b/services/web/client/source/class/osparc/component/node/BaseNodeView.js
index 4540cfb4a6b..c7b658f6508 100644
--- a/services/web/client/source/class/osparc/component/node/BaseNodeView.js
+++ b/services/web/client/source/class/osparc/component/node/BaseNodeView.js
@@ -58,6 +58,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
__pane2: null,
__title: null,
__serviceInfoLayout: null,
+ __nodeStatusUI: null,
__header: null,
_mainView: null,
__inputsView: null,
@@ -66,8 +67,9 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
_settingsLayout: null,
_mapperLayout: null,
_iFrameLayout: null,
+ _loggerLayout: null,
__buttonContainer: null,
- __filesButton: null,
+ __outFilesButton: null,
populateLayout: function() {
this.__cleanLayout();
@@ -77,6 +79,8 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
this.__addOutputPortsUIs();
this._addSettings();
this._addIFrame();
+ // this._addLogger();
+
this._addButtons();
},
@@ -193,6 +197,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
this._settingsLayout = this.self().createSettingsGroupBox(this.tr("Settings"));
this._mapperLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(10));
this._iFrameLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox());
+ this._loggerLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox());
return mainView;
},
@@ -237,8 +242,14 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
header.addSpacer();
+ // just a placeholder until the node is set
+ const nodeStatusUI = this.__nodeStatusUI = new qx.ui.core.Widget();
+ header.add(nodeStatusUI);
+
+ header.addSpacer();
+
const buttonsPart = this.__buttonContainer = new qx.ui.toolbar.Part();
- const filesBtn = this.__filesButton = new qx.ui.toolbar.Button(this.tr("Output Files"), "@FontAwesome5Solid/folder-open/14");
+ const filesBtn = this.__outFilesButton = new qx.ui.toolbar.Button(this.tr("Output Files"), "@FontAwesome5Solid/folder-open/14");
osparc.utils.Utils.setIdToWidget(filesBtn, "nodeViewFilesBtn");
filesBtn.addListener("execute", () => this.__openNodeDataManager(), this);
buttonsPart.add(filesBtn);
@@ -334,7 +345,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
retrieveBtn.setEnabled(Boolean(this.getNode().getServiceUrl()));
this.__buttonContainer.add(retrieveBtn);
}
- this.__buttonContainer.add(this.__filesButton);
+ this.__buttonContainer.add(this.__outFilesButton);
this.__header.add(this.__buttonContainer);
},
@@ -346,6 +357,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
const othersStatus2 = isSettingsGroupShowable && !maximize ? "visible" : "excluded";
this._settingsLayout.setVisibility(othersStatus2);
this._mapperLayout.setVisibility(othersStatus);
+ this._loggerLayout.setVisibility(othersStatus);
this.__header.setVisibility(othersStatus);
},
@@ -475,6 +487,10 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
throw new Error("Abstract method called!");
},
+ _addLogger: function() {
+ return;
+ },
+
/**
* @abstract
*/
@@ -482,6 +498,16 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
throw new Error("Abstract method called!");
},
+ __createNodeStatusUI: function(node) {
+ const nodeStatusUI = new osparc.ui.basic.NodeStatusUI(node).set({
+ backgroundColor: "material-button-background"
+ });
+ nodeStatusUI.getChildControl("label").set({
+ font: "text-16"
+ });
+ return nodeStatusUI;
+ },
+
/**
* @param node {osparc.data.model.Node} node
*/
@@ -498,6 +524,13 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
const infoButton = this.__getInfoButton();
this.__serviceInfoLayout.add(infoButton);
}
+
+ const idx = this.__header.indexOf(this.__nodeStatusUI);
+ if (idx > -1) {
+ this.__header.remove(this.__nodeStatusUI);
+ }
+ this.__nodeStatusUI = this.__createNodeStatusUI(node);
+ this.__header.addAt(this.__nodeStatusUI, idx);
}
}
});
diff --git a/services/web/client/source/class/osparc/component/node/NodeView.js b/services/web/client/source/class/osparc/component/node/NodeView.js
index e1e1e20c53e..18d0e466cef 100644
--- a/services/web/client/source/class/osparc/component/node/NodeView.js
+++ b/services/web/client/source/class/osparc/component/node/NodeView.js
@@ -100,34 +100,55 @@ qx.Class.define("osparc.component.node.NodeView", {
const loadingPage = this.getNode().getLoadingPage();
const iFrame = this.getNode().getIFrame();
- if (loadingPage === null && iFrame === null) {
- return;
- }
- [
- loadingPage,
- iFrame
- ].forEach(widget => {
- if (widget) {
- widget.addListener("maximize", e => {
- this._maximizeIFrame(true);
- }, this);
- widget.addListener("restore", e => {
- this._maximizeIFrame(false);
- }, this);
- this._maximizeIFrame(widget.hasState("maximized"));
- }
- });
- this.__iFrameChanged();
-
- iFrame.addListener("load", () => {
+ if (loadingPage && iFrame) {
+ [
+ loadingPage,
+ iFrame
+ ].forEach(widget => {
+ if (widget) {
+ widget.addListener("maximize", e => {
+ this._maximizeIFrame(true);
+ }, this);
+ widget.addListener("restore", e => {
+ this._maximizeIFrame(false);
+ }, this);
+ this._maximizeIFrame(widget.hasState("maximized"));
+ }
+ });
this.__iFrameChanged();
- });
+
+ iFrame.addListener("load", () => {
+ this.__iFrameChanged();
+ });
+ } else {
+ // This will keep what comes after at the bottom
+ this._iFrameLayout.add(new qx.ui.core.Spacer(), {
+ flex: 1
+ });
+ }
this._addToMainView(this._iFrameLayout, {
flex: 1
});
},
+ _addLogger: function() {
+ this._loggerLayout.removeAll();
+
+ const loggerView = this.__loggerView = this.getNode().getLogger().set({
+ maxHeight: 250
+ });
+ loggerView.getChildControl("pin-node").exclude();
+ const loggerPanel = new osparc.desktop.PanelView(this.tr("Logger"), loggerView).set({
+ collapsed: true,
+ backgroundColor: "background-main-lighter"
+ });
+ osparc.utils.Utils.setIdToWidget(loggerPanel.getTitleLabel(), "nodeLoggerTitleLabel");
+ this._loggerLayout.add(loggerPanel);
+
+ this._addToMainView(this._loggerLayout);
+ },
+
_openEditAccessLevel: function() {
const settingsEditorLayout = osparc.component.node.BaseNodeView.createSettingsGroupBox(this.tr("Settings"));
const propsFormEditor = this.getNode().getPropsFormEditor();
diff --git a/services/web/client/source/class/osparc/component/widget/CollapsibleView.js b/services/web/client/source/class/osparc/component/widget/CollapsibleView.js
index c95e7347af7..b31323a7ab2 100644
--- a/services/web/client/source/class/osparc/component/widget/CollapsibleView.js
+++ b/services/web/client/source/class/osparc/component/widget/CollapsibleView.js
@@ -100,12 +100,18 @@ qx.Class.define("osparc.component.widget.CollapsibleView", {
}
case "title": {
const header = this.getChildControl("header");
- control = new qx.ui.basic.Atom(this.getTitle());
+ control = new qx.ui.basic.Label(this.getTitle());
header.addAt(control, 1);
// Attach handler
this.__attachToggler(control);
break;
}
+ case "icon": {
+ const header = this.getChildControl("header");
+ control = new qx.ui.basic.Image();
+ header.addAt(control, 2);
+ break;
+ }
}
return control || this.base(arguments, id);
},
@@ -187,12 +193,16 @@ qx.Class.define("osparc.component.widget.CollapsibleView", {
}
},
+ _applyCaretSize: function(size) {
+ this.getChildControl("caret").setSource(this.__getCaretId(this.getCollapsed()));
+ },
+
_applyTitle: function(title) {
- this.getChildControl("title").setLabel(title);
+ this.getChildControl("title").setValue(title);
},
- _applyCaretSize: function(size) {
- this.getChildControl("caret").setSource(this.__getCaretId(this.getCollapsed()));
+ _applyIcon: function(icon) {
+ this.getChildControl("icon").setSource(icon);
},
__getCaretId: function(collapsed) {
diff --git a/services/web/client/source/class/osparc/component/widget/NodePorts.js b/services/web/client/source/class/osparc/component/widget/NodePorts.js
index 7fba70ed21e..3518e512f87 100644
--- a/services/web/client/source/class/osparc/component/widget/NodePorts.js
+++ b/services/web/client/source/class/osparc/component/widget/NodePorts.js
@@ -44,7 +44,30 @@ qx.Class.define("osparc.component.widget.NodePorts", {
this.base(arguments, node.getLabel());
+ this.getTitleBar().set({
+ height: 30
+ });
node.bind("label", this, "title");
+
+ node.getStatus().bind("modified", this.getChildControl("icon"), "source", {
+ converter: modified => {
+ if (modified === null) {
+ return osparc.utils.StatusUI.getIconSource();
+ }
+ return osparc.utils.StatusUI.getIconSource(modified === true ? "modified" : "up-to-date");
+ }
+ }, this);
+ node.getStatus().bind("modified", this.getChildControl("icon"), "textColor", {
+ converter: modified => {
+ if (modified === null) {
+ return osparc.utils.StatusUI.getColor();
+ }
+ return osparc.utils.StatusUI.getColor(modified === true ? "modified" : "up-to-date");
+ }
+ }, this);
+ node.getStatus().bind("modified", this.getChildControl("icon"), "toolTipText", {
+ converter: modified => modified === true ? this.tr("Out of date") : ""
+ }, this);
},
properties: {
diff --git a/services/web/client/source/class/osparc/component/widget/logger/RemoteTableModel.js b/services/web/client/source/class/osparc/component/widget/logger/LoggerTable.js
similarity index 82%
rename from services/web/client/source/class/osparc/component/widget/logger/RemoteTableModel.js
rename to services/web/client/source/class/osparc/component/widget/logger/LoggerTable.js
index 881c33b7642..52e84060195 100644
--- a/services/web/client/source/class/osparc/component/widget/logger/RemoteTableModel.js
+++ b/services/web/client/source/class/osparc/component/widget/logger/LoggerTable.js
@@ -25,7 +25,7 @@
* Here is a little example of how to use the widget.
*
*
- * let tableModel = this.__logModel = new osparc.component.widget.logger.RemoteTableModel();
+ * let tableModel = this.__logModel = new osparc.component.widget.logger.LoggerTable();
* tableModel.setColumns(["Origin", "Message"], ["whoRich", "whatRich"]);
* let custom = {
* tableColumnModel : function(obj) {
@@ -42,14 +42,19 @@
* @asset(demobrowser/backend/remote_table.php)
*/
-qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
-
+qx.Class.define("osparc.component.widget.logger.LoggerTable", {
extend : qx.ui.table.model.Remote,
construct : function() {
this.base(arguments);
- this.setColumns(["Origin", "Message"], ["whoRich", "msgRich"]);
+ this.setColumns([
+ "Origin",
+ "Message"
+ ], [
+ "whoRich",
+ "msgRich"
+ ]);
this.__rawData = [];
},
@@ -60,15 +65,11 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
check : "Number",
init: -1
},
+
filterString: {
nullable: true,
check : "String",
init: ""
- },
- caseSensitive: {
- nullable: false,
- check : "Boolean",
- init: false
}
},
@@ -85,8 +86,8 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
addRows: function(newRows) {
for (let i=0; i
- * let loggerView = new osparc.component.widget.logger.LoggerView(workbench);
+ * let loggerView = new osparc.component.widget.logger.LoggerView();
* this.getRoot().add(loggerView);
* loggerView.info(null, "Hello world");
*
@@ -62,8 +62,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
this._setLayout(new qx.ui.layout.VBox());
- const filterToolbar = this.__createFilterToolbar();
- this._add(filterToolbar);
+ this.__createFilterToolbar();
const table = this.__createTableLayout();
this._add(table, {
@@ -71,14 +70,8 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
});
this.__messengerColors = new Set();
-
- this.__createInitMsg();
-
- this.__textFilterField.addListener("changeValue", this.__applyFilters, this);
},
- events: {},
-
properties: {
logLevel: {
apply : "__applyFilters",
@@ -87,12 +80,6 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
init: LOG_LEVEL[0].debug
},
- caseSensitive: {
- nullable: false,
- check : "Boolean",
- init: false
- },
-
currentNodeId: {
check: "String",
nullable: true,
@@ -129,68 +116,99 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
},
members: {
- __currentNodeButton: null,
__textFilterField: null,
- __logModel: null,
+ __loggerModel: null,
__logView: null,
__messengerColors: null,
+ _createChildControlImpl: function(id) {
+ let control;
+ switch (id) {
+ case "toolbar":
+ control = new qx.ui.toolbar.ToolBar();
+ this._add(control);
+ break;
+ case "pin-node": {
+ const toolbar = this.getChildControl("toolbar");
+ control = new qx.ui.form.ToggleButton().set({
+ icon: "@FontAwesome5Solid/thumbtack/14",
+ toolTipText: this.tr("Show logs only from current node"),
+ appearance: "toolbar-button"
+ });
+ toolbar.add(control);
+ break;
+ }
+ case "filter-text": {
+ const toolbar = this.getChildControl("toolbar");
+ control = new qx.ui.form.TextField().set({
+ appearance: "toolbar-textfield",
+ liveUpdate: true,
+ placeholder: this.tr("Filter")
+ });
+ osparc.utils.Utils.setIdToWidget(control, "logsFilterField");
+ toolbar.add(control, {
+ flex: 1
+ });
+ break;
+ }
+ case "log-level": {
+ const toolbar = this.getChildControl("toolbar");
+ control = new qx.ui.form.SelectBox().set({
+ appearance: "toolbar-selectbox",
+ maxWidth: 80
+ });
+ let logLevelSet = false;
+ for (let i=0; i {
- // this.currectNodeClicked(currentNodeButton.getValue());
+ const pinNode = this.getChildControl("pin-node");
+ pinNode.addListener("changeValue", e => {
this.currectNodeClicked(e.getData());
}, this);
- toolbar.add(currentNodeButton);
- toolbar.add(new qx.ui.toolbar.Separator());
- const textFilterField = this.__textFilterField = new qx.ui.form.TextField().set({
- appearance: "toolbar-textfield",
- liveUpdate: true,
- placeholder: this.tr("Filter")
- });
- osparc.utils.Utils.setIdToWidget(textFilterField, "logsFilterField");
- toolbar.add(textFilterField, {
- flex: 1
- });
+ const textFilterField = this.__textFilterField = this.getChildControl("filter-text");
+ textFilterField.addListener("changeValue", this.__applyFilters, this);
- const logLevelSelectBox = new qx.ui.form.SelectBox().set({
- appearance: "toolbar-selectbox",
- maxWidth: 80
- });
- let logLevelSet = false;
- for (let i=0; i {
this.setLogLevel(e.getData().logLevel);
}, this);
toolbar.add(logLevelSelectBox);
- const copyToClipboardButton = new qx.ui.form.Button().set({
- icon: "@FontAwesome5Solid/copy/14",
- toolTipText: this.tr("Copy logs to clipboard"),
- appearance: "toolbar-button"
- });
- osparc.utils.Utils.setIdToWidget(copyToClipboardButton, "copyLogsToClipboardButton");
+ const copyToClipboardButton = this.getChildControl("copy-to-clipboard");
copyToClipboardButton.addListener("execute", e => {
this.__copyLogsToClipboard();
}, this);
@@ -200,7 +218,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
},
__createTableLayout: function() {
- const tableModel = this.__logModel = new osparc.component.widget.logger.RemoteTableModel();
+ const loggerModel = this.__loggerModel = new osparc.component.widget.logger.LoggerTable();
const custom = {
tableColumnModel : function(obj) {
@@ -209,7 +227,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
};
// table
- const table = this.__logView = new qx.ui.table.Table(tableModel, custom).set({
+ const table = this.__logView = new qx.ui.table.Table(loggerModel, custom).set({
selectable: true,
statusBarVisible: false,
showCellFocusIndicator: false
@@ -230,7 +248,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
},
__currentNodeIdChanged: function() {
- this.__currentNodeButton.setValue(false);
+ this.getChildControl("pin-node").setValue(false);
},
currectNodeClicked: function(checked) {
@@ -254,7 +272,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
__copyLogsToClipboard: function() {
let logs = "";
- this.__logModel.getRows().forEach(row => {
+ this.__loggerModel.getRows().forEach(row => {
logs += `(${row.nodeId}) ${row.label}: ${row.msg} \n`;
});
osparc.utils.Utils.copyTextToClipboard(logs);
@@ -293,7 +311,7 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
label = node.getLabel();
node.addListener("changeLabel", e => {
const newLabel = e.getData();
- this.__logModel.nodeLabelChanged(nodeId, newLabel);
+ this.__loggerModel.nodeLabelChanged(nodeId, newLabel);
this.__updateTable();
}, this);
} else {
@@ -314,14 +332,14 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
};
msgLogs.push(msgLog);
}
- this.__logModel.addRows(msgLogs);
+ this.__loggerModel.addRows(msgLogs);
this.__updateTable();
},
__updateTable: function() {
- this.__logModel.reloadData();
- const nFilteredRows = this.__logModel.getFilteredRowCount();
+ this.__loggerModel.reloadData();
+ const nFilteredRows = this.__loggerModel.getFilteredRowCount();
this.__logView.scrollCellVisible(0, nFilteredRows);
},
@@ -337,19 +355,13 @@ qx.Class.define("osparc.component.widget.logger.LoggerView", {
},
__applyFilters: function() {
- if (this.__logModel === null) {
+ if (this.__loggerModel === null) {
return;
}
- this.__logModel.setFilterString(this.__textFilterField.getValue());
- this.__logModel.setFilterLogLevel(this.getLogLevel());
- this.__logModel.reloadData();
- },
-
- __createInitMsg: function() {
- const nodeId = null;
- const msg = "Logger initialized";
- this.debug(nodeId, msg);
+ this.__loggerModel.setFilterString(this.__textFilterField.getValue());
+ this.__loggerModel.setFilterLogLevel(this.getLogLevel());
+ this.__loggerModel.reloadData();
}
}
});
diff --git a/services/web/client/source/class/osparc/component/workbench/EdgeUI.js b/services/web/client/source/class/osparc/component/workbench/EdgeUI.js
index b79b515a946..2b1dad1a9be 100644
--- a/services/web/client/source/class/osparc/component/workbench/EdgeUI.js
+++ b/services/web/client/source/class/osparc/component/workbench/EdgeUI.js
@@ -44,6 +44,11 @@ qx.Class.define("osparc.component.workbench.EdgeUI", {
this.setEdge(edge);
this.setRepresentation(representation);
+ edge.getInputNode().getStatus().addListener("changeModified", () => {
+ this.__updateCurveColor();
+ });
+ this.__updateCurveColor();
+
this.subscribeToFilterGroup("workbench");
},
@@ -59,6 +64,28 @@ qx.Class.define("osparc.component.workbench.EdgeUI", {
},
members: {
+ __updateCurveColor: function() {
+ const modified = this.getEdge().getInputNode().getStatus()
+ .getModified();
+ let newColor = null;
+ if (modified === null) {
+ newColor = qx.theme.manager.Color.getInstance().resolve("workbench-edge-comp-active");
+ } else {
+ newColor = osparc.utils.StatusUI.getColor(modified ? "failed" : "ready");
+ }
+ const newColorHex = qx.theme.manager.Color.getInstance().resolve(newColor);
+ osparc.component.workbench.SvgWidget.updateCurveColor(this.getRepresentation(), newColorHex);
+ },
+
+ setSelected: function(selected) {
+ if (selected) {
+ const selectedColor = qx.theme.manager.Color.getInstance().resolve("workbench-edge-selected");
+ osparc.component.workbench.SvgWidget.updateCurveColor(this.getRepresentation(), selectedColor);
+ } else {
+ this.__updateCurveColor();
+ }
+ },
+
getEdgeId: function() {
return this.getEdge().getEdgeId();
},
diff --git a/services/web/client/source/class/osparc/component/workbench/NodeUI.js b/services/web/client/source/class/osparc/component/workbench/NodeUI.js
index 71307adfaa7..69323220986 100644
--- a/services/web/client/source/class/osparc/component/workbench/NodeUI.js
+++ b/services/web/client/source/class/osparc/component/workbench/NodeUI.js
@@ -192,6 +192,12 @@ qx.Class.define("osparc.component.workbench.NodeUI", {
if (node.isComputational() || node.isFilePicker()) {
node.getStatus().bind("progress", this.__progressBar, "value");
}
+ /*
+ node.getStatus().bind("running", this, "decorator", {
+ // Paint borders
+ converter: state => osparc.utils.StatusUI.getBorderDecorator(state)
+ });
+ */
},
getInputPort: function() {
@@ -212,6 +218,25 @@ qx.Class.define("osparc.component.workbench.NodeUI", {
isInput: isInput,
ui: portLabel
};
+ if (isInput) {
+ this.getNode().getStatus().bind("dependencies", portLabel, "textColor", {
+ converter: dependencies => {
+ if (dependencies !== null) {
+ return osparc.utils.StatusUI.getColor(dependencies.length ? "failed" : "ready");
+ }
+ return osparc.utils.StatusUI.getColor();
+ }
+ });
+ } else {
+ this.getNode().getStatus().bind("modified", portLabel, "textColor", {
+ converter: modified => {
+ if (modified === null) {
+ return osparc.utils.StatusUI.getColor();
+ }
+ return osparc.utils.StatusUI.getColor(modified ? "failed" : "ready");
+ }
+ });
+ }
label.ui.isInput = isInput;
this.__addDragDropMechanism(label.ui, isInput);
if (isInput) {
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 222a140d37b..bb4203ec021 100644
--- a/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js
+++ b/services/web/client/source/class/osparc/component/workbench/WorkbenchUI.js
@@ -969,17 +969,15 @@ qx.Class.define("osparc.component.workbench.WorkbenchUI", {
const oldId = this.__selectedItemId;
if (oldId) {
if (this.__isSelectedItemAnEdge()) {
- const unselectedEdge = this.__getEdgeUI(oldId);
- const unselectedColor = qx.theme.manager.Color.getInstance().getTheme().colors["workbench-edge-comp-active"];
- osparc.component.workbench.SvgWidget.updateCurveColor(unselectedEdge.getRepresentation(), unselectedColor);
+ const edge = this.__getEdgeUI(oldId);
+ edge.setSelected(false);
}
}
this.__selectedItemId = newID;
if (this.__isSelectedItemAnEdge()) {
- const selectedEdge = this.__getEdgeUI(newID);
- const selectedColor = qx.theme.manager.Color.getInstance().getTheme().colors["workbench-edge-selected"];
- osparc.component.workbench.SvgWidget.updateCurveColor(selectedEdge.getRepresentation(), selectedColor);
+ const edge = this.__getEdgeUI(newID);
+ edge.setSelected(true);
} else if (newID) {
this.fireDataEvent("changeSelectedNode", newID);
}
diff --git a/services/web/client/source/class/osparc/dashboard/StudyBrowser.js b/services/web/client/source/class/osparc/dashboard/StudyBrowser.js
index 04629ce5a81..09ee7a3620d 100644
--- a/services/web/client/source/class/osparc/dashboard/StudyBrowser.js
+++ b/services/web/client/source/class/osparc/dashboard/StudyBrowser.js
@@ -840,7 +840,10 @@ qx.Class.define("osparc.dashboard.StudyBrowser", {
__createConfirmWindow: function(isMulti) {
const msg = isMulti ? this.tr("Are you sure you want to delete the studies?") : this.tr("Are you sure you want to delete the study?");
- return new osparc.ui.window.Confirmation(msg);
+ const confirmationWin = new osparc.ui.window.Confirmation(msg);
+ const confirmButton = confirmationWin.getChildControl("confirm-button");
+ osparc.utils.Utils.setIdToWidget(confirmButton, "confirmDeleteStudyBtn");
+ return confirmationWin;
}
}
});
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 61d2ef5df59..e8b6b730099 100644
--- a/services/web/client/source/class/osparc/data/model/Node.js
+++ b/services/web/client/source/class/osparc/data/model/Node.js
@@ -141,6 +141,12 @@ qx.Class.define("osparc.data.model.Node", {
event: "changeOutputs"
},
+ status: {
+ check: "osparc.data.model.NodeStatus",
+ nullable: false
+ },
+
+ // GUI elements //
propsForm: {
check: "osparc.component.form.renderer.PropForm",
init: null,
@@ -171,10 +177,12 @@ qx.Class.define("osparc.data.model.Node", {
nullable: true
},
- status: {
- check: "osparc.data.model.NodeStatus",
- nullable: false
+ logger: {
+ check: "osparc.component.widget.logger.LoggerView",
+ init: null,
+ nullable: true
}
+ // GUI elements //
},
events: {
@@ -333,25 +341,11 @@ qx.Class.define("osparc.data.model.Node", {
if (nodeData.label) {
this.setLabel(nodeData.label);
}
-
this.populateInputOutputData(nodeData);
-
- if (nodeData.state) {
- if (nodeData.state.currentStatus) {
- this.getStatus().setRunningStatus(nodeData.state.currentStatus);
- }
- if (nodeData.state.modified) {
- this.getStatus().setModifiedStatus(nodeData.state.modified);
- }
- if (nodeData.state.dependencies) {
- this.getStatus().setDependenciesStatus(nodeData.state.dependencies);
- }
- }
-
if ("progress" in nodeData) {
this.getStatus().setProgress(nodeData.progress);
}
-
+ this.populateStates(nodeData);
if (nodeData.thumbnail) {
this.setThumbnail(nodeData.thumbnail);
}
@@ -364,8 +358,8 @@ qx.Class.define("osparc.data.model.Node", {
this.__outputWidget.populatePortsData();
}
+ this.__initLogger();
if (this.isDynamic()) {
- this.__initLoadingIPage();
this.__initIFrame();
}
},
@@ -384,6 +378,24 @@ qx.Class.define("osparc.data.model.Node", {
this.addOutputNodes(nodeData.outputNodes);
},
+ populateStates: function(nodeData) {
+ if ("state" in nodeData) {
+ if ("dependencies" in nodeData.state) {
+ this.getStatus().setDependencies(nodeData.state.dependencies);
+ }
+ if ("currentStatus" in nodeData.state && this.isComputational()) {
+ this.getStatus().setRunning(nodeData.state.currentStatus);
+ }
+ if ("modified" in nodeData.state) {
+ if (this.getStatus().getHasOutputs()) {
+ this.getStatus().setModified(nodeData.state.modified || this.getStatus().hasDependencies());
+ } else {
+ this.getStatus().setModified(null);
+ }
+ }
+ }
+ },
+
giveUniqueName: function() {
const label = this.getLabel();
this.__giveUniqueName(label, 2);
@@ -428,7 +440,7 @@ qx.Class.define("osparc.data.model.Node", {
msg: errorMsg
};
this.fireDataEvent("showInLogger", errorMsgData);
- this.getStatus().setInteractiveStatus("failed");
+ this.getStatus().setInteractive("failed");
osparc.component.message.FlashMessenger.getInstance().logAs(this.tr("There was an error while starting the node."), "ERROR");
});
},
@@ -641,6 +653,8 @@ qx.Class.define("osparc.data.model.Node", {
this.getOutputs()[outputKey]["value"] = "";
}
}
+ this.getStatus().setHasOutputs(true);
+
this.fireDataEvent("changeOutputs", this.getOutputs());
}
},
@@ -778,8 +792,12 @@ qx.Class.define("osparc.data.model.Node", {
return true;
},
+ __initLogger: function() {
+ this.setLogger(new osparc.component.widget.logger.LoggerView());
+ },
+
__getLoadingPageHeader: function() {
- const status = this.getStatus().getInteractiveStatus();
+ const status = this.getStatus().getInteractive();
const label = this.getLabel();
if (status) {
const sta = status.charAt(0).toUpperCase() + status.slice(1);
@@ -794,13 +812,15 @@ qx.Class.define("osparc.data.model.Node", {
this.addListener("changeLabel", e => {
loadingPage.setHeader(this.__getLoadingPageHeader());
}, this);
- this.getStatus().addListener("changeInteractiveStatus", e => {
+ this.getStatus().addListener("changeInteractive", e => {
loadingPage.setHeader(this.__getLoadingPageHeader());
}, this);
this.setLoadingPage(loadingPage);
},
__initIFrame: function() {
+ this.__initLoadingIPage();
+
const iframe = new osparc.component.widget.PersistentIframe();
osparc.utils.Utils.setIdToWidget(iframe, "PersistentIframe");
iframe.addListener("restart", () => {
@@ -933,7 +953,7 @@ qx.Class.define("osparc.data.model.Node", {
const status = this.getStatus();
status.setProgress(0);
- status.setInteractiveStatus("starting");
+ status.setInteractive("starting");
this.__nodeState();
}
@@ -943,20 +963,20 @@ qx.Class.define("osparc.data.model.Node", {
const status = this.getStatus();
switch (serviceState) {
case "idle": {
- status.setInteractiveStatus("idle");
+ status.setInteractive("idle");
const interval = 1000;
qx.event.Timer.once(() => this.__nodeState(), this, interval);
break;
}
case "starting":
case "pulling": {
- status.setInteractiveStatus(serviceState);
+ status.setInteractive(serviceState);
const interval = 5000;
qx.event.Timer.once(() => this.__nodeState(), this, interval);
break;
}
case "pending": {
- status.setInteractiveStatus("pending");
+ status.setInteractive("pending");
const interval = 10000;
qx.event.Timer.once(() => this.__nodeState(), this, interval);
break;
@@ -978,7 +998,7 @@ qx.Class.define("osparc.data.model.Node", {
case "complete":
break;
case "failed": {
- status.setInteractiveStatus("failed");
+ status.setInteractive("failed");
const msg = "Service failed: " + data["service_message"];
const msgData = {
nodeId: this.getNodeId(),
@@ -1019,7 +1039,7 @@ qx.Class.define("osparc.data.model.Node", {
msg: errorMsg
};
this.fireDataEvent("showInLogger", errorMsgData);
- this.getStatus().setInteractiveStatus("failed");
+ this.getStatus().setInteractive("failed");
osparc.component.message.FlashMessenger.getInstance().logAs(this.tr("There was an error while starting the node."), "ERROR");
});
},
@@ -1049,7 +1069,7 @@ qx.Class.define("osparc.data.model.Node", {
}, this);
pingRequest.addListenerOnce("fail", e => {
const error = e.getTarget().getResponse();
- this.getStatus().setInteractiveStatus("connecting");
+ this.getStatus().setInteractive("connecting");
console.log("service not ready yet, waiting... " + error);
// Check if node is still there
const study = osparc.store.Store.getInstance().getCurrentStudy();
@@ -1063,7 +1083,7 @@ qx.Class.define("osparc.data.model.Node", {
},
__serviceReadyIn: function(srvUrl) {
this.setServiceUrl(srvUrl);
- this.getStatus().setInteractiveStatus("ready");
+ this.getStatus().setInteractive("ready");
const msg = "Service ready on " + srvUrl;
const msgData = {
nodeId: this.getNodeId(),
diff --git a/services/web/client/source/class/osparc/data/model/NodeStatus.js b/services/web/client/source/class/osparc/data/model/NodeStatus.js
index f88cf97573e..8beb877109d 100644
--- a/services/web/client/source/class/osparc/data/model/NodeStatus.js
+++ b/services/web/client/source/class/osparc/data/model/NodeStatus.js
@@ -34,28 +34,62 @@ qx.Class.define("osparc.data.model.NodeStatus", {
event: "changeProgress"
},
- runningStatus: {
+ running: {
check: ["UNKNOWN", "NOT_STARTED", "PUBLISHED", "PENDING", "STARTED", "RETRY", "SUCCESS", "FAILED", "ABORTED"],
nullable: true,
- event: "changeRunningStatus"
+ init: null,
+ event: "changeRunning"
},
- interactiveStatus: {
+ interactive: {
check: ["idle", "starting", "pulling", "pending", "connecting", "ready", "failed"],
nullable: true,
- event: "changeInteractiveStatus"
+ init: null,
+ event: "changeInteractive"
},
- modifiedStatus: {
- check: "Boolean",
+ dependencies: {
+ check: "Array",
nullable: true,
- event: "changeModifiedStatus"
+ init: null,
+ event: "changeDependencies",
+ apply: "__applyDependencies"
},
- dependenciesStatus: {
- check: "Array",
+ modified: {
+ check: "Boolean",
nullable: true,
- event: "changeDependenciesStatus"
+ init: null,
+ event: "changeModified",
+ apply: "__applyModified"
+ },
+
+ hasOutputs: {
+ check: "Boolean",
+ init: false,
+ apply: "__applyModified"
+ }
+ },
+
+ members: {
+ hasDependencies: function() {
+ const dependencies = this.getDependencies();
+ if (dependencies && dependencies.length) {
+ return true;
+ }
+ return false;
+ },
+
+ __applyDependencies: function() {
+ this.__applyModified(this.hasDependencies());
+ },
+
+ __applyModified: function(modified) {
+ if (this.getHasOutputs()) {
+ this.setModified(modified || this.hasDependencies());
+ } else {
+ this.setModified(null);
+ }
}
}
});
diff --git a/services/web/client/source/class/osparc/data/model/Study.js b/services/web/client/source/class/osparc/data/model/Study.js
index 23705509cb0..668d2dd1748 100644
--- a/services/web/client/source/class/osparc/data/model/Study.js
+++ b/services/web/client/source/class/osparc/data/model/Study.js
@@ -154,7 +154,8 @@ qx.Class.define("osparc.data.model.Study", {
state: {
check: "Object",
- nullable: true
+ nullable: true,
+ event: "changeState"
},
quality: {
@@ -189,20 +190,6 @@ qx.Class.define("osparc.data.model.Study", {
return myNewStudyObject;
},
- updateStudy: function(params) {
- return new Promise(resolve => {
- osparc.data.Resources.fetch("studies", "put", {
- url: {
- projectId: params.uuid
- },
- data: params
- }).then(data => {
- qx.event.message.Bus.getInstance().dispatchByName("updateStudy", data);
- resolve(data);
- });
- });
- },
-
getProperties: function() {
return Object.keys(qx.util.PropertyUtil.getProperties(osparc.data.model.Study));
},
@@ -313,16 +300,22 @@ qx.Class.define("osparc.data.model.Study", {
return jsonObject;
},
- updateStudy: function(params) {
+ updateStudy: function(params, run = false) {
return new Promise(resolve => {
- this.self().updateStudy({
- ...this.serialize(),
- ...params
- })
- .then(data => {
- this.__updateModel(data);
- resolve(data);
- });
+ osparc.data.Resources.fetch("studies", "put", {
+ url: {
+ projectId: this.getUuid(),
+ run
+ },
+ data: {
+ ...this.serialize(),
+ ...params
+ }
+ }).then(data => {
+ this.__updateModel(data);
+ qx.event.message.Bus.getInstance().dispatchByName("updateStudy", data);
+ resolve(data);
+ });
});
},
@@ -338,6 +331,14 @@ qx.Class.define("osparc.data.model.Study", {
ui: this.getUi(),
sweeper: this.getSweeper()
});
+
+ const nodes = this.getWorkbench().getNodes(true);
+ Object.values(nodes).forEach(node => {
+ const nodeId = node.getNodeId();
+ if (nodeId in data.workbench) {
+ node.populateStates(data.workbench[nodeId]);
+ }
+ });
}
}
});
diff --git a/services/web/client/source/class/osparc/data/model/Workbench.js b/services/web/client/source/class/osparc/data/model/Workbench.js
index 72ad28f4506..1de5580ee52 100644
--- a/services/web/client/source/class/osparc/data/model/Workbench.js
+++ b/services/web/client/source/class/osparc/data/model/Workbench.js
@@ -91,7 +91,7 @@ qx.Class.define("osparc.data.model.Workbench", {
getNodes: function(recursive = false) {
let nodes = Object.assign({}, this.__rootNodes);
- if (recursive) {
+ if (recursive && this.__rootNodes) {
let topLevelNodes = Object.values(this.__rootNodes);
for (const topLevelNode of topLevelNodes) {
let innerNodes = topLevelNode.getInnerNodes(true);
@@ -340,20 +340,20 @@ qx.Class.define("osparc.data.model.Workbench", {
},
__deserializeNodes: function(workbenchData, workbenchUIData = {}) {
- let keys = Object.keys(workbenchData);
+ const nodeIds = Object.keys(workbenchData);
// Create first all the nodes
- for (let i=0; i 1) {
- if (keys[nKeys-1] === keys[nKeys-2]) {
+ if (nodeIds[nKeys-1] === nodeIds[nKeys-2]) {
console.log(nodeId, "will never be created, parent missing", nodeData.parent);
return;
}
@@ -371,21 +371,23 @@ qx.Class.define("osparc.data.model.Workbench", {
}
// Then populate them (this will avoid issues of connecting nodes that might not be created yet)
- for (let i=0; i {
+ this.getNode(nodeId).giveUniqueName();
+ });
+ },
+
+ __populateNodesData: function(workbenchData, workbenchUIData) {
+ Object.entries(workbenchData).forEach(([nodeId, nodeData]) => {
this.getNode(nodeId).populateNodeData(nodeData);
if ("position" in nodeData) {
this.getNode(nodeId).populateNodeUIData(nodeData);
}
- if ("workbench" in workbenchUIData && nodeId in workbenchUIData.workbench) {
+ if (workbenchUIData && "workbench" in workbenchUIData && nodeId in workbenchUIData.workbench) {
this.getNode(nodeId).populateNodeUIData(workbenchUIData.workbench[nodeId]);
}
- }
- for (let i=0; i {
+ this.fireDataEvent("nodeSelected", e.getData());
+ }, this);
+ control = new qx.ui.container.Scroll();
+ control.add(breadcrumbNavigation);
+ this._add(control, {
+ flex: 1
+ });
+ break;
+ }
case "prev-next-btns": {
control = new osparc.navigation.PrevNextButtons();
control.addListener("nodeSelected", e => {
diff --git a/services/web/client/source/class/osparc/desktop/SlideShowView.js b/services/web/client/source/class/osparc/desktop/SlideShowView.js
index 8b53c0eeb17..a64a1fc7994 100644
--- a/services/web/client/source/class/osparc/desktop/SlideShowView.js
+++ b/services/web/client/source/class/osparc/desktop/SlideShowView.js
@@ -31,6 +31,10 @@ qx.Class.define("osparc.desktop.SlideShowView", {
this._add(slideShowToolbar);
},
+ events: {
+ "startPartialPipeline": "qx.event.type.Data"
+ },
+
properties: {
study: {
check: "osparc.data.model.Study",
@@ -52,12 +56,36 @@ qx.Class.define("osparc.desktop.SlideShowView", {
return [this.__currentNodeId];
},
- nodeSelected: function(nodeId) {
- this.__currentNodeId = nodeId;
- this.getStudy().getUi().setCurrentNodeId(nodeId);
+ __isNodeReady: function(node, oldCurrentNodeId) {
+ const dependencies = node.getStatus().getDependencies();
+ if (dependencies && dependencies.length) {
+ const msg = this.tr("Do you want to run the required steps?");
+ const win = new osparc.ui.window.Confirmation(msg);
+ win.center();
+ win.open();
+ win.addListener("close", () => {
+ if (win.getConfirmed()) {
+ this.fireDataEvent("startPartialPipeline", dependencies);
+ }
+ // bring the user back to the old node or to the first dependency
+ if (oldCurrentNodeId === this.__currentNodeId) {
+ this.nodeSelected(dependencies[0]);
+ } else {
+ this.nodeSelected(oldCurrentNodeId);
+ }
+ }, this);
+ return false;
+ }
+ return true;
+ },
+ nodeSelected: function(nodeId) {
const node = this.getStudy().getWorkbench().getNode(nodeId);
if (node) {
+ const oldCurrentNodeId = this.__currentNodeId;
+ this.__currentNodeId = nodeId;
+ this.getStudy().getUi().setCurrentNodeId(nodeId);
+
let view;
if (node.isContainer()) {
view = new osparc.component.node.GroupNodeView();
@@ -79,6 +107,10 @@ qx.Class.define("osparc.desktop.SlideShowView", {
});
this.__lastView = view;
}
+ // check if upstream has to be run
+ if (!this.__isNodeReady(node, oldCurrentNodeId)) {
+ return;
+ }
}
this.getStudy().getUi().setCurrentNodeId(nodeId);
diff --git a/services/web/client/source/class/osparc/desktop/StartStopButtons.js b/services/web/client/source/class/osparc/desktop/StartStopButtons.js
index 78b5f172fc3..ac1da0d49dc 100644
--- a/services/web/client/source/class/osparc/desktop/StartStopButtons.js
+++ b/services/web/client/source/class/osparc/desktop/StartStopButtons.js
@@ -41,6 +41,15 @@ qx.Class.define("osparc.desktop.StartStopButtons", {
this.__initDefault();
},
+ properties: {
+ study: {
+ check: "osparc.data.model.Study",
+ apply: "__applyStudy",
+ init: null,
+ nullable: false
+ }
+ },
+
events: {
"startPipeline": "qx.event.type.Event",
"startPartialPipeline": "qx.event.type.Event",
@@ -83,36 +92,6 @@ qx.Class.define("osparc.desktop.StartStopButtons", {
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() {
@@ -153,6 +132,44 @@ qx.Class.define("osparc.desktop.StartStopButtons", {
this.fireEvent("stopPipeline");
}, this);
return stopButton;
+ },
+
+ __applyStudy: function(study) {
+ this.__checkButtonsVisible();
+
+ study.addListener("changeState", () => {
+ this.__updateRunButtonsStatus();
+ }, this);
+ },
+
+ __checkButtonsVisible: function() {
+ this.setVisibility(this.getStudy().isReadOnly() ? "excluded" : "visible");
+ },
+
+ __updateRunButtonsStatus: function() {
+ const study = this.getStudy();
+ 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.value;
+ switch (pipelineState) {
+ 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;
+ }
+ }
+ }
}
}
});
diff --git a/services/web/client/source/class/osparc/desktop/StudyEditor.js b/services/web/client/source/class/osparc/desktop/StudyEditor.js
index 2dd1b64da67..1cc6ade2ce5 100644
--- a/services/web/client/source/class/osparc/desktop/StudyEditor.js
+++ b/services/web/client/source/class/osparc/desktop/StudyEditor.js
@@ -34,12 +34,22 @@ qx.Class.define("osparc.desktop.StudyEditor", {
const slideshowView = this.__slideshowView = new osparc.desktop.SlideShowView();
viewsStack.add(slideshowView);
+ slideshowView.addListener("startPartialPipeline", e => {
+ const partialPipeline = e.getData();
+ this.__startPipeline(partialPipeline);
+ }, this);
+
[
workbenchView.getStartStopButtons(),
slideshowView.getStartStopButtons()
].forEach(startStopButtons => {
- startStopButtons.addListener("startPipeline", this.__startPipeline, this);
- startStopButtons.addListener("startPartialPipeline", () => this.__startPipeline(false), this);
+ startStopButtons.addListener("startPipeline", () => {
+ this.__startPipeline([]);
+ }, this);
+ startStopButtons.addListener("startPartialPipeline", () => {
+ const partialPipeline = this.getPageContext() === "workbench" ? this.__workbenchView.getSelectedNodeIDs() : this.__slideshowView.getSelectedNodeIDs();
+ this.__startPipeline(partialPipeline);
+ }, this);
startStopButtons.addListener("stopPipeline", this.__stopPipeline, this);
});
@@ -156,7 +166,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
// ------------------ START/STOP PIPELINE ------------------
- __startPipeline: function(runAll = true) {
+ __startPipeline: function(partialPipeline = []) {
if (!osparc.data.Permissions.getInstance().canDo("study.start", true)) {
return;
}
@@ -167,64 +177,67 @@ qx.Class.define("osparc.desktop.StudyEditor", {
startStopButtonsSS.setRunning(true);
this.updateStudyDocument(true)
.then(() => {
- this.__doStartPipeline(runAll);
+ this.__doStartPipeline(partialPipeline);
})
.catch(() => {
- this.getLogger().error(null, "Run failed");
+ this.__getStudyLogger().error(null, "Run failed");
startStopButtonsWB.setRunning(false);
startStopButtonsSS.setRunning(false);
});
},
- __doStartPipeline: function(runAll) {
+ __doStartPipeline: function(partialPipeline) {
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);
- }
+ this.__requestStartPipeline(this.getStudy().getUuid(), partialPipeline);
}
},
- __requestStartPipeline: function(studyId, selectedNodeIDs = []) {
+ __requestStartPipeline: function(studyId, partialPipeline = [], forceRestart = false) {
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");
+ this.__getStudyLogger().error(null, "Error submitting pipeline");
startStopButtonsWB.setRunning(false);
startStopButtonsSS.setRunning(false);
}, this);
req.addListener("fail", e => {
if (e.getTarget().getStatus() == "403") {
- this.getLogger().error(null, "Pipeline is already running");
+ this.__getStudyLogger().error(null, "Pipeline is already running");
} else if (e.getTarget().getStatus() == "422") {
- this.getLogger().info(null, "The pipeline is up-to-date");
+ this.__getStudyLogger().info(null, "The pipeline is up-to-date");
+ const msg = this.tr("The pipeline is up-to-date. Do you want to re-run it?");
+ const win = new osparc.ui.window.Confirmation(msg);
+ win.center();
+ win.open();
+ win.addListener("close", () => {
+ if (win.getConfirmed()) {
+ this.__requestStartPipeline(studyId, partialPipeline, true);
+ }
+ }, this);
} else {
- this.getLogger().error(null, "Failed submitting pipeline");
+ this.__getStudyLogger().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");
+
+ req.setRequestData({
+ "subgraph": partialPipeline,
+ "force_restart": forceRestart
+ });
+ req.send();
+ if (partialPipeline.length) {
+ this.__getStudyLogger().info(null, "Starting partial pipeline");
} else {
- req.send();
- this.getLogger().info(null, "Starting pipeline");
+ this.__getStudyLogger().info(null, "Starting pipeline");
}
return true;
@@ -233,12 +246,12 @@ qx.Class.define("osparc.desktop.StudyEditor", {
__onPipelinesubmitted: function(e) {
const resp = e.getTarget().getResponse();
const pipelineId = resp.data["pipeline_id"];
- this.getLogger().debug(null, "Pipeline ID " + pipelineId);
+ this.__getStudyLogger().debug(null, "Pipeline ID " + pipelineId);
const notGood = [null, undefined, -1];
if (notGood.includes(pipelineId)) {
- this.getLogger().error(null, "Submission failed");
+ this.__getStudyLogger().error(null, "Submission failed");
} else {
- this.getLogger().info(null, "Pipeline started");
+ this.__getStudyLogger().info(null, "Pipeline started");
/* If no projectStateUpdated comes in 60 seconds, client must
check state of pipeline and update button accordingly. */
const timer = setTimeout(() => {
@@ -277,17 +290,17 @@ qx.Class.define("osparc.desktop.StudyEditor", {
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.__getStudyLogger().debug(null, "Pipeline aborting");
}, this);
req.addListener("error", e => {
- this.getLogger().error(null, "Error stopping pipeline");
+ this.__getStudyLogger().error(null, "Error stopping pipeline");
}, this);
req.addListener("fail", e => {
- this.getLogger().error(null, "Failed stopping pipeline");
+ this.__getStudyLogger().error(null, "Failed stopping pipeline");
}, this);
req.send();
- this.getLogger().info(null, "Stopping pipeline");
+ this.__getStudyLogger().info(null, "Stopping pipeline");
return true;
},
// ------------------ START/STOP PIPELINE ------------------
@@ -295,12 +308,12 @@ qx.Class.define("osparc.desktop.StudyEditor", {
__updatePipelineAndRetrieve: function(node, portKey = null) {
this.updateStudyDocument(false)
.then(() => {
- this.getLogger().debug(null, "Retrieveing inputs");
+ this.__getStudyLogger().debug(null, "Retrieveing inputs");
if (node) {
node.retrieveInputs(portKey);
}
});
- this.getLogger().debug(null, "Updating pipeline");
+ this.__getStudyLogger().debug(null, "Updating pipeline");
},
// overridden
@@ -321,7 +334,7 @@ qx.Class.define("osparc.desktop.StudyEditor", {
this.__slideshowView.nodeSelected(nodeId);
},
- getLogger: function() {
+ __getStudyLogger: function() {
return this.__workbenchView.getLogger();
},
@@ -340,19 +353,24 @@ qx.Class.define("osparc.desktop.StudyEditor", {
__startAutoSaveTimer: function() {
let diffPatcher = osparc.wrapper.JsonDiffPatch.getInstance();
- // Save every 5 seconds
- const interval = 5000;
+ // Save every 3 seconds
+ const interval = 3000;
let timer = this.__autoSaveTimer = new qx.event.Timer(interval);
timer.addListener("interval", () => {
const newObj = this.getStudy().serialize();
const delta = diffPatcher.diff(this.__lastSavedStudy, newObj);
if (delta) {
let deltaKeys = Object.keys(delta);
- // lastChangeDate should not be taken into account as data change
- const index = deltaKeys.indexOf("lastChangeDate");
- if (index > -1) {
- deltaKeys.splice(index, 1);
- }
+ // lastChangeDate and creationDate should not be taken into account as data change
+ [
+ "creationDate",
+ "lastChangeDate"
+ ].forEach(prop => {
+ const index = deltaKeys.indexOf(prop);
+ if (index > -1) {
+ deltaKeys.splice(index, 1);
+ }
+ });
if (deltaKeys.length > 0) {
this.updateStudyDocument(false);
}
@@ -376,24 +394,15 @@ qx.Class.define("osparc.desktop.StudyEditor", {
});
}
- this.getStudy().setLastChangeDate(new Date());
const newObj = this.getStudy().serialize();
- const prjUuid = this.getStudy().getUuid();
-
- const params = {
- url: {
- projectId: prjUuid,
- run
- },
- data: newObj
- };
- return osparc.data.Resources.fetch("studies", "put", params)
+ return this.getStudy().updateStudy(newObj, run)
.then(data => {
this.__lastSavedStudy = osparc.wrapper.JsonDiffPatch.getInstance().clone(newObj);
- }).catch(error => {
+ })
+ .catch(error => {
console.error(error);
osparc.component.message.FlashMessenger.getInstance().logAs(this.tr("Error saving the study"), "ERROR");
- this.getLogger().error(null, "Error updating pipeline");
+ this.__getStudyLogger().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/Toolbar.js b/services/web/client/source/class/osparc/desktop/Toolbar.js
index f0a6cd70047..a17db525221 100644
--- a/services/web/client/source/class/osparc/desktop/Toolbar.js
+++ b/services/web/client/source/class/osparc/desktop/Toolbar.js
@@ -59,29 +59,17 @@ qx.Class.define("osparc.desktop.Toolbar", {
_createChildControlImpl: function(id) {
let control;
switch (id) {
- case "breadcrumb-navigation": {
- const breadcrumbNavigation = this._navNodes = new osparc.navigation.BreadcrumbNavigation();
- breadcrumbNavigation.addListener("nodeSelected", e => {
- this.fireDataEvent("nodeSelected", e.getData());
- }, this);
- control = new qx.ui.container.Scroll();
- 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);
+ [
+ "startPipeline",
+ "startPartialPipeline",
+ "stopPipeline"
+ ].forEach(signalName => {
+ control.addListener(signalName, () => {
+ this.fireEvent(signalName);
+ }, this);
+ });
this._add(control);
break;
}
@@ -94,7 +82,7 @@ qx.Class.define("osparc.desktop.Toolbar", {
study.getUi().addListener("changeCurrentNodeId", () => {
this._populateNodesNavigationLayout();
});
- this._startStopBtns.setVisibility(study.isReadOnly() ? "excluded" : "visible");
+ this._startStopBtns.setStudy(study);
this._populateNodesNavigationLayout();
}
diff --git a/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js b/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js
index 337b001ec79..1209c1913ba 100644
--- a/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js
+++ b/services/web/client/source/class/osparc/desktop/WorkbenchToolbar.js
@@ -32,6 +32,18 @@ qx.Class.define("osparc.desktop.WorkbenchToolbar", {
_createChildControlImpl: function(id) {
let control;
switch (id) {
+ case "breadcrumb-navigation": {
+ const breadcrumbNavigation = this._navNodes = new osparc.navigation.BreadcrumbsWorkbench();
+ breadcrumbNavigation.addListener("nodeSelected", e => {
+ this.fireDataEvent("nodeSelected", e.getData());
+ }, this);
+ control = new qx.ui.container.Scroll();
+ control.add(breadcrumbNavigation);
+ this._add(control, {
+ flex: 1
+ });
+ break;
+ }
case "sweeper-btn": {
control = new qx.ui.form.Button(this.tr("Sweeper"), "@FontAwesome5Solid/paw/14").set({
toolTipText: this.tr("Sweeper"),
diff --git a/services/web/client/source/class/osparc/desktop/WorkbenchView.js b/services/web/client/source/class/osparc/desktop/WorkbenchView.js
index ab5f2747682..f32b5f5ccf6 100644
--- a/services/web/client/source/class/osparc/desktop/WorkbenchView.js
+++ b/services/web/client/source/class/osparc/desktop/WorkbenchView.js
@@ -85,7 +85,10 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
},
getSelectedNodeIDs: function() {
- return this.__workbenchUI.getSelectedNodeIDs();
+ if (this.__mainPanel.getMainView() === this.__workbenchUI) {
+ return this.__workbenchUI.getSelectedNodeIDs();
+ }
+ return [this.__currentNodeId];
},
nodeSelected: function(nodeId) {
@@ -132,6 +135,16 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
return this.__loggerView;
},
+ __getNodeLogger: function(nodeId) {
+ const nodes = this.getStudy().getWorkbench().getNodes(true);
+ for (const node of Object.values(nodes)) {
+ if (nodeId === node.getNodeId()) {
+ return node.getLogger();
+ }
+ }
+ return null;
+ },
+
__editSlides: function() {
const uiData = this.getStudy().getUi();
const nodesSlidesTree = new osparc.component.widget.NodesSlidesTree(uiData.getSlideshow());
@@ -316,9 +329,9 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
flex: 1
});
- const loggerView = this.__loggerView = new osparc.component.widget.logger.LoggerView(study.getWorkbench());
+ const loggerView = this.__loggerView = new osparc.component.widget.logger.LoggerView();
const loggerPanel = new osparc.desktop.PanelView(this.tr("Logger"), loggerView);
- osparc.utils.Utils.setIdToWidget(loggerPanel.getTitleLabel(), "loggerTitleLabel");
+ osparc.utils.Utils.setIdToWidget(loggerPanel.getTitleLabel(), "studyLoggerTitleLabel");
this.__sidePanel.addOrReplaceAt(loggerPanel, 2, {
flex: 1
});
@@ -501,7 +514,13 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
// Filtering out logs from other studies
return;
}
- this.getLogger().infos(data["Node"], data["Messages"]);
+ const nodeId = data["Node"];
+ const messages = data["Messages"];
+ this.getLogger().infos(nodeId, messages);
+ const nodeLogger = this.__getNodeLogger(nodeId);
+ if (nodeLogger) {
+ nodeLogger.infos(nodeId, messages);
+ }
}, this);
}
socket.emit(slotName);
@@ -534,13 +553,11 @@ qx.Class.define("osparc.desktop.WorkbenchView", {
const node = workbench.getNode(nodeId);
if (node && nodeData) {
node.setOutputData(nodeData.outputs);
- if ("state" in nodeData && node.isComputational()) {
- node.getStatus().setRunningStatus(nodeData["state"]["currentStatus"]);
- }
if ("progress" in nodeData) {
const progress = Number.parseInt(nodeData["progress"]);
node.getStatus().setProgress(progress);
}
+ node.populateStates(nodeData);
} else if (osparc.data.Permissions.getInstance().isTester()) {
console.log("Ignored ws 'nodeUpdated' msg", d);
}
diff --git a/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js b/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js
index 299d6f808c6..e352c4b3952 100644
--- a/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js
+++ b/services/web/client/source/class/osparc/navigation/BreadcrumbNavigation.js
@@ -37,33 +37,21 @@ qx.Class.define("osparc.navigation.BreadcrumbNavigation", {
},
members: {
- populateButtons: function(nodesIds = [], shape = "slash") {
- const btns = [];
- if (shape === "slash") {
- for (let i=0; i (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;
- },
-
- __buttonsToBreadcrumb: function(btns, shape = "slash") {
+ _buttonsToBreadcrumb: function(btns, shape = "slash") {
this._removeAll();
for (let i=0; i `${pos+1}- ${val}`
+ });
+ node.getStatus().bind("dependencies", btn.getChildControl("label"), "textColor", {
+ converter: dependencies => {
+ let textColor = "material-button-text";
+ if (dependencies && dependencies.length) {
+ textColor = "material-button-text-disabled";
+ }
+ return textColor;
+ }
+ });
+ node.getStatus().bind("modified", btn, "label", {
+ converter: modified => {
+ const label = btn.getLabel();
+ const lastCharacter = label.slice(-1);
+ if (modified === true && lastCharacter !== "*") {
+ return label + "*"; // add star suffix
+ } else if ((modified === false || modified === null) && lastCharacter === "*") {
+ return label.slice(0, -1); // remove star suffix
+ }
+ return label;
+ }
+ });
+
+ const statusUI = new osparc.ui.basic.NodeStatusUI(node);
+ const statusLabel = statusUI.getChildControl("label");
+ const statusIcon = statusUI.getChildControl("icon");
+ // eslint-disable-next-line no-underscore-dangle
+ btn._add(statusIcon);
+
+ statusLabel.bind("value", btn, "toolTipText", {
+ converter: status => `${node.getLabel()} - ${status}`
+ });
+ }
+ return btn;
+ }
+ }
+});
diff --git a/services/web/client/source/class/osparc/navigation/BreadcrumbsWorkbench.js b/services/web/client/source/class/osparc/navigation/BreadcrumbsWorkbench.js
new file mode 100644
index 00000000000..918d6623c1a
--- /dev/null
+++ b/services/web/client/source/class/osparc/navigation/BreadcrumbsWorkbench.js
@@ -0,0 +1,55 @@
+/* ************************************************************************
+
+ 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.BreadcrumbsWorkbench", {
+ extend: osparc.navigation.BreadcrumbNavigation,
+
+ members: {
+ populateButtons: function(nodesIds = []) {
+ const btns = [];
+ for (let i=0; i {
if (state) {
this.show();
- if (state === "STARTED") {
- state = "Running";
- }
- return qx.lang.String.firstUp(state.toLowerCase());
+ const labelValue = osparc.utils.StatusUI.getLabelValue(state);
+ return qx.lang.String.firstUp(labelValue.toLowerCase());
}
this.exclude();
return null;
+ },
+ onUpdate: (source, target) => {
+ const state = source.getRunning();
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
}
});
- this.__node.getStatus().bind("runningStatus", this.__icon, "source", {
- converter: state => {
- switch (state) {
- case "SUCCESS":
- return "@FontAwesome5Solid/check/12";
- case "FAILED":
- case "ABORTED":
- return "@FontAwesome5Solid/exclamation-circle/12";
- case "PENDING":
- case "PUBLISHED":
- case "STARTED":
- case "RETRY":
- return "@FontAwesome5Solid/circle-notch/12";
- case "UNKNOWN":
- case "NOT_STARTED":
- default:
- return "";
- }
- },
+ this.__node.getStatus().bind("running", this.__icon, "source", {
+ converter: state => osparc.utils.StatusUI.getIconSource(state),
onUpdate: (source, target) => {
target.show();
- const state = source.getRunningStatus();
+ const state = source.getRunning();
switch (state) {
case "SUCCESS":
- this.__removeClass(this.__icon.getContentElement(), "rotate");
- target.setTextColor("ready-green");
- return;
case "FAILED":
case "ABORTED":
- this.__removeClass(this.__icon.getContentElement(), "rotate");
- target.setTextColor("failed-red");
+ this.self().removeClass(this.__icon.getContentElement(), "rotate");
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
return;
case "PENDING":
case "PUBLISHED":
case "STARTED":
case "RETRY":
- this.__addClass(this.__icon.getContentElement(), "rotate");
- target.resetTextColor();
+ this.self().addClass(this.__icon.getContentElement(), "rotate");
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
return;
case "UNKNOWN":
case "NOT_STARTED":
@@ -119,54 +103,39 @@ qx.Class.define("osparc.ui.basic.NodeStatusUI", {
},
__setupInteractive: function() {
- this.__node.getStatus().bind("interactiveStatus", this.__label, "value", {
- converter: status => {
- if (status === "ready") {
- return this.tr("Ready");
- } else if (status === "failed") {
- return this.tr("Error");
- } else if (status === "starting") {
- return this.tr("Starting...");
- } else if (status === "pending") {
- return this.tr("Pending...");
- } else if (status === "pulling") {
- return this.tr("Pulling...");
- } else if (status === "connecting") {
- return this.tr("Connecting...");
- }
- return status;
+ this.__node.getStatus().bind("interactive", this.__label, "value", {
+ converter: state => osparc.utils.StatusUI.getLabelValue(state),
+ onUpdate: (source, target) => {
+ const state = source.getInteractive();
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
}
});
- this.__node.getStatus().bind("interactiveStatus", this.__icon, "source", {
- converter: status => {
- if (status === "ready") {
- return "@FontAwesome5Solid/check/12";
- } else if (status === "failed") {
- return "@FontAwesome5Solid/exclamation-circle/12";
- } else if (status === "starting") {
- return "@FontAwesome5Solid/circle-notch/12";
- } else if (status === "pending") {
- return "@FontAwesome5Solid/circle-notch/12";
- } else if (status === "pulling") {
- return "@FontAwesome5Solid/circle-notch/12";
- } else if (status === "connecting") {
- return "@FontAwesome5Solid/circle-notch/12";
- }
- return "";
- },
+ this.__node.getStatus().bind("interactive", this.__icon, "source", {
+ converter: state => osparc.utils.StatusUI.getIconSource(state),
onUpdate: (source, target) => {
- if (source.getInteractiveStatus() == null) {
- this.__removeClass(this.__icon.getContentElement(), "rotate");
- } else if (source.getInteractiveStatus() === "ready") {
- this.__removeClass(this.__icon.getContentElement(), "rotate");
- target.setTextColor("ready-green");
- } else if (source.getInteractiveStatus() === "failed") {
- this.__removeClass(this.__icon.getContentElement(), "rotate");
- target.setTextColor("failed-red");
- } else {
- this.__addClass(this.__icon.getContentElement(), "rotate");
- target.resetTextColor();
+ const state = source.getInteractive();
+ switch (state) {
+ case "ready":
+ case "failed":
+ this.self().removeClass(this.__icon.getContentElement(), "rotate");
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
+ break;
+ case "idle":
+ this.self().removeClass(this.__icon.getContentElement(), "rotate");
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
+ break;
+ case "starting":
+ case "pulling":
+ case "pending":
+ case "connecting":
+ this.self().addClass(this.__icon.getContentElement(), "rotate");
+ target.setTextColor(osparc.utils.StatusUI.getColor(state));
+ break;
+ default:
+ this.self().removeClass(this.__icon.getContentElement(), "rotate");
+ target.resetTextColor();
+ break;
}
}
});
diff --git a/services/web/client/source/class/osparc/ui/window/Confirmation.js b/services/web/client/source/class/osparc/ui/window/Confirmation.js
index 714997f96a8..e433d9d10bf 100644
--- a/services/web/client/source/class/osparc/ui/window/Confirmation.js
+++ b/services/web/client/source/class/osparc/ui/window/Confirmation.js
@@ -16,18 +16,14 @@ qx.Class.define("osparc.ui.window.Confirmation", {
* @extends osparc.ui.window.Dialog
* @param {String} message Message that will be displayed to the user.
*/
- construct: function(message) {
+ construct: function(message, confirmBtnText = this.tr("Yes")) {
this.base(arguments, this.tr("Confirmation"), null, message);
this.addCancelButton();
- const btnYes = new qx.ui.toolbar.Button("Yes");
- osparc.utils.Utils.setIdToWidget(btnYes, "confirmDeleteStudyBtn");
- btnYes.addListener("execute", e => {
- this.setConfirmed(true);
- this.close(1);
- }, this);
- this.addButton(btnYes);
+ this._createChildControlImpl("confirm-button").set({
+ label: confirmBtnText
+ });
},
properties: {
@@ -35,5 +31,23 @@ qx.Class.define("osparc.ui.window.Confirmation", {
check: "Boolean",
init: false
}
+ },
+
+ members: {
+ _createChildControlImpl: function(id) {
+ let control;
+ switch (id) {
+ case "confirm-button": {
+ control = new qx.ui.toolbar.Button();
+ control.addListener("execute", e => {
+ this.setConfirmed(true);
+ this.close(1);
+ }, this);
+ this.addButton(control);
+ break;
+ }
+ }
+ return control || this.base(arguments, id);
+ }
}
});
diff --git a/services/web/client/source/class/osparc/utils/StatusUI.js b/services/web/client/source/class/osparc/utils/StatusUI.js
new file mode 100644
index 00000000000..a7d47e7f6ea
--- /dev/null
+++ b/services/web/client/source/class/osparc/utils/StatusUI.js
@@ -0,0 +1,152 @@
+/* ************************************************************************
+
+ 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)
+
+************************************************************************ */
+
+/**
+ * Collection of methods for dealing status decorators.
+ *
+ */
+
+qx.Class.define("osparc.utils.StatusUI", {
+ type: "static",
+
+ statics: {
+ getIconSource: function(state) {
+ switch (state) {
+ // computationals
+ case "SUCCESS":
+ return "@FontAwesome5Solid/check/12";
+ case "FAILED":
+ case "ABORTED":
+ return "@FontAwesome5Solid/exclamation-circle/12";
+ case "PENDING":
+ case "PUBLISHED":
+ case "STARTED":
+ case "RETRY":
+ return "@FontAwesome5Solid/circle-notch/12";
+ case "UNKNOWN":
+ case "NOT_STARTED":
+ return "";
+
+ // dynamics
+ case "ready":
+ return "@FontAwesome5Solid/check/12";
+ case "failed":
+ return "@FontAwesome5Solid/exclamation-circle/12";
+ case "starting":
+ case "pending":
+ case "pulling":
+ case "connecting":
+ return "@FontAwesome5Solid/circle-notch/12";
+
+ // ports
+ case "modified":
+ return "@FontAwesome5Solid/exclamation-circle/12";
+ case "up-to-date":
+ return "@FontAwesome5Solid/check/12";
+
+ default:
+ return "";
+ }
+ },
+
+ getLabelValue: function(state) {
+ switch (state) {
+ // computationals
+ case "STARTED":
+ return qx.locale.Manager.tr("Running");
+
+ // dynamics
+ case "ready":
+ return qx.locale.Manager.tr("Ready");
+ case "failed":
+ return qx.locale.Manager.tr("Error");
+ case "starting":
+ return qx.locale.Manager.tr("Starting...");
+ case "pending":
+ return qx.locale.Manager.tr("Pending...");
+ case "pulling":
+ return qx.locale.Manager.tr("Pulling...");
+ case "connecting":
+ return qx.locale.Manager.tr("Connecting...");
+
+ default:
+ return state;
+ }
+ },
+
+ getColor: function(state) {
+ switch (state) {
+ // computationals
+ case "SUCCESS":
+ return "ready-green";
+ case "FAILED":
+ case "ABORTED":
+ return "failed-red";
+ case "PENDING":
+ case "PUBLISHED":
+ case "STARTED":
+ case "RETRY":
+ return "busy-orange";
+ case "UNKNOWN":
+ case "NOT_STARTED":
+ return "text";
+
+ // dynamics
+ case "ready":
+ return "ready-green";
+ case "failed":
+ return "failed-red";
+ case "idle":
+ case "starting":
+ case "pulling":
+ case "pending":
+ case "connecting":
+ return "busy-orange";
+
+ // ports
+ case "modified":
+ return "busy-orange";
+ case "up-to-date":
+ return "ready-green";
+
+ default:
+ return "text";
+ }
+ },
+
+ getBorderDecorator: function(state) {
+ switch (state) {
+ case "SUCCESS":
+ return "border-ok";
+ case "FAILED":
+ case "ABORTED":
+ return "border-error";
+ case "PENDING":
+ case "PUBLISHED":
+ case "STARTED":
+ case "RETRY":
+ return "border-busy";
+ case "UNKNOWN":
+ case "NOT_STARTED":
+ return "no-border";
+
+ default:
+ return "no-border";
+ }
+ }
+ }
+});
diff --git a/services/web/client/source/class/osparc/viewer/NodeViewer.js b/services/web/client/source/class/osparc/viewer/NodeViewer.js
index 134f0548abf..288cade9258 100644
--- a/services/web/client/source/class/osparc/viewer/NodeViewer.js
+++ b/services/web/client/source/class/osparc/viewer/NodeViewer.js
@@ -23,9 +23,7 @@ qx.Class.define("osparc.viewer.NodeViewer", {
this._setLayout(new qx.ui.layout.VBox());
- this.__initLoadingPage();
this.__initIFrame();
-
this.__iFrameChanged();
this.set({
@@ -85,6 +83,8 @@ qx.Class.define("osparc.viewer.NodeViewer", {
},
__initIFrame: function() {
+ this.__initLoadingPage();
+
const iframe = new osparc.component.widget.PersistentIframe().set({
showActionButton: false,
showRestartButton: false
diff --git a/tests/e2e/tutorials/jupyters.js b/tests/e2e/tutorials/jupyters.js
index b7e7088fcb3..1fe216aaa3e 100644
--- a/tests/e2e/tutorials/jupyters.js
+++ b/tests/e2e/tutorials/jupyters.js
@@ -55,7 +55,8 @@ async function runTutorial() {
await tutorial.takeScreenshot("pressRunNB_" + (i+1));
}
- await tutorial.retrieve();
+ // TODO: Better check that the kernel is finished
+ await tutorial.waitFor(3000);
console.log('Checking results for the notebook:');
await tutorial.openNodeFiles(1);
@@ -69,8 +70,6 @@ async function runTutorial() {
// open jupyter lab
await tutorial.openNode(2);
- await tutorial.retrieve();
-
const iframeHandles2 = await tutorial.getIframe();
// expected three iframes = loading + jupyterNB + jupyterLab
const jLabIframe = await iframeHandles2[2].contentFrame();
diff --git a/tests/e2e/utils/utils.js b/tests/e2e/utils/utils.js
index c807294fa3b..53d7ced521d 100644
--- a/tests/e2e/utils/utils.js
+++ b/tests/e2e/utils/utils.js
@@ -369,7 +369,7 @@ function isElementVisible (page, selector) {
async function clickLoggerTitle(page) {
console.log("Click LoggerTitle");
- await this.waitAndClick(page, '[osparc-test-id="loggerTitleLabel"]')
+ await this.waitAndClick(page, '[osparc-test-id="studyLoggerTitleLabel"]')
}