Skip to content

Commit 6df7211

Browse files
authored
✨ App mode: get ready for larger studies (ITISFoundation#3359)
1 parent 62590f3 commit 6df7211

File tree

23 files changed

+298
-163
lines changed

23 files changed

+298
-163
lines changed

services/web/client/source/class/osparc/Application.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ qx.Class.define("osparc.Application", {
434434
if (this.__mainPage) {
435435
this.__mainPage.closeEditor();
436436
}
437+
osparc.utils.Utils.closeHangingWindows();
437438
osparc.store.Store.getInstance().dispose();
438439
this.__restart();
439440
},

services/web/client/source/class/osparc/auth/LoginPage.js

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -75,38 +75,6 @@ qx.Class.define("osparc.auth.LoginPage", {
7575
return image;
7676
},
7777

78-
_getLogoWPlatform2: function() {
79-
const container = new qx.ui.container.Stack();
80-
[
81-
"osparc/kz_1.jpg",
82-
"osparc/kz_2.jpg",
83-
"osparc/kz_3.png",
84-
"osparc/kz_4.png"
85-
].forEach((src, i) => {
86-
const layout = new qx.ui.container.Composite(new qx.ui.layout.HBox());
87-
layout.add(new qx.ui.core.Spacer(), {
88-
flex: 1
89-
});
90-
const image = new qx.ui.basic.Image(src).set({
91-
allowShrinkX: true,
92-
allowShrinkY: true,
93-
width: 300,
94-
height: 150,
95-
scale: true
96-
});
97-
image.addListener("tap", () => {
98-
const nextIdx = i === 3 ? 0 : i+1;
99-
container.setSelection([container.getSelectables()[nextIdx]]);
100-
});
101-
layout.add(image);
102-
layout.add(new qx.ui.core.Spacer(), {
103-
flex: 1
104-
});
105-
container.add(layout);
106-
});
107-
return container;
108-
},
109-
11078
_getLoginStack: function() {
11179
const pages = new qx.ui.container.Stack().set({
11280
allowGrowX: false,

services/web/client/source/class/osparc/auth/Manager.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,12 @@ qx.Class.define("osparc.auth.Manager", {
242242
},
243243

244244
__fetchStartUpResources: function() {
245-
osparc.data.Resources.get("clusters");
245+
osparc.utils.DisabledPlugins.isClustersDisabled()
246+
.then(isDisabled => {
247+
if (isDisabled === false) {
248+
osparc.data.Resources.get("clusters");
249+
}
250+
});
246251
},
247252

248253
__logoutUser: function() {

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

Lines changed: 49 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,14 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
7070
}
7171
},
7272

73+
events: {
74+
"startPartialPipeline": "qx.event.type.Data",
75+
"stopPipeline": "qx.event.type.Event"
76+
},
77+
7378
members: {
7479
_header: null,
75-
__inputsStateButton: null,
80+
__inputsButton: null,
7681
__preparingInputs: null,
7782
__nodeStatusUI: null,
7883
_mainView: null,
@@ -103,33 +108,32 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
103108
},
104109

105110
_buildHeader: function() {
106-
const header = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({
111+
const header = new qx.ui.container.Composite(new qx.ui.layout.HBox(10).set({
107112
alignX: "center"
108113
})).set({
109114
padding: 6,
110115
height: this.self().HEADER_HEIGHT
111116
});
112117

113-
const infoBtn = new qx.ui.form.Button(null, "@MaterialIcons/info_outline/16").set({
114-
backgroundColor: "transparent",
115-
toolTipText: this.tr("Information")
118+
119+
const inputsStateBtn = this.__inputsButton = new qx.ui.form.Button().set({
120+
label: this.tr("Inputs"),
121+
icon: "@FontAwesome5Solid/sign-in-alt/14",
122+
backgroundColor: "transparent"
116123
});
117-
infoBtn.addListener("execute", () => this.__openServiceDetails(), this);
118-
header.add(infoBtn);
124+
inputsStateBtn.addListener("execute", () => this.showPreparingInputs(), this);
125+
header.add(inputsStateBtn);
119126

120127
header.add(new qx.ui.core.Spacer(), {
121128
flex: 1
122129
});
123130

124-
const inputsStateBtn = this.__inputsStateButton = new qx.ui.form.Button().set({
125-
label: this.tr("Preparing inputs..."),
126-
icon: "@FontAwesome5Solid/circle-notch/14",
131+
const infoBtn = new qx.ui.form.Button(null, "@MaterialIcons/info_outline/16").set({
127132
backgroundColor: "transparent",
128-
toolTipText: this.tr("The view will remain disabled until the inputs are fetched")
133+
toolTipText: this.tr("Information")
129134
});
130-
inputsStateBtn.getChildControl("icon").getContentElement().addClass("rotate");
131-
inputsStateBtn.addListener("execute", () => this.showPreparingInputs(), this);
132-
header.add(inputsStateBtn);
135+
infoBtn.addListener("execute", () => this.__openServiceDetails(), this);
136+
header.add(infoBtn);
133137

134138
const nodeStatusUI = this.__nodeStatusUI = new osparc.ui.basic.NodeStatusUI().set({
135139
backgroundColor: "background-main-4"
@@ -141,9 +145,10 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
141145
flex: 1
142146
});
143147

144-
const outputsBtn = this._outputsBtn = new qx.ui.form.ToggleButton(null, "@FontAwesome5Solid/sign-out-alt/14").set({
145-
backgroundColor: "transparent",
146-
toolTipText: this.tr("Outputs")
148+
const outputsBtn = this._outputsBtn = new qx.ui.form.ToggleButton().set({
149+
label: this.tr("Outputs"),
150+
icon: "@FontAwesome5Solid/sign-out-alt/14",
151+
backgroundColor: "transparent"
147152
});
148153
osparc.utils.Utils.setIdToWidget(outputsBtn, "outputsBtn");
149154
header.add(outputsBtn);
@@ -256,7 +261,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
256261

257262
__areInputsReady: function() {
258263
const wb = this.getNode().getStudy().getWorkbench();
259-
const upstreamNodeIds = wb.getUpstreamNodes(this.getNode(), false);
264+
const upstreamNodeIds = wb.getUpstreamCompNodes(this.getNode(), false);
260265
for (let i=0; i<upstreamNodeIds.length; i++) {
261266
const upstreamNodeId = upstreamNodeIds[i];
262267
if (!osparc.data.model.NodeStatus.isCompNodeReady(wb.getNode(upstreamNodeId))) {
@@ -266,8 +271,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
266271
return true;
267272
},
268273

269-
__enableContent: function(enable) {
270-
this._mainView.setEnabled(enable);
274+
__enableIframeContent: function(enable) {
271275
const iframe = this.getNode().getIFrame();
272276
if (iframe) {
273277
// enable/disable user interaction on iframe
@@ -276,29 +280,47 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
276280
"pointer-events": enable ? "auto" : "none"
277281
});
278282
}
283+
if (enable) {
284+
if ("tapListenerId" in this._iFrameLayout) {
285+
this._iFrameLayout.removeListenerById(this._iFrameLayout.tapListenerId);
286+
}
287+
} else if (!this._iFrameLayout.hasListener("tap")) {
288+
const tapListenerId = this._iFrameLayout.addListener("tap", () => this.showPreparingInputs());
289+
this._iFrameLayout.tapListenerId = tapListenerId;
290+
}
279291
},
280292

281-
setNotReadyDependencies: function(notReadyNodeIds = []) {
293+
setUpstreamDependencies: function(upstreamDependencies) {
294+
this.__inputsButton.setVisibility(upstreamDependencies.length > 0 ? "visible" : "excluded");
282295
const monitoredNodes = [];
283296
const workbench = this.getNode().getStudy().getWorkbench();
284-
notReadyNodeIds.forEach(notReadyNodeId => monitoredNodes.push(workbench.getNode(notReadyNodeId)));
297+
upstreamDependencies.forEach(nodeId => monitoredNodes.push(workbench.getNode(nodeId)));
285298
this.__preparingInputs.setMonitoredNodes(monitoredNodes);
286299
},
287300

288301
__dependeciesChanged: function() {
289302
const preparingNodes = this.__preparingInputs.getPreparingNodes();
290303
const waiting = Boolean(preparingNodes && preparingNodes.length);
291-
this.__inputsStateButton.setVisibility(waiting ? "visible" : "excluded");
292-
this.__enableContent(!waiting);
304+
const buttonsIcon = this.__inputsButton.getChildControl("icon");
305+
if (waiting) {
306+
this.__inputsButton.setIcon("@FontAwesome5Solid/circle-notch/14");
307+
osparc.utils.Utils.addClass(buttonsIcon.getContentElement(), "rotate");
308+
} else {
309+
this.__inputsButton.setIcon("@FontAwesome5Solid/sign-in-alt/14");
310+
osparc.utils.Utils.removeClass(buttonsIcon.getContentElement(), "rotate");
311+
}
312+
this.__enableIframeContent(!waiting);
293313
},
294314

295315
__applyNode: function(node) {
296316
if (this.__nodeStatusUI) {
297317
this.__nodeStatusUI.setNode(node);
298318
}
299319

300-
this.__preparingInputs = new osparc.component.widget.PreparingInputs();
320+
this.__preparingInputs = new osparc.component.widget.PreparingInputs(node.getStudy());
301321
this.__preparingInputs.addListener("changePreparingNodes", () => this.__dependeciesChanged());
322+
this.__preparingInputs.addListener("startPartialPipeline", e => this.fireDataEvent("startPartialPipeline", e.getData()));
323+
this.__preparingInputs.addListener("stopPipeline", () => this.fireEvent("stopPipeline"));
302324
this.__dependeciesChanged();
303325

304326
this._mainView.removeAll();
@@ -310,7 +332,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
310332
const updateProgress = () => {
311333
const running = node.getStatus().getRunning();
312334
const progress = node.getStatus().getProgress();
313-
if (["PENDING", "PUBLISHED"].includes(running) ||
335+
if (["PUBLISHED", "PENDING"].includes(running) ||
314336
(["STARTED"].includes(running) && progress === 0)) {
315337
this.__progressBar.setBackgroundColor("busy-orange");
316338
this.__progressBar.getContentElement().setStyles({
@@ -348,7 +370,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
348370
outputCounter++;
349371
}
350372
});
351-
return `(${outputCounter})`;
373+
return this.tr("Outputs") + ` (${outputCounter})`;
352374
}
353375
});
354376
this._outputsBtn.addListener("changeLabel", () => {

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

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,40 @@
1818
qx.Class.define("osparc.component.widget.PreparingInputs", {
1919
extend: qx.ui.core.Widget,
2020

21-
construct: function(monitoredNodes = []) {
21+
construct: function(study) {
2222
this.base(arguments);
2323

2424
osparc.utils.Utils.setIdToWidget(this, "preparingInputsView");
2525

2626
this._setLayout(new qx.ui.layout.VBox(10));
2727

28-
const text = this.tr("In order to move to this step, we need to prepare some inputs for you.<br>This might take a while, so enjoy checking the logs down here:");
28+
const text = this.tr("In order to move to this step, we need to prepare some inputs for you.<br>Here you can check the logs of the progress:");
2929
const title = new qx.ui.basic.Label(text).set({
3030
font: "text-14",
3131
rich: true
3232
});
3333
this._add(title);
3434

35+
const startStopButtons = new qx.ui.container.Composite(new qx.ui.layout.HBox(5)).set({
36+
marginLeft: 50
37+
});
38+
const runAllButton = this.__getRunAllButton();
39+
startStopButtons.add(runAllButton);
40+
const stopButton = this.__getStopButton();
41+
startStopButtons.add(stopButton);
42+
this._add(startStopButtons);
43+
3544
const list = this.__monitoredNodesList = new qx.ui.container.Composite(new qx.ui.layout.VBox(5));
3645
this._add(list);
37-
this.setMonitoredNodes(monitoredNodes);
46+
this.setMonitoredNodes([]);
3847

3948
const loggerLayout = this.__loggerLayout = new qx.ui.container.Composite(new qx.ui.layout.VBox());
4049
this._add(loggerLayout, {
4150
flex: 1
4251
});
52+
53+
study.addListener("changePipelineRunning", () => this.__updateRunButtonsStatus(study));
54+
this.__updateRunButtonsStatus(study);
4355
},
4456

4557
properties: {
@@ -52,11 +64,47 @@ qx.Class.define("osparc.component.widget.PreparingInputs", {
5264
},
5365

5466
events: {
55-
"changePreparingNodes": "qx.event.type.Data"
67+
"changePreparingNodes": "qx.event.type.Data",
68+
"startPartialPipeline": "qx.event.type.Data",
69+
"stopPipeline": "qx.event.type.Event"
5670
},
5771

5872
members: {
5973
__monitoredNodesList: null,
74+
__runAllButton: null,
75+
__stopButton: null,
76+
77+
__getRunAllButton: function() {
78+
const runAllButton = this.__runAllButton = new osparc.ui.form.FetchButton(this.tr("Run all")).set({
79+
minWidth: 80,
80+
maxWidth: 80,
81+
alignX: "center"
82+
});
83+
runAllButton.addListener("execute", () => {
84+
const monitoredNodes = this.getMonitoredNodes();
85+
if (monitoredNodes && monitoredNodes.length) {
86+
const moniteoredNodesIds = monitoredNodes.map(monitoredNode => monitoredNode.getNodeId());
87+
this.fireDataEvent("startPartialPipeline", moniteoredNodesIds);
88+
}
89+
});
90+
return runAllButton;
91+
},
92+
93+
__getStopButton: function() {
94+
const stopButton = this.__stopButton = new osparc.ui.form.FetchButton(this.tr("Stop")).set({
95+
minWidth: 80,
96+
maxWidth: 80,
97+
alignX: "center"
98+
});
99+
stopButton.addListener("execute", () => this.fireEvent("stopPipeline"), this);
100+
return stopButton;
101+
},
102+
103+
__updateRunButtonsStatus: function(study) {
104+
const isPipelineRunning = study.isPipelineRunning();
105+
this.__runAllButton.setFetching(isPipelineRunning);
106+
this.__stopButton.setEnabled(isPipelineRunning);
107+
},
60108

61109
__applyMonitoredNodes: function(monitoredNodes) {
62110
monitoredNodes.forEach(monitoredNode => {
@@ -68,6 +116,7 @@ qx.Class.define("osparc.component.widget.PreparingInputs", {
68116
});
69117
});
70118
this.__updateMonitoredNodesList();
119+
this.__updatePreparingNodes();
71120
},
72121

73122
__updateMonitoredNodesList: function() {
@@ -86,13 +135,43 @@ qx.Class.define("osparc.component.widget.PreparingInputs", {
86135
const nodeLayout = new qx.ui.container.Composite(new qx.ui.layout.HBox(5).set({
87136
alignY: "middle"
88137
}));
138+
89139
const showLoggerBtn = new qx.ui.form.ToggleButton(this.tr("Logs"));
90140
showLoggerBtn.node = node;
91141
nodeLayout.add(showLoggerBtn);
92142
group.add(showLoggerBtn);
93143
if (group.getSelection().length === 0) {
94144
group.setSelection([showLoggerBtn]);
95145
}
146+
147+
const rerunBtn = new osparc.ui.form.FetchButton(this.tr("Re-run")).set({
148+
minWidth: 80,
149+
maxWidth: 80,
150+
alignX: "center"
151+
});
152+
rerunBtn.addListener("execute", () => this.fireDataEvent("startPartialPipeline", [node.getNodeId()]), this);
153+
nodeLayout.add(rerunBtn);
154+
155+
const checkRerunStatus = () => {
156+
const nodeRunningStatus = node.getStatus().getRunning();
157+
const fetching = [
158+
"PUBLISHED",
159+
"PENDING",
160+
"STARTED"
161+
].includes(nodeRunningStatus);
162+
rerunBtn.setFetching(fetching);
163+
const rerunnable = [
164+
"FAILED",
165+
"ABORTED",
166+
"SUCCESS"
167+
].includes(nodeRunningStatus);
168+
const isPipelineRunning = node.getStudy().isPipelineRunning();
169+
rerunBtn.setEnabled(rerunnable && !(isPipelineRunning === true));
170+
};
171+
node.getStatus().addListener("changeRunning", () => checkRerunStatus());
172+
node.getStudy().addListener("changePipelineRunning", () => checkRerunStatus());
173+
checkRerunStatus();
174+
96175
const statusUI = new osparc.ui.basic.NodeStatusUI(node);
97176
nodeLayout.add(statusUI);
98177
nodeLayout.add(new qx.ui.basic.Label(node.getLabel()), {
@@ -114,7 +193,6 @@ qx.Class.define("osparc.component.widget.PreparingInputs", {
114193
return preparingNodes;
115194
},
116195

117-
118196
__updatePreparingNodes: function() {
119197
this.fireDataEvent("changePreparingNodes", this.getPreparingNodes().length);
120198
}

services/web/client/source/class/osparc/data/model/NodeStatus.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,7 @@ qx.Class.define("osparc.data.model.NodeStatus", {
9999

100100
isCompNodeReady: function(node) {
101101
if (node && node.isComputational()) {
102-
return (
103-
// run if last run was not succesful
104-
node.getStatus().getRunning() === "SUCCESS" &&
105-
// and outputs up-to-date
106-
node.getStatus().getOutput() === "up-to-date"
107-
);
102+
return node.getStatus().getRunning() === "SUCCESS" && node.getStatus().getOutput() === "up-to-date";
108103
}
109104
return true;
110105
},

0 commit comments

Comments
 (0)