Skip to content

Commit 908699a

Browse files
authored
File Picker with downloadLink UI/UX (#2194)
- File Picker's modified status is either null or false, never true. - Dynamic service's modified status can only be true if there is an output. - DownloadLink label extraction extended and initialization improved.
1 parent 790bac2 commit 908699a

File tree

9 files changed

+88
-83
lines changed

9 files changed

+88
-83
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ qx.Class.define("osparc.component.node.BaseNodeView", {
334334

335335
_addButtons: function() {
336336
this.__buttonContainer.removeAll();
337-
if (this.getNode().isDynamic() && this.getNode().isRealService()) {
337+
if (this.getNode().isDynamic()) {
338338
const retrieveBtn = new qx.ui.form.Button(this.tr("Retrieve"), "@FontAwesome5Solid/spinner/14");
339339
osparc.utils.Utils.setIdToWidget(retrieveBtn, "nodeViewRetrieveBtn");
340340
retrieveBtn.addListener("execute", e => {

services/web/client/source/class/osparc/component/widget/inputs/NodeOutputTreeItem.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,12 @@ qx.Class.define("osparc.component.widget.inputs.NodeOutputTreeItem", {
149149
url: presignedLinkData.presignedLink.link
150150
});
151151
}
152-
} else if (typeof value === "object" && "donwloadLink" in value) {
152+
} else if (typeof value === "object" && "downloadLink" in value) {
153153
// it's a link
154+
const filename = (value.filename && value.filename.length > 0) ? value.filename : osparc.file.FileDownloadLink.extractLabelFromLink(value["downloadLink"]);
154155
this.__labelLink.set({
155-
value: value.filename,
156-
url: value.donwloadLink
156+
value: filename,
157+
url: value.downloadLink
157158
});
158159
} else {
159160
this.__label.setValue(value);
@@ -180,7 +181,7 @@ qx.Class.define("osparc.component.widget.inputs.NodeOutputTreeItem", {
180181
if (value.getDownloadLink) {
181182
// it's a link
182183
return {
183-
donwloadLink: value.getDownloadLink(),
184+
downloadLink: value.getDownloadLink(),
184185
filename: value.getLabel()
185186
};
186187
}

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

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ qx.Class.define("osparc.data.model.Node", {
192192
},
193193

194194
statics: {
195+
196+
isFilePicker: function(metaData) {
197+
return (metaData && metaData.key && metaData.key.includes("file-picker"));
198+
},
199+
195200
isContainer: function(metaData) {
196201
return (metaData && metaData.key && metaData.key.includes("nodes-group"));
197202
},
@@ -202,14 +207,6 @@ qx.Class.define("osparc.data.model.Node", {
202207

203208
isComputational: function(metaData) {
204209
return (metaData && metaData.type && metaData.type === "computational");
205-
},
206-
207-
isFilePicker: function(metaData) {
208-
return (metaData && metaData.key && metaData.key.includes("file-picker"));
209-
},
210-
211-
isRealService: function(metaData) {
212-
return (metaData && metaData.type && (metaData.key.includes("simcore/services/dynamic") || metaData.key.includes("simcore/services/comp")));
213210
}
214211
},
215212

@@ -241,6 +238,10 @@ qx.Class.define("osparc.data.model.Node", {
241238
return this.getKey().includes(str);
242239
},
243240

241+
isFilePicker: function() {
242+
return osparc.data.model.Node.isFilePicker(this.getMetaData());
243+
},
244+
244245
isContainer: function() {
245246
return osparc.data.model.Node.isContainer(this.getMetaData());
246247
},
@@ -253,14 +254,6 @@ qx.Class.define("osparc.data.model.Node", {
253254
return osparc.data.model.Node.isComputational(this.getMetaData());
254255
},
255256

256-
isFilePicker: function() {
257-
return osparc.data.model.Node.isFilePicker(this.getMetaData());
258-
},
259-
260-
isRealService: function() {
261-
return osparc.data.model.Node.isRealService(this.getMetaData());
262-
},
263-
264257
getMetaData: function() {
265258
return this.__metaData;
266259
},
@@ -384,11 +377,13 @@ qx.Class.define("osparc.data.model.Node", {
384377
this.getStatus().setDependencies(nodeData.state.dependencies);
385378
}
386379
if ("currentStatus" in nodeData.state && this.isComputational()) {
380+
// currentStatus is only applicable to computational services
387381
this.getStatus().setRunning(nodeData.state.currentStatus);
388382
}
389383
if ("modified" in nodeData.state) {
390384
if (this.getStatus().getHasOutputs()) {
391-
this.getStatus().setModified(nodeData.state.modified || this.getStatus().hasDependencies());
385+
// File Picker can't have a modified output
386+
this.getStatus().setModified((nodeData.state.modified || this.getStatus().hasDependencies()) && !this.isFilePicker());
392387
} else {
393388
this.getStatus().setModified(null);
394389
}
@@ -657,7 +652,7 @@ qx.Class.define("osparc.data.model.Node", {
657652
}
658653
this.getStatus().setHasOutputs(hasOutputs);
659654

660-
if (this.isFilePicker() || this.isDynamic()) {
655+
if (hasOutputs && (this.isFilePicker() || this.isDynamic())) {
661656
this.getStatus().setModified(false);
662657
}
663658

@@ -888,7 +883,7 @@ qx.Class.define("osparc.data.model.Node", {
888883
},
889884

890885
retrieveInputs: function(portKey = null) {
891-
if (this.isDynamic() && this.isRealService()) {
886+
if (this.isDynamic()) {
892887
if (!osparc.data.Permissions.getInstance().canDo("study.update")) {
893888
return;
894889
}
@@ -947,7 +942,7 @@ qx.Class.define("osparc.data.model.Node", {
947942
},
948943

949944
startDynamicService: function() {
950-
if (this.isDynamic() && this.isRealService()) {
945+
if (this.isDynamic()) {
951946
const metaData = this.getMetaData();
952947

953948
const msg = "Starting " + metaData.key + ":" + metaData.version + "...";

services/web/client/source/class/osparc/file/FileDownloadLink.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ qx.Class.define("osparc.file.FileDownloadLink", {
3535
this.base(arguments);
3636

3737
this._setLayout(new qx.ui.layout.HBox(5));
38-
const downloadLinkField = this.__downloadLinkField = this._createChildControlImpl("downloadLink");
3938

40-
const selectButton = this._createChildControlImpl("selectButton");
39+
const downloadLinkField = this.getChildControl("downloadLinkField");
40+
41+
const selectButton = this.getChildControl("selectButton");
4142
selectButton.addListener("execute", () => {
4243
const downloadLink = downloadLinkField.getValue();
4344
this.fireDataEvent("fileLinkAdded", downloadLink);
@@ -59,7 +60,13 @@ qx.Class.define("osparc.file.FileDownloadLink", {
5960
const parts = found[1].split("/");
6061
return parts[parts.length - 1];
6162
}
62-
return "n/a";
63+
64+
const idx = downloadLink.lastIndexOf("/");
65+
if (idx > -1) {
66+
return downloadLink.substring(idx + 1);
67+
}
68+
69+
return "unknown";
6370
},
6471

6572
checkFileExists: function(urlToFile) {
@@ -79,12 +86,10 @@ qx.Class.define("osparc.file.FileDownloadLink", {
7986
},
8087

8188
members: {
82-
__downloadLinkField: null,
83-
8489
_createChildControlImpl: function(id) {
8590
let control;
8691
switch (id) {
87-
case "downloadLink":
92+
case "downloadLinkField":
8893
control = new qx.ui.form.TextField().set({
8994
placeholder: this.tr("Type a Download Link")
9095
});
@@ -112,11 +117,11 @@ qx.Class.define("osparc.file.FileDownloadLink", {
112117
},
113118

114119
getValue: function() {
115-
return this.__downloadLinkField.getValue();
120+
return this.getChildControl("downloadLinkField").getValue();
116121
},
117122

118123
setValue: function(value) {
119-
this.__downloadLinkField.setValue(value);
124+
this.getChildControl("downloadLinkField").setValue(value);
120125
}
121126
}
122127
});

services/web/client/source/class/osparc/file/FilePicker.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,16 @@ qx.Class.define("osparc.file.FilePicker", {
5454
},
5555

5656
statics: {
57-
getOutputLabel: function(outputs) {
57+
getOutput: function(outputs) {
5858
if ("outFile" in outputs && "value" in outputs["outFile"]) {
59-
const outFileValue = outputs["outFile"]["value"];
59+
return outputs["outFile"]["value"];
60+
}
61+
return null;
62+
},
63+
64+
getOutputLabel: function(outputs) {
65+
const outFileValue = this.getOutput(outputs);
66+
if (outFileValue) {
6067
if ("label" in outFileValue) {
6168
return outFileValue.label;
6269
}
@@ -71,10 +78,26 @@ qx.Class.define("osparc.file.FilePicker", {
7178
return null;
7279
},
7380

81+
isOutputFromStore: function(outputs) {
82+
const outFileValue = this.getOutput(outputs);
83+
return (typeof outFileValue === "object" && "path" in outFileValue);
84+
},
85+
86+
isOutputDownloadLink: function(outputs) {
87+
const outFileValue = this.getOutput(outputs);
88+
return (typeof outFileValue === "object" && "downloadLink" in outFileValue);
89+
},
90+
91+
extractLabelFromLink: function(outputs) {
92+
const outFileValue = this.getOutput(outputs);
93+
return osparc.file.FileDownloadLink.extractLabelFromLink(outFileValue["downloadLink"]);
94+
},
95+
7496
serializeOutput: function(outputs) {
7597
let output = {};
76-
if ("outFile" in outputs && "value" in outputs["outFile"]) {
77-
output["outFile"] = outputs["outFile"]["value"];
98+
const outFileValue = this.self().getOutput(outputs);
99+
if (outFileValue) {
100+
output["outFile"] = outFileValue;
78101
}
79102
return output;
80103
},
@@ -196,12 +219,12 @@ qx.Class.define("osparc.file.FilePicker", {
196219
},
197220

198221
init: function() {
199-
if (this.__isOutputFileSelectedFromStore()) {
222+
if (this.self().isOutputFromStore(this.getNode().getOutputs())) {
200223
const outFile = this.__getOutputFile();
201224
this.__filesTree.loadFilePath(outFile.value);
202225
}
203226

204-
if (this.__isOutputFileSelectedFromLink()) {
227+
if (this.self().isOutputDownloadLink(this.getNode().getOutputs())) {
205228
const outFile = this.__getOutputFile();
206229
this.getChildControl("downloadLink").setValue(outFile.value["downloadLink"]);
207230
}
@@ -262,30 +285,8 @@ qx.Class.define("osparc.file.FilePicker", {
262285
}
263286
},
264287

265-
__isOutputFileSelectedFromStore: function() {
266-
const outFile = this.__getOutputFile();
267-
if (outFile &&
268-
"value" in outFile &&
269-
typeof outFile["value"] === "object" &&
270-
"path" in outFile["value"]) {
271-
return true;
272-
}
273-
return false;
274-
},
275-
276-
__isOutputFileSelectedFromLink: function() {
277-
const outFile = this.__getOutputFile();
278-
if (outFile &&
279-
"value" in outFile &&
280-
typeof outFile["value"] === "object" &&
281-
"downloadLink" in outFile.value) {
282-
return true;
283-
}
284-
return false;
285-
},
286-
287288
__checkSelectedFileIsListed: function() {
288-
if (this.__isOutputFileSelectedFromStore()) {
289+
if (this.self().isOutputFromStore(this.getNode().getOutputs())) {
289290
const outFile = this.__getOutputFile();
290291
this.__filesTree.setSelectedFile(outFile.value.path);
291292
this.__filesTree.fireEvent("selectionChanged");

services/web/client/source/class/osparc/navigation/NavigationBar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ qx.Class.define("osparc.navigation.NavigationBar", {
267267
const context = ["workbench", "slideshow"].includes(this.getPageContext());
268268
if (areSlidesEnabled && context) {
269269
const study = this.getStudy();
270-
if (Object.keys(study.getUi().getSlideshow()).length) {
270+
if (study && Object.keys(study.getUi().getSlideshow()).length) {
271271
if (this.getPageContext() === "slideshow") {
272272
this.__startSlidesBtn.exclude();
273273
this.__stopSlidesBtn.show();

services/web/client/source/class/osparc/ui/basic/NodeStatusUI.js

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -142,27 +142,30 @@ qx.Class.define("osparc.ui.basic.NodeStatusUI", {
142142
},
143143

144144
__setupFilepicker: function() {
145-
const node = this.__node;
146-
this.__node.getStatus().bind("progress", this.__icon, "source", {
147-
converter: progress => {
148-
if (progress === 100) {
145+
this.__node.bind("outputs", this.__icon, "source", {
146+
converter: outputs => {
147+
if (osparc.file.FilePicker.getOutput(outputs)) {
149148
return "@FontAwesome5Solid/check/12";
150149
}
151150
return "@FontAwesome5Solid/file/12";
152151
},
153152
onUpdate: (source, target) => {
154-
if (source.getProgress() === 100) {
153+
if (osparc.file.FilePicker.getOutput(source.getOutputs())) {
155154
target.setTextColor("ready-green");
156155
} else {
157156
target.resetTextColor();
158157
}
159158
}
160159
});
161160

162-
this.__node.getStatus().bind("progress", this.__label, "value", {
163-
converter: progress => {
164-
if (progress === 100) {
165-
return osparc.file.FilePicker.getOutputLabel(node.getOutputs());
161+
this.__node.bind("outputs", this.__label, "value", {
162+
converter: outputs => {
163+
if (osparc.file.FilePicker.getOutput(outputs)) {
164+
const outputLabel = osparc.file.FilePicker.getOutputLabel(outputs);
165+
if (outputLabel === "" && osparc.file.FilePicker.isOutputDownloadLink(outputs)) {
166+
return osparc.file.FilePicker.extractLabelFromLink(outputs);
167+
}
168+
return outputLabel;
166169
}
167170
return this.tr("Select a file");
168171
}

0 commit comments

Comments
 (0)