From 9c665e712e06947bbb5a00f7e69fd0d4f9e36a1a Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 12 Mar 2019 22:32:20 -0400 Subject: [PATCH 01/38] Add data dialog to tool form data selector --- client/galaxy/scripts/mvc/ui/ui-options.js | 2 +- .../scripts/mvc/ui/ui-select-content.js | 103 ++++++++++++------ client/galaxy/style/scss/ui.scss | 6 - 3 files changed, 68 insertions(+), 43 deletions(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-options.js b/client/galaxy/scripts/mvc/ui/ui-options.js index 7b7ab975cba6..76a49bf6b8d9 100644 --- a/client/galaxy/scripts/mvc/ui/ui-options.js +++ b/client/galaxy/scripts/mvc/ui/ui-options.js @@ -286,7 +286,7 @@ RadioButton.View = Base.extend({ /** Main template function */ _template: function() { - return $("
").addClass("btn-group ui-radiobutton"); + return $("
").addClass("btn-group ui-radiobutton d-flex"); } }); diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index b70c3eb6a8cb..93518933569a 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -18,14 +18,15 @@ var Configurations = { icon: "fa-file-o", tooltip: _l("Single dataset"), multiple: false, - batch: Batch.DISABLED + batch: Batch.ENABLED, + showdialog: true }, { src: "hda", icon: "fa-files-o", tooltip: _l("Multiple datasets"), multiple: true, - batch: Batch.LINKED + batch: Batch.ENABLED }, { src: "hdca", @@ -149,28 +150,11 @@ var View = Backbone.View.extend({ } ] }); - var $batch_div = $("
") - .addClass("form-text text-muted") - .append($("").addClass("fa fa-sitemap")) - .append( - $("").html( - "This is a batch mode input field. Separate jobs will be triggered for each dataset selection." - ) - ); this.$batch = { - linked: $batch_div.clone(), - enabled: $batch_div + linked: $(this._templateBatch()).clone(), + enabled: $(this._templateBatch()) .clone() - .append( - $("
") - .append( - $("
") - .addClass("ui-form-title") - .html("Batch options:") - ) - .append(this.button_product.$el) - ) - .append($("
").css("clear", "both")) + .append(this.button_product.$el) }; // add drag-drop event handlers @@ -234,7 +218,7 @@ var View = Backbone.View.extend({ /** Return the currently selected dataset values */ value: function(new_value) { - let Galaxy = getGalaxyInstance(); + let galaxy = getGalaxyInstance(); new_value !== undefined && this.model.set("value", new_value); var current = this.model.get("current"); if (this.config[current]) { @@ -248,7 +232,7 @@ var View = Backbone.View.extend({ if (details) { result.values.push(details); } else { - Galaxy.emit.debug( + galaxy.emit.debug( "ui-select-content::value()", `Requested details not found for '${id_list[i]}'.` ); @@ -260,7 +244,7 @@ var View = Backbone.View.extend({ } } } else { - Galaxy.emit.debug("ui-select-content::value()", `Invalid value/source '${new_value}'.`); + galaxy.emit.debug("ui-select-content::value()", `Invalid value/source '${new_value}'.`); } return null; }, @@ -269,11 +253,21 @@ var View = Backbone.View.extend({ _changeCurrent: function() { var self = this; _.each(this.fields, (field, i) => { + let cnf = self.config[i]; if (self.model.get("current") == i) { field.$el.show(); _.each(self.$batch, ($batchfield, batchmode) => { - $batchfield[self.config[i].batch == batchmode ? "show" : "hide"](); + if (cnf.batch == batchmode) { + $batchfield.show(); + } else { + $batchfield.hide(); + } }); + if (cnf.showdialog) { + self.button_dialog.show(); + } else { + self.button_dialog.hide(); + } self.button_type.value(i); } else { field.$el.hide(); @@ -283,8 +277,8 @@ var View = Backbone.View.extend({ /** Change of type */ _changeType: function() { - let Galaxy = getGalaxyInstance(); - var self = this; + let self = this; + let galaxy = getGalaxyInstance(); // identify selector type identifier i.e. [ flavor ]_[ type ]_[ multiple ] var config_id = @@ -295,7 +289,7 @@ var View = Backbone.View.extend({ this.config = Configurations[config_id]; } else { this.config = Configurations["data"]; - Galaxy.emit.debug("ui-select-content::_changeType()", `Invalid configuration/type id '${config_id}'.`); + galaxy.emit.debug("ui-select-content::_changeType()", `Invalid configuration/type id '${config_id}'.`); } // prepare extension component of error message @@ -303,7 +297,7 @@ var View = Backbone.View.extend({ var extensions = Utils.textify(this.model.get("extensions")); var src_labels = this.model.get("src_labels"); - // build views + // build radio button for data selectors this.fields = []; this.button_data = []; _.each(this.config, (c, i) => { @@ -335,18 +329,45 @@ var View = Backbone.View.extend({ } }); + // build data dialog button + this.button_dialog = new Ui.Button({ + icon: "fa-folder-open-o", + title: "Browse Datasets", + cls: "mt-2 mb-2 float-left", + onclick: () => { + galaxy.data.dialog(id => { + this.model.set("value", { + values: [{ src: "hda", id: id }] + }); + this.model.trigger("change:value"); + }, { + multiple: false, + format: null + }); + } + }); + // append views - this.$el.empty(); - var button_width = 0; + let $left = $("
"); + let $right = $("
"); + this.$el.empty() + .append("
") + .addClass("d-flex flex-row") + .append($left) + .append($right); if (this.fields.length > 1) { - this.$el.append(this.button_type.$el); - button_width = `${Math.max(0, this.fields.length * 40)}px`; + $left.addClass("mr-2").append( + this.button_type.$el + ); } _.each(this.fields, field => { - self.$el.append(field.$el.css({ "margin-left": button_width })); + $right.append(field.$el); }); + $right.append( + this.button_dialog.$el + ); _.each(this.$batch, ($batchfield, batchmode) => { - self.$el.append($batchfield.css({ "margin-left": button_width })); + $right.append($batchfield); }); this.model.set("current", 0); this._changeCurrent(); @@ -487,6 +508,16 @@ var View = Backbone.View.extend({ } } return result; + }, + + /** Template for batch mode execution options */ + _templateBatch: function() { + return `
+ + + This is a batch mode input field. Separate jobs will be triggered for each dataset selection. + +
`; } }); diff --git a/client/galaxy/style/scss/ui.scss b/client/galaxy/style/scss/ui.scss index 1e2847c840f6..243dee8611d1 100644 --- a/client/galaxy/style/scss/ui.scss +++ b/client/galaxy/style/scss/ui.scss @@ -449,12 +449,6 @@ $ui-margin-horizontal-large: $margin-v * 2; } } -.ui-select-content { - .ui-options { - @extend .float-left; - } -} - .ui-dragover { border-radius: 3px; border: 2px solid $table-border-color; From b63ead0b0b8231ead30794481c8f5b640461adbb Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 13 Mar 2019 20:41:35 -0400 Subject: [PATCH 02/38] Add data dialog browsing option to multiple selector --- .../galaxy/scripts/mvc/ui/ui-select-content.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index 93518933569a..58668e486472 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -26,7 +26,8 @@ var Configurations = { icon: "fa-files-o", tooltip: _l("Multiple datasets"), multiple: true, - batch: Batch.ENABLED + batch: Batch.ENABLED, + showdialog: true }, { src: "hdca", @@ -335,13 +336,18 @@ var View = Backbone.View.extend({ title: "Browse Datasets", cls: "mt-2 mb-2 float-left", onclick: () => { - galaxy.data.dialog(id => { - this.model.set("value", { - values: [{ src: "hda", id: id }] + let current = this.model.get("current"); + let cnf = this.config[current]; + galaxy.data.dialog(response => { + let values = []; + let ids = $.isArray(response) ? response : [response]; + _.each(ids, id => { + values.push({ id: id, src: "hda" }); }); + this.model.set("value", { values: values }); this.model.trigger("change:value"); }, { - multiple: false, + multiple: cnf.multiple, format: null }); } From 849203ea37d43b357f3d83e65f40fec04cb61d13 Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 13 Mar 2019 21:05:28 -0400 Subject: [PATCH 03/38] Reuse drag/drop mechanism for data dialog and value highlighting --- .../galaxy/scripts/components/DataDialog.vue | 4 +- .../scripts/mvc/ui/ui-select-content.js | 40 +++++++++---------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/client/galaxy/scripts/components/DataDialog.vue b/client/galaxy/scripts/components/DataDialog.vue index 6e30d3a5c870..e493460df869 100644 --- a/client/galaxy/scripts/components/DataDialog.vue +++ b/client/galaxy/scripts/components/DataDialog.vue @@ -162,10 +162,12 @@ export default { done: function() { let results = []; Object.values(this.values).forEach(v => { - let value = v.id; + let value = null; if (this.format == "url") { let host = `${window.location.protocol}//${window.location.hostname}:${window.location.port}`; value = `${host}/api/histories/${v.history_id}/contents/${value}/display`; + } else { + value = v; } results.push(value); }); diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index 58668e486472..065b63a702ea 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -339,13 +339,10 @@ var View = Backbone.View.extend({ let current = this.model.get("current"); let cnf = this.config[current]; galaxy.data.dialog(response => { - let values = []; - let ids = $.isArray(response) ? response : [response]; - _.each(ids, id => { - values.push({ id: id, src: "hda" }); + let values = $.isArray(response) ? response : [response]; + _.each(values, v => { + this._handleDropValues(v); }); - this.model.set("value", { values: values }); - this.model.trigger("change:value"); }, { multiple: cnf.multiple, format: null @@ -441,21 +438,27 @@ var View = Backbone.View.extend({ /** Handles drop events e.g. from history panel */ _handleDrop: function(ev) { + let drop_data = JSON.parse(ev.dataTransfer.getData("text"))[0]; + this._handleDropValues(drop_data); + ev.preventDefault(); + }, + + /** Add values from drag/drop */ + _handleDropValues: function(drop_data) { try { - var data = this.model.get("data"); - var current = this.model.get("current"); - var config = this.config[current]; - var field = this.fields[current]; - var drop_data = JSON.parse(ev.dataTransfer.getData("text"))[0]; - var new_id = drop_data.id; - var new_src = drop_data.history_content_type == "dataset_collection" ? "hdca" : "hda"; - var new_value = { id: new_id, src: new_src }; - if (data && drop_data.history_id) { + let data = this.model.get("data"); + let current = this.model.get("current"); + let config = this.config[current]; + let field = this.fields[current]; + let new_id = drop_data.id; + let new_src = drop_data.history_content_type == "dataset_collection" ? "hdca" : "hda"; + let new_value = { id: new_id, src: new_src }; + if (data) { if (!_.findWhere(data[new_src], new_value)) { data[new_src].push({ id: new_id, src: new_src, - hid: drop_data.hid || "Dropped", + hid: drop_data.hid || "Selected", name: drop_data.hid ? drop_data.name : new_id, keep: true, tags: [] @@ -477,14 +480,11 @@ var View = Backbone.View.extend({ this.model.trigger("change:value"); } this.trigger("change"); - this._handleDropStatus("success"); - } else { - this._handleDropStatus("danger"); } + this._handleDropStatus("success"); } catch (e) { this._handleDropStatus("danger"); } - ev.preventDefault(); }, /** Highlight drag result */ From 3ba6d5eecb1ab3470fc206939bf121cd9d9c5830 Mon Sep 17 00:00:00 2001 From: guerler Date: Thu, 14 Mar 2019 01:43:28 -0400 Subject: [PATCH 04/38] Augment drop value handler to properly process single/multiple values --- .../scripts/mvc/ui/ui-select-content.js | 82 ++++++++++++------- 1 file changed, 51 insertions(+), 31 deletions(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index 065b63a702ea..d422d669bb77 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -18,7 +18,7 @@ var Configurations = { icon: "fa-file-o", tooltip: _l("Single dataset"), multiple: false, - batch: Batch.ENABLED, + batch: Batch.DISABLED, showdialog: true }, { @@ -26,7 +26,7 @@ var Configurations = { icon: "fa-files-o", tooltip: _l("Multiple datasets"), multiple: true, - batch: Batch.ENABLED, + batch: Batch.LINKED, showdialog: true }, { @@ -339,10 +339,7 @@ var View = Backbone.View.extend({ let current = this.model.get("current"); let cnf = this.config[current]; galaxy.data.dialog(response => { - let values = $.isArray(response) ? response : [response]; - _.each(values, v => { - this._handleDropValues(v); - }); + this._handleDropValues(response, false); }, { multiple: cnf.multiple, format: null @@ -443,46 +440,69 @@ var View = Backbone.View.extend({ ev.preventDefault(); }, + /** Source helper matches history_content_types to source types */ + _getSource: function(v) { + return v.history_content_type == "dataset_collection" ? "hdca" : "hda"; + }, + /** Add values from drag/drop */ - _handleDropValues: function(drop_data) { + _handleDropValues: function(drop_data, drop_partial=true) { try { let data = this.model.get("data"); let current = this.model.get("current"); let config = this.config[current]; let field = this.fields[current]; - let new_id = drop_data.id; - let new_src = drop_data.history_content_type == "dataset_collection" ? "hdca" : "hda"; - let new_value = { id: new_id, src: new_src }; if (data) { - if (!_.findWhere(data[new_src], new_value)) { - data[new_src].push({ - id: new_id, - src: new_src, - hid: drop_data.hid || "Selected", - name: drop_data.hid ? drop_data.name : new_id, - keep: true, - tags: [] + let values = $.isArray(drop_data) ? drop_data : [drop_data]; + if (values.length > 0) { + let data_changed = false; + _.each(values, v => { + let new_id = v.id; + let new_src = v.src = this._getSource(v); + let new_value = { id: new_id, src: new_src }; + if (!_.findWhere(data[new_src], new_value)) { + data_changed = true; + data[new_src].push({ + id: new_id, + src: new_src, + hid: v.hid || "Selected", + name: v.hid ? v.name : new_id, + keep: true, + tags: [] + }); + } }); - this._changeData(); - } - if (config.src == new_src) { - var current_value = field.value(); - if (current_value && config.multiple) { - if (current_value.indexOf(new_id) == -1) { - current_value.push(new_id); + if (data_changed) { + this._changeData(); + } + let first_id = values[0].id; + let first_src = values[0].src; + if (config.src == first_src && drop_partial) { + var current_value = field.value(); + if (current_value && config.multiple) { + _.each(values, v => { + if (current_value.indexOf(v.id) == -1) { + current_value.push(v.id); + } + }); + } else { + current_value = first_id; } + field.value(current_value); } else { - current_value = new_id; + this.model.set("value", { values: values }); + this.model.trigger("change:value"); } - field.value(current_value); - } else { - this.model.set("value", { values: [new_value] }); - this.model.trigger("change:value"); + this.trigger("change"); } - this.trigger("change"); } this._handleDropStatus("success"); } catch (e) { + let galaxy = getGalaxyInstance(); + galaxy.emit.debug( + "ui-select-content::_handleDropValues()", + "Selected value could not be applied to data selector." + ); this._handleDropStatus("danger"); } }, From 8dd4cb180ba5264c7925643307f3f728d01f4226 Mon Sep 17 00:00:00 2001 From: guerler Date: Mon, 18 Mar 2019 15:39:08 -0400 Subject: [PATCH 05/38] Add pagination to dialog dataset table --- client/galaxy/scripts/components/DataDialog.vue | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/galaxy/scripts/components/DataDialog.vue b/client/galaxy/scripts/components/DataDialog.vue index e493460df869..d93bfedd8c54 100644 --- a/client/galaxy/scripts/components/DataDialog.vue +++ b/client/galaxy/scripts/components/DataDialog.vue @@ -17,6 +17,8 @@ :items="formatedItems" :fields="fields" :filter="filter" + :per-page="perPage" + :current-page="currentPage" @row-clicked="clicked" @filtered="filtered" > @@ -42,6 +44,11 @@ +
No search results found for: {{ this.filter }} Date: Tue, 19 Mar 2019 02:37:05 -0400 Subject: [PATCH 06/38] Properly link filter to pagination --- client/galaxy/scripts/components/DataDialog.vue | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/galaxy/scripts/components/DataDialog.vue b/client/galaxy/scripts/components/DataDialog.vue index d93bfedd8c54..b165792a8f55 100644 --- a/client/galaxy/scripts/components/DataDialog.vue +++ b/client/galaxy/scripts/components/DataDialog.vue @@ -44,10 +44,10 @@ -
@@ -139,9 +139,6 @@ export default { } } return this.items; - }, - rows() { - return this.items.length } }, created: function() { @@ -153,6 +150,7 @@ export default { }, filtered: function(items) { this.nItems = items.length; + this.currentPage = 1 }, clicked: function(record) { if (this.isDataset(record)) { @@ -208,6 +206,7 @@ export default { .then(response => { this.items = []; this.stack = [response.data]; + this.filter = null; while (this.stack.length > 0) { let root = this.stack.pop(); if (Array.isArray(root)) { From a46988a0d375dbac4f371f199b51f4150f77bd7e Mon Sep 17 00:00:00 2001 From: guerler Date: Tue, 19 Mar 2019 14:19:49 -0400 Subject: [PATCH 07/38] Fix width of select fields --- client/galaxy/scripts/mvc/ui/ui-select-content.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index d422d669bb77..581bb2a53e34 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -349,7 +349,7 @@ var View = Backbone.View.extend({ // append views let $left = $("
"); - let $right = $("
"); + let $right = $("
").addClass("w-100"); this.$el.empty() .append("
") .addClass("d-flex flex-row") From ee469a929b0647ee3473573a16bc374cd1a6b158 Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 20 Mar 2019 15:35:52 -0400 Subject: [PATCH 08/38] Adjust white space handling in data selectors --- client/galaxy/scripts/mvc/ui/ui-select-content.js | 1 - client/galaxy/style/scss/ui.scss | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-select-content.js b/client/galaxy/scripts/mvc/ui/ui-select-content.js index 581bb2a53e34..c581485474b4 100644 --- a/client/galaxy/scripts/mvc/ui/ui-select-content.js +++ b/client/galaxy/scripts/mvc/ui/ui-select-content.js @@ -351,7 +351,6 @@ var View = Backbone.View.extend({ let $left = $("
"); let $right = $("
").addClass("w-100"); this.$el.empty() - .append("
") .addClass("d-flex flex-row") .append($left) .append($right); diff --git a/client/galaxy/style/scss/ui.scss b/client/galaxy/style/scss/ui.scss index 243dee8611d1..5d19dd672796 100644 --- a/client/galaxy/style/scss/ui.scss +++ b/client/galaxy/style/scss/ui.scss @@ -421,6 +421,9 @@ $ui-margin-horizontal-large: $margin-v * 2; -webkit-appearance: none; -moz-border-radius: $border-radius-base; line-height: 1.5rem; + .select2-chosen { + white-space: normal; + } .select2-arrow { display: none; } From 23e6bb715f7447167cfe2f6f1c1a177b85881d1f Mon Sep 17 00:00:00 2001 From: guerler Date: Wed, 20 Mar 2019 16:16:55 -0400 Subject: [PATCH 09/38] Fix visibility handling in options, right align browser button --- client/galaxy/scripts/mvc/ui/ui-options.js | 14 ++++++++- .../scripts/mvc/ui/ui-select-content.js | 30 +++++++++---------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/client/galaxy/scripts/mvc/ui/ui-options.js b/client/galaxy/scripts/mvc/ui/ui-options.js index 76a49bf6b8d9..03fe661287a1 100644 --- a/client/galaxy/scripts/mvc/ui/ui-options.js +++ b/client/galaxy/scripts/mvc/ui/ui-options.js @@ -12,6 +12,7 @@ var Base = Backbone.View.extend({ (options && options.model) || new Backbone.Model({ visible: true, + cls: null, data: [], id: Utils.uid(), error_text: "No options available.", @@ -36,6 +37,7 @@ var Base = Backbone.View.extend({ .empty() .removeClass() .addClass("ui-options") + .addClass(this.model.get("cls")) .append((this.$message = $("
").addClass("mt-2"))) .append((this.$menu = $("
").addClass("ui-options-menu"))) .append((this.$options = $(this._template()))); @@ -154,6 +156,16 @@ var Base = Backbone.View.extend({ return this.$(".ui-option").length; }, + /** Shows the options */ + show: function() { + this.model.set("visible", true); + }, + + /** Hides the options */ + hide: function() { + this.model.set("visible", false); + }, + /** Set value to dom */ _setValue: function(new_value) { var self = this; @@ -260,7 +272,7 @@ RadioButton.View = Base.extend({ /** Template for a single option */ _templateOption: function(pair) { - var $el = $("