Skip to content

Commit 4a5956a

Browse files
authored
Bind node states to GUI elements (#2153)
Bind node states to GUI elements: - Dependencies: Node still waiting for an input coming from the upstream - WV: colored the "in" label in the Node box. - NV: Show an icon in the inputs on the left - GM: Grey out nodes that are waiting for dependencies. When clicking on a greyed out step, ask for running all the previous ones. - Running/Interactive: Node's running state: - WV: colored NodeStatus text in the Node box - NV: Show the running status on the toolbar - GM: Running status on breadcrumb - Modified: Node is out of date. A combination of a input modified in the node itself && waiting for dependencies - WV: colored the "out" label in the Node box. The edge will also show that the current output was modified - NV: Show an icon in the outputs on the right - GM: Propagate modified downstream
1 parent 24ea40e commit 4a5956a

33 files changed

+1060
-509
lines changed

services/web/client/source/class/osparc/component/node/BaseNodeView.js

+36-3
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
5858
__pane2: null,
5959
__title: null,
6060
__serviceInfoLayout: null,
61+
__nodeStatusUI: null,
6162
__header: null,
6263
_mainView: null,
6364
__inputsView: null,
@@ -66,8 +67,9 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
6667
_settingsLayout: null,
6768
_mapperLayout: null,
6869
_iFrameLayout: null,
70+
_loggerLayout: null,
6971
__buttonContainer: null,
70-
__filesButton: null,
72+
__outFilesButton: null,
7173

7274
populateLayout: function() {
7375
this.__cleanLayout();
@@ -77,6 +79,8 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
7779
this.__addOutputPortsUIs();
7880
this._addSettings();
7981
this._addIFrame();
82+
// this._addLogger();
83+
8084
this._addButtons();
8185
},
8286

@@ -193,6 +197,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
193197
this._settingsLayout = this.self().createSettingsGroupBox(this.tr("Settings"));
194198
this._mapperLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox(10));
195199
this._iFrameLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox());
200+
this._loggerLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox());
196201

197202
return mainView;
198203
},
@@ -237,8 +242,14 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
237242

238243
header.addSpacer();
239244

245+
// just a placeholder until the node is set
246+
const nodeStatusUI = this.__nodeStatusUI = new qx.ui.core.Widget();
247+
header.add(nodeStatusUI);
248+
249+
header.addSpacer();
250+
240251
const buttonsPart = this.__buttonContainer = new qx.ui.toolbar.Part();
241-
const filesBtn = this.__filesButton = new qx.ui.toolbar.Button(this.tr("Output Files"), "@FontAwesome5Solid/folder-open/14");
252+
const filesBtn = this.__outFilesButton = new qx.ui.toolbar.Button(this.tr("Output Files"), "@FontAwesome5Solid/folder-open/14");
242253
osparc.utils.Utils.setIdToWidget(filesBtn, "nodeViewFilesBtn");
243254
filesBtn.addListener("execute", () => this.__openNodeDataManager(), this);
244255
buttonsPart.add(filesBtn);
@@ -334,7 +345,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
334345
retrieveBtn.setEnabled(Boolean(this.getNode().getServiceUrl()));
335346
this.__buttonContainer.add(retrieveBtn);
336347
}
337-
this.__buttonContainer.add(this.__filesButton);
348+
this.__buttonContainer.add(this.__outFilesButton);
338349
this.__header.add(this.__buttonContainer);
339350
},
340351

@@ -346,6 +357,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
346357
const othersStatus2 = isSettingsGroupShowable && !maximize ? "visible" : "excluded";
347358
this._settingsLayout.setVisibility(othersStatus2);
348359
this._mapperLayout.setVisibility(othersStatus);
360+
this._loggerLayout.setVisibility(othersStatus);
349361
this.__header.setVisibility(othersStatus);
350362
},
351363

@@ -475,13 +487,27 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
475487
throw new Error("Abstract method called!");
476488
},
477489

490+
_addLogger: function() {
491+
return;
492+
},
493+
478494
/**
479495
* @abstract
480496
*/
481497
_openEditAccessLevel: function() {
482498
throw new Error("Abstract method called!");
483499
},
484500

501+
__createNodeStatusUI: function(node) {
502+
const nodeStatusUI = new osparc.ui.basic.NodeStatusUI(node).set({
503+
backgroundColor: "material-button-background"
504+
});
505+
nodeStatusUI.getChildControl("label").set({
506+
font: "text-16"
507+
});
508+
return nodeStatusUI;
509+
},
510+
485511
/**
486512
* @param node {osparc.data.model.Node} node
487513
*/
@@ -498,6 +524,13 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
498524
const infoButton = this.__getInfoButton();
499525
this.__serviceInfoLayout.add(infoButton);
500526
}
527+
528+
const idx = this.__header.indexOf(this.__nodeStatusUI);
529+
if (idx > -1) {
530+
this.__header.remove(this.__nodeStatusUI);
531+
}
532+
this.__nodeStatusUI = this.__createNodeStatusUI(node);
533+
this.__header.addAt(this.__nodeStatusUI, idx);
501534
}
502535
}
503536
});

services/web/client/source/class/osparc/component/node/NodeView.js

+42-21
Original file line numberDiff line numberDiff line change
@@ -100,34 +100,55 @@ qx.Class.define("osparc.component.node.NodeView", {
100100

101101
const loadingPage = this.getNode().getLoadingPage();
102102
const iFrame = this.getNode().getIFrame();
103-
if (loadingPage === null && iFrame === null) {
104-
return;
105-
}
106-
[
107-
loadingPage,
108-
iFrame
109-
].forEach(widget => {
110-
if (widget) {
111-
widget.addListener("maximize", e => {
112-
this._maximizeIFrame(true);
113-
}, this);
114-
widget.addListener("restore", e => {
115-
this._maximizeIFrame(false);
116-
}, this);
117-
this._maximizeIFrame(widget.hasState("maximized"));
118-
}
119-
});
120-
this.__iFrameChanged();
121-
122-
iFrame.addListener("load", () => {
103+
if (loadingPage && iFrame) {
104+
[
105+
loadingPage,
106+
iFrame
107+
].forEach(widget => {
108+
if (widget) {
109+
widget.addListener("maximize", e => {
110+
this._maximizeIFrame(true);
111+
}, this);
112+
widget.addListener("restore", e => {
113+
this._maximizeIFrame(false);
114+
}, this);
115+
this._maximizeIFrame(widget.hasState("maximized"));
116+
}
117+
});
123118
this.__iFrameChanged();
124-
});
119+
120+
iFrame.addListener("load", () => {
121+
this.__iFrameChanged();
122+
});
123+
} else {
124+
// This will keep what comes after at the bottom
125+
this._iFrameLayout.add(new qx.ui.core.Spacer(), {
126+
flex: 1
127+
});
128+
}
125129

126130
this._addToMainView(this._iFrameLayout, {
127131
flex: 1
128132
});
129133
},
130134

135+
_addLogger: function() {
136+
this._loggerLayout.removeAll();
137+
138+
const loggerView = this.__loggerView = this.getNode().getLogger().set({
139+
maxHeight: 250
140+
});
141+
loggerView.getChildControl("pin-node").exclude();
142+
const loggerPanel = new osparc.desktop.PanelView(this.tr("Logger"), loggerView).set({
143+
collapsed: true,
144+
backgroundColor: "background-main-lighter"
145+
});
146+
osparc.utils.Utils.setIdToWidget(loggerPanel.getTitleLabel(), "nodeLoggerTitleLabel");
147+
this._loggerLayout.add(loggerPanel);
148+
149+
this._addToMainView(this._loggerLayout);
150+
},
151+
131152
_openEditAccessLevel: function() {
132153
const settingsEditorLayout = osparc.component.node.BaseNodeView.createSettingsGroupBox(this.tr("Settings"));
133154
const propsFormEditor = this.getNode().getPropsFormEditor();

services/web/client/source/class/osparc/component/widget/CollapsibleView.js

+14-4
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,18 @@ qx.Class.define("osparc.component.widget.CollapsibleView", {
100100
}
101101
case "title": {
102102
const header = this.getChildControl("header");
103-
control = new qx.ui.basic.Atom(this.getTitle());
103+
control = new qx.ui.basic.Label(this.getTitle());
104104
header.addAt(control, 1);
105105
// Attach handler
106106
this.__attachToggler(control);
107107
break;
108108
}
109+
case "icon": {
110+
const header = this.getChildControl("header");
111+
control = new qx.ui.basic.Image();
112+
header.addAt(control, 2);
113+
break;
114+
}
109115
}
110116
return control || this.base(arguments, id);
111117
},
@@ -187,12 +193,16 @@ qx.Class.define("osparc.component.widget.CollapsibleView", {
187193
}
188194
},
189195

196+
_applyCaretSize: function(size) {
197+
this.getChildControl("caret").setSource(this.__getCaretId(this.getCollapsed()));
198+
},
199+
190200
_applyTitle: function(title) {
191-
this.getChildControl("title").setLabel(title);
201+
this.getChildControl("title").setValue(title);
192202
},
193203

194-
_applyCaretSize: function(size) {
195-
this.getChildControl("caret").setSource(this.__getCaretId(this.getCollapsed()));
204+
_applyIcon: function(icon) {
205+
this.getChildControl("icon").setSource(icon);
196206
},
197207

198208
__getCaretId: function(collapsed) {

services/web/client/source/class/osparc/component/widget/NodePorts.js

+23
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,30 @@ qx.Class.define("osparc.component.widget.NodePorts", {
4444

4545
this.base(arguments, node.getLabel());
4646

47+
this.getTitleBar().set({
48+
height: 30
49+
});
4750
node.bind("label", this, "title");
51+
52+
node.getStatus().bind("modified", this.getChildControl("icon"), "source", {
53+
converter: modified => {
54+
if (modified === null) {
55+
return osparc.utils.StatusUI.getIconSource();
56+
}
57+
return osparc.utils.StatusUI.getIconSource(modified === true ? "modified" : "up-to-date");
58+
}
59+
}, this);
60+
node.getStatus().bind("modified", this.getChildControl("icon"), "textColor", {
61+
converter: modified => {
62+
if (modified === null) {
63+
return osparc.utils.StatusUI.getColor();
64+
}
65+
return osparc.utils.StatusUI.getColor(modified === true ? "modified" : "up-to-date");
66+
}
67+
}, this);
68+
node.getStatus().bind("modified", this.getChildControl("icon"), "toolTipText", {
69+
converter: modified => modified === true ? this.tr("Out of date") : ""
70+
}, this);
4871
},
4972

5073
properties: {

services/web/client/source/class/osparc/component/widget/logger/RemoteTableModel.js renamed to services/web/client/source/class/osparc/component/widget/logger/LoggerTable.js

+16-19
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
* Here is a little example of how to use the widget.
2626
*
2727
* <pre class='javascript'>
28-
* let tableModel = this.__logModel = new osparc.component.widget.logger.RemoteTableModel();
28+
* let tableModel = this.__logModel = new osparc.component.widget.logger.LoggerTable();
2929
* tableModel.setColumns(["Origin", "Message"], ["whoRich", "whatRich"]);
3030
* let custom = {
3131
* tableColumnModel : function(obj) {
@@ -42,14 +42,19 @@
4242
* @asset(demobrowser/backend/remote_table.php)
4343
*/
4444

45-
qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
46-
45+
qx.Class.define("osparc.component.widget.logger.LoggerTable", {
4746
extend : qx.ui.table.model.Remote,
4847

4948
construct : function() {
5049
this.base(arguments);
5150

52-
this.setColumns(["Origin", "Message"], ["whoRich", "msgRich"]);
51+
this.setColumns([
52+
"Origin",
53+
"Message"
54+
], [
55+
"whoRich",
56+
"msgRich"
57+
]);
5358

5459
this.__rawData = [];
5560
},
@@ -60,15 +65,11 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
6065
check : "Number",
6166
init: -1
6267
},
68+
6369
filterString: {
6470
nullable: true,
6571
check : "String",
6672
init: ""
67-
},
68-
caseSensitive: {
69-
nullable: false,
70-
check : "Boolean",
71-
init: false
7273
}
7374
},
7475

@@ -85,8 +86,8 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
8586
addRows: function(newRows) {
8687
for (let i=0; i<newRows.length; i++) {
8788
const newRow = newRows[i];
88-
newRow["whoRich"] = osparc.component.widget.logger.RemoteTableModel.addColorTag(newRow.label, newRow.nodeColor);
89-
newRow["msgRich"] = osparc.component.widget.logger.RemoteTableModel.addColorTag(newRow.msg, newRow.msgColor);
89+
newRow["whoRich"] = osparc.component.widget.logger.LoggerTable.addColorTag(newRow.label, newRow.nodeColor);
90+
newRow["msgRich"] = osparc.component.widget.logger.LoggerTable.addColorTag(newRow.msg, newRow.msgColor);
9091
this.__rawData.push(newRow);
9192
}
9293
},
@@ -100,7 +101,7 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
100101
const row = this.__rawData[i];
101102
if (row.nodeId === nodeId) {
102103
row.label = newLabel;
103-
row["whoRich"] = osparc.component.widget.logger.RemoteTableModel.addColorTag(row.label, row.nodeColor);
104+
row["whoRich"] = osparc.component.widget.logger.LoggerTable.addColorTag(row.label, row.nodeColor);
104105
}
105106
}
106107
},
@@ -143,13 +144,9 @@ qx.Class.define("osparc.component.widget.logger.RemoteTableModel", {
143144
if (searchString === null || searchString === "") {
144145
return true;
145146
}
146-
if (searchString && !this.isCaseSensitive()) {
147-
searchString = searchString.toUpperCase();
148-
}
149-
if (msg !== null && msg !== undefined) {
150-
if (!this.isCaseSensitive()) {
151-
msg = msg.toUpperCase();
152-
}
147+
searchString = searchString.toUpperCase();
148+
if (msg) {
149+
msg = msg.toUpperCase();
153150
return msg.includes(searchString);
154151
}
155152
return false;

0 commit comments

Comments
 (0)