mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'dev' into visualization_header
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
import * as _ from "libs/underscore";
|
||||
import * as Backbone from "libs/backbone";
|
||||
import util_mod from "viz/trackster/util";
|
||||
import config_mod from "utils/config";
|
||||
|
||||
/* global $ */
|
||||
/* global Galaxy */
|
||||
|
||||
/**
|
||||
* A configuration setting. Currently key is used as id.
|
||||
*/
|
||||
@@ -307,23 +311,22 @@ var ConfigSettingCollectionView = Backbone.View.extend({
|
||||
// No propagation to avoid triggering document click (and tip hiding) above.
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
var // Icon for setting a new random color; behavior set below.
|
||||
new_color_icon = $("<a href='javascript:void(0)'/>")
|
||||
// Icon for setting a new random color; behavior set below.
|
||||
var new_color_icon = $("<a href='javascript:void(0)'/>")
|
||||
.addClass("icon-button arrow-circle")
|
||||
.appendTo(container_div)
|
||||
.attr("title", "Set new random color")
|
||||
.tooltip();
|
||||
|
||||
var // Color picker in tool tip style.
|
||||
tip = $("<div class='tooltip right' style='position: absolute;' />")
|
||||
// Color picker in tool tip style.
|
||||
var tip = $("<div class='tooltip right' style='position: absolute;' />")
|
||||
.appendTo(container_div)
|
||||
.hide();
|
||||
|
||||
var // Inner div for padding purposes
|
||||
tip_inner = $("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(tip);
|
||||
// Inner div for padding purposes
|
||||
var tip_inner = $("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(tip);
|
||||
|
||||
var tip_arrow = $("<div class='tooltip-arrow'></div>").appendTo(tip);
|
||||
$("<div class='tooltip-arrow'></div>").appendTo(tip);
|
||||
|
||||
var farb_obj = $.farbtastic(tip_inner, {
|
||||
width: 100,
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import _l from "utils/localization";
|
||||
/**
|
||||
* Top-level trackster code, used for creating/loading visualizations and user interface elements.
|
||||
*/
|
||||
//import * as $ from 'jquery';
|
||||
import _l from "utils/localization";
|
||||
import * as _ from "libs/underscore";
|
||||
import * as Backbone from "libs/backbone";
|
||||
import tracks from "viz/trackster/tracks";
|
||||
import visualization from "viz/visualization";
|
||||
import mod_icon_btn from "mvc/ui/icon-button";
|
||||
import IconButton from "mvc/ui/icon-button";
|
||||
import query_string from "utils/query-string-parsing";
|
||||
import GridView from "mvc/grid/grid-view";
|
||||
import mod_utils from "utils/utils";
|
||||
import Utils from "utils/utils";
|
||||
import "libs/jquery/jquery.event.drag";
|
||||
import "libs/jquery/jquery.event.hover";
|
||||
import "libs/jquery/jquery.mousewheel";
|
||||
@@ -20,44 +20,36 @@ import "libs/jquery/jquery.form";
|
||||
import "libs/jquery/jquery.rating";
|
||||
import "ui/editable-text";
|
||||
|
||||
// trackster global variables
|
||||
var ui = null;
|
||||
var view = null;
|
||||
var browser_router = null;
|
||||
|
||||
/**
|
||||
* Base Object/Model for inhertiance.
|
||||
*/
|
||||
var Base = function() {
|
||||
if (this.initialize) {
|
||||
this.initialize.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
Base.extend = Backbone.Model.extend;
|
||||
/* global Galaxy */
|
||||
/* global $ */
|
||||
|
||||
/**
|
||||
* User interface controls for trackster
|
||||
*/
|
||||
var TracksterUI = Base.extend({
|
||||
initialize: function(baseURL) {
|
||||
mod_utils.cssLoadFile("static/style/jquery.rating.css");
|
||||
mod_utils.cssLoadFile("static/style/autocomplete_tagging.css");
|
||||
mod_utils.cssLoadFile("static/style/jquery-ui/smoothness/jquery-ui.css");
|
||||
mod_utils.cssLoadFile("static/style/library.css");
|
||||
mod_utils.cssLoadFile("static/style/trackster.css");
|
||||
class TracksterUI extends Backbone.Model {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
initialize(baseURL) {
|
||||
this.baseURL = baseURL;
|
||||
},
|
||||
Utils.cssLoadFile("static/style/jquery.rating.css");
|
||||
Utils.cssLoadFile("static/style/autocomplete_tagging.css");
|
||||
Utils.cssLoadFile("static/style/jquery-ui/smoothness/jquery-ui.css");
|
||||
Utils.cssLoadFile("static/style/library.css");
|
||||
Utils.cssLoadFile("static/style/trackster.css");
|
||||
}
|
||||
|
||||
/**
|
||||
* Save visualization, returning a Deferred object for the remote call to save.
|
||||
*/
|
||||
save_viz: function() {
|
||||
save_viz() {
|
||||
// show dialog
|
||||
Galaxy.modal.show({ title: "Saving...", body: "progress" });
|
||||
|
||||
// Save bookmarks.
|
||||
var bookmarks = [];
|
||||
$(".bookmark").each(function() {
|
||||
$(".bookmark").each(() => {
|
||||
bookmarks.push({
|
||||
position: $(this)
|
||||
.children(".position")
|
||||
@@ -69,14 +61,16 @@ var TracksterUI = Base.extend({
|
||||
});
|
||||
|
||||
// FIXME: give unique IDs to Drawables and save overview as ID.
|
||||
var overview_track_name = view.overview_drawable ? view.overview_drawable.config.get_value("name") : null;
|
||||
var overview_track_name = this.view.overview_drawable
|
||||
? this.view.overview_drawable.config.get_value("name")
|
||||
: null;
|
||||
|
||||
var viz_config = {
|
||||
view: view.to_dict(),
|
||||
view: this.view.to_dict(),
|
||||
viewport: {
|
||||
chrom: view.chrom,
|
||||
start: view.low,
|
||||
end: view.high,
|
||||
chrom: this.view.chrom,
|
||||
start: this.view.low,
|
||||
end: this.view.high,
|
||||
overview: overview_track_name
|
||||
},
|
||||
bookmarks: bookmarks
|
||||
@@ -88,17 +82,17 @@ var TracksterUI = Base.extend({
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {
|
||||
id: view.vis_id,
|
||||
title: view.config.get_value("name"),
|
||||
dbkey: view.dbkey,
|
||||
id: this.view.vis_id,
|
||||
title: this.view.config.get_value("name"),
|
||||
dbkey: this.view.dbkey,
|
||||
type: "trackster",
|
||||
vis_json: JSON.stringify(viz_config)
|
||||
}
|
||||
})
|
||||
.success(vis_info => {
|
||||
Galaxy.modal.hide();
|
||||
view.vis_id = vis_info.vis_id;
|
||||
view.has_changes = false;
|
||||
this.view.vis_id = vis_info.vis_id;
|
||||
this.view.has_changes = false;
|
||||
|
||||
// Needed to set URL when first saving a visualization.
|
||||
window.history.pushState({}, "", vis_info.url + window.top.location.hash);
|
||||
@@ -109,29 +103,27 @@ var TracksterUI = Base.extend({
|
||||
title: _l("Could Not Save"),
|
||||
body: "Could not save visualization. Please try again later.",
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
Cancel: () => {
|
||||
Galaxy.modal.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Create button menu
|
||||
*/
|
||||
createButtonMenu: function() {
|
||||
var self = this;
|
||||
|
||||
var menu = mod_icon_btn.create_icon_buttons_menu(
|
||||
createButtonMenu() {
|
||||
var menu = IconButton.create_icon_buttons_menu(
|
||||
[
|
||||
{
|
||||
icon_class: "plus-button",
|
||||
title: _l("Add tracks"),
|
||||
on_click: function() {
|
||||
visualization.select_datasets({ dbkey: view.dbkey }, new_tracks => {
|
||||
on_click: () => {
|
||||
visualization.select_datasets({ dbkey: this.view.dbkey }, new_tracks => {
|
||||
_.each(new_tracks, track => {
|
||||
view.add_drawable(tracks.object_from_template(track, view, view));
|
||||
this.view.add_drawable(tracks.object_from_template(track, this.view, this.view));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -139,9 +131,9 @@ var TracksterUI = Base.extend({
|
||||
{
|
||||
icon_class: "block--plus",
|
||||
title: _l("Add group"),
|
||||
on_click: function() {
|
||||
view.add_drawable(
|
||||
new tracks.DrawableGroup(view, view, {
|
||||
on_click: () => {
|
||||
this.view.add_drawable(
|
||||
new tracks.DrawableGroup(this.view, this.view, {
|
||||
name: "New Group"
|
||||
})
|
||||
);
|
||||
@@ -150,7 +142,7 @@ var TracksterUI = Base.extend({
|
||||
{
|
||||
icon_class: "bookmarks",
|
||||
title: _l("Bookmarks"),
|
||||
on_click: function() {
|
||||
on_click: () => {
|
||||
// HACK -- use style to determine if panel is hidden and hide/show accordingly.
|
||||
window.force_right_panel($("div#right").css("right") == "0px" ? "hide" : "show");
|
||||
}
|
||||
@@ -158,22 +150,22 @@ var TracksterUI = Base.extend({
|
||||
{
|
||||
icon_class: "globe",
|
||||
title: _l("Circster"),
|
||||
on_click: function() {
|
||||
window.top.location = `${self.baseURL}visualization/circster?id=${view.vis_id}`;
|
||||
on_click: () => {
|
||||
window.top.location = `${this.baseURL}visualization/circster?id=${this.view.vis_id}`;
|
||||
}
|
||||
},
|
||||
{
|
||||
icon_class: "disk--arrow",
|
||||
title: _l("Save"),
|
||||
on_click: function() {
|
||||
self.save_viz();
|
||||
on_click: () => {
|
||||
this.save_viz();
|
||||
}
|
||||
},
|
||||
{
|
||||
icon_class: "cross-circle",
|
||||
title: _l("Close"),
|
||||
on_click: function() {
|
||||
self.handle_unsaved_changes(view);
|
||||
on_click: () => {
|
||||
this.handle_unsaved_changes(this.view);
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -184,12 +176,12 @@ var TracksterUI = Base.extend({
|
||||
|
||||
this.buttonMenu = menu;
|
||||
return menu;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bookmark.
|
||||
*/
|
||||
add_bookmark: function(position, annotation, editable) {
|
||||
add_bookmark(position, annotation, editable) {
|
||||
// Create HTML.
|
||||
var bookmarks_container = $("#right .unified-panel-body");
|
||||
|
||||
@@ -201,11 +193,12 @@ var TracksterUI = Base.extend({
|
||||
.addClass("position")
|
||||
.appendTo(new_bookmark);
|
||||
|
||||
var position_link = $("<a href=''/>")
|
||||
//position_link
|
||||
$("<a href=''/>")
|
||||
.text(position)
|
||||
.appendTo(position_div)
|
||||
.click(() => {
|
||||
view.go_to(position);
|
||||
this.view.go_to(position);
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -222,11 +215,12 @@ var TracksterUI = Base.extend({
|
||||
// Remove bookmark.
|
||||
new_bookmark.slideUp("fast");
|
||||
new_bookmark.remove();
|
||||
view.has_changes = true;
|
||||
this.view.has_changes = true;
|
||||
return false;
|
||||
});
|
||||
|
||||
var delete_icon = $("<a href=''/>")
|
||||
// delete_icon
|
||||
$("<a href=''/>")
|
||||
.addClass("icon-button delete")
|
||||
.appendTo(delete_icon_container);
|
||||
|
||||
@@ -239,56 +233,50 @@ var TracksterUI = Base.extend({
|
||||
.addClass("annotation");
|
||||
}
|
||||
|
||||
view.has_changes = true;
|
||||
this.view.has_changes = true;
|
||||
return new_bookmark;
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a complete Trackster visualization. Returns view.
|
||||
*/
|
||||
create_visualization: function(view_config, viewport_config, drawables_config, bookmarks_config, editable) {
|
||||
create_visualization(view_config, viewport_config, drawables_config, bookmarks_config, editable) {
|
||||
// Create view.
|
||||
var self = this;
|
||||
this.view = new tracks.TracksterView(_.extend(view_config, { header: false }));
|
||||
this.view.editor = true;
|
||||
|
||||
view = new tracks.TracksterView(_.extend(view_config, { header: false }));
|
||||
|
||||
view.editor = true;
|
||||
$.when(view.load_chroms_deferred).then(chrom_info => {
|
||||
$.when(this.view.load_chroms_deferred).then(chrom_info => {
|
||||
var overview_drawable_name = null;
|
||||
// Viewport config.
|
||||
if (viewport_config) {
|
||||
var chrom = viewport_config.chrom;
|
||||
var start = viewport_config.start;
|
||||
var end = viewport_config.end;
|
||||
var overview_drawable_name = viewport_config.overview;
|
||||
overview_drawable_name = viewport_config.overview;
|
||||
|
||||
if (chrom && start !== undefined && end) {
|
||||
view.change_chrom(chrom, start, end);
|
||||
this.view.change_chrom(chrom, start, end);
|
||||
} else {
|
||||
// No valid viewport, so use first chromosome.
|
||||
view.change_chrom(chrom_info[0].chrom);
|
||||
this.view.change_chrom(chrom_info[0].chrom);
|
||||
}
|
||||
} else {
|
||||
// No viewport, so use first chromosome.
|
||||
view.change_chrom(chrom_info[0].chrom);
|
||||
this.view.change_chrom(chrom_info[0].chrom);
|
||||
}
|
||||
|
||||
// Add drawables to view.
|
||||
if (drawables_config) {
|
||||
// FIXME: can from_dict() be used to create view and add drawables?
|
||||
var drawable_config;
|
||||
|
||||
var drawable_type;
|
||||
var drawable;
|
||||
for (var i = 0; i < drawables_config.length; i++) {
|
||||
view.add_drawable(tracks.object_from_template(drawables_config[i], view, view));
|
||||
for (let i = 0; i < drawables_config.length; i++) {
|
||||
this.view.add_drawable(tracks.object_from_template(drawables_config[i], this.view, this.view));
|
||||
}
|
||||
}
|
||||
|
||||
// Set overview.
|
||||
var overview_drawable;
|
||||
for (var i = 0; i < view.drawables.length; i++) {
|
||||
if (view.drawables[i].config.get_value("name") === overview_drawable_name) {
|
||||
view.set_overview(view.drawables[i]);
|
||||
for (let i = 0; i < this.view.drawables.length; i++) {
|
||||
if (this.view.drawables[i].config.get_value("name") === overview_drawable_name) {
|
||||
this.view.set_overview(this.view.drawables[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -296,34 +284,35 @@ var TracksterUI = Base.extend({
|
||||
// Load bookmarks.
|
||||
if (bookmarks_config) {
|
||||
var bookmark;
|
||||
for (var i = 0; i < bookmarks_config.length; i++) {
|
||||
for (let i = 0; i < bookmarks_config.length; i++) {
|
||||
bookmark = bookmarks_config[i];
|
||||
self.add_bookmark(bookmark["position"], bookmark["annotation"], editable);
|
||||
this.add_bookmark(bookmark.position, bookmark.annotation, editable);
|
||||
}
|
||||
}
|
||||
|
||||
// View has no changes as of yet.
|
||||
view.has_changes = false;
|
||||
this.view.has_changes = false;
|
||||
});
|
||||
|
||||
// Final initialization.
|
||||
this.set_up_router({ view: view });
|
||||
this.set_up_router({ view: this.view });
|
||||
|
||||
return view;
|
||||
},
|
||||
// TODO: This is hopefully not necessary anymore, since we're using the instance view. Do it for compatibility for now.
|
||||
return this.view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up location router to use hashes as track browser locations.
|
||||
*/
|
||||
set_up_router: function(options) {
|
||||
set_up_router(options) {
|
||||
new visualization.TrackBrowserRouter(options);
|
||||
Backbone.history.start();
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up keyboard navigation for a visualization.
|
||||
*/
|
||||
init_keyboard_nav: function(view) {
|
||||
init_keyboard_nav(view) {
|
||||
// Keyboard navigation. Scroll ~7% of height when scrolling up/down.
|
||||
$(document).keyup(e => {
|
||||
// Do not navigate if arrow keys used in input element.
|
||||
@@ -337,39 +326,38 @@ var TracksterUI = Base.extend({
|
||||
view.move_fraction(0.25);
|
||||
break;
|
||||
case 38:
|
||||
var change = Math.round(view.viewport_container.height() / 15.0);
|
||||
// var change = Math.round(view.viewport_container.height() / 15.0);
|
||||
view.viewport_container.scrollTop(view.viewport_container.scrollTop() - 20);
|
||||
break;
|
||||
case 39:
|
||||
view.move_fraction(-0.25);
|
||||
break;
|
||||
case 40:
|
||||
var change = Math.round(view.viewport_container.height() / 15.0);
|
||||
// var change = Math.round(view.viewport_container.height() / 15.0);
|
||||
view.viewport_container.scrollTop(view.viewport_container.scrollTop() + 20);
|
||||
break;
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsaved changes in visualization.
|
||||
*/
|
||||
handle_unsaved_changes: function(view) {
|
||||
handle_unsaved_changes(view) {
|
||||
if (view.has_changes) {
|
||||
var self = this;
|
||||
Galaxy.modal.show({
|
||||
title: _l("Close visualization"),
|
||||
body: "There are unsaved changes to your visualization which will be lost if you do not save them.",
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
Cancel: () => {
|
||||
Galaxy.modal.hide();
|
||||
},
|
||||
"Leave without Saving": function() {
|
||||
"Leave without Saving": () => {
|
||||
$(window).off("beforeunload");
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
},
|
||||
Save: function() {
|
||||
$.when(self.save_viz()).then(() => {
|
||||
Save: () => {
|
||||
$.when(this.save_viz()).then(() => {
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
});
|
||||
}
|
||||
@@ -379,22 +367,25 @@ var TracksterUI = Base.extend({
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var TracksterView = Backbone.View.extend({
|
||||
class TracksterUIView extends Backbone.View {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
}
|
||||
// initalize trackster
|
||||
initialize: function() {
|
||||
initialize() {
|
||||
// load ui
|
||||
ui = new TracksterUI(Galaxy.root);
|
||||
this.ui = new TracksterUI(Galaxy.root);
|
||||
|
||||
// create button menu
|
||||
ui.createButtonMenu();
|
||||
this.ui.createButtonMenu();
|
||||
|
||||
// attach the button menu to the panel header and float it left
|
||||
ui.buttonMenu.$el.attr("style", "float: right");
|
||||
this.ui.buttonMenu.$el.attr("style", "float: right");
|
||||
|
||||
// add to center panel
|
||||
$("#center .unified-panel-header-inner").append(ui.buttonMenu.$el);
|
||||
$("#center .unified-panel-header-inner").append(this.ui.buttonMenu.$el);
|
||||
|
||||
// configure right panel
|
||||
$("#right .unified-panel-title").append("Bookmarks");
|
||||
@@ -404,7 +395,7 @@ var TracksterView = Backbone.View.extend({
|
||||
|
||||
// resize view when showing/hiding right panel (bookmarks for now).
|
||||
$("#right-border").click(() => {
|
||||
view.resize_window();
|
||||
this.ui.view.resize_window();
|
||||
});
|
||||
|
||||
// hide right panel
|
||||
@@ -418,10 +409,9 @@ var TracksterView = Backbone.View.extend({
|
||||
} else {
|
||||
this.view_new();
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
choose_existing_or_new: function() {
|
||||
var self = this;
|
||||
choose_existing_or_new() {
|
||||
var dbkey = query_string.get("dbkey");
|
||||
var listTracksParams = {};
|
||||
|
||||
@@ -442,21 +432,21 @@ var TracksterView = Backbone.View.extend({
|
||||
body: `<p><ul style='list-style: disc inside none'>You can add this dataset as:<li>a new track to one of your existing, saved Trackster sessions if they share the genome build: <b>${dbkey ||
|
||||
"Not available."}</b></li><li>or create a new session with this dataset as the only track</li></ul></p>`,
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
Cancel: () => {
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
"View in saved visualization": function() {
|
||||
self.view_in_saved(dataset_params);
|
||||
"View in saved visualization": () => {
|
||||
this.view_in_saved(dataset_params);
|
||||
},
|
||||
"View in new visualization": function() {
|
||||
self.view_new();
|
||||
"View in new visualization": () => {
|
||||
this.view_new();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// view
|
||||
view_in_saved: function(dataset_params) {
|
||||
view_in_saved(dataset_params) {
|
||||
var tracks_grid = new GridView({
|
||||
url_base: `${Galaxy.root}visualization/list_tracks`,
|
||||
embedded: true
|
||||
@@ -465,28 +455,28 @@ var TracksterView = Backbone.View.extend({
|
||||
title: _l("Add Data to Saved Visualization"),
|
||||
body: tracks_grid.$el,
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
Cancel: () => {
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
"Add to visualization": function() {
|
||||
$(parent.document)
|
||||
"Add to visualization": () => {
|
||||
$(window.parent.document)
|
||||
.find("input[name=id]:checked")
|
||||
.each(function() {
|
||||
.each(() => {
|
||||
dataset_params.id = $(this).val();
|
||||
window.top.location = `${Galaxy.root}visualization/trackster?${$.param(dataset_params)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// view
|
||||
view_existing: function() {
|
||||
view_existing() {
|
||||
// get config
|
||||
var viz_config = window.galaxy_config.app.viz_config;
|
||||
|
||||
// view
|
||||
view = ui.create_visualization(
|
||||
this.ui.create_visualization(
|
||||
{
|
||||
container: $("#center .unified-panel-body"),
|
||||
name: viz_config.title,
|
||||
@@ -501,31 +491,28 @@ var TracksterView = Backbone.View.extend({
|
||||
|
||||
// initialize editor
|
||||
this.init_editor();
|
||||
},
|
||||
}
|
||||
|
||||
// view
|
||||
view_new: function() {
|
||||
// reference this
|
||||
var self = this;
|
||||
|
||||
view_new() {
|
||||
// ajax
|
||||
$.ajax({
|
||||
url: `${Galaxy.root}api/genomes?chrom_info=True`,
|
||||
data: {},
|
||||
error: function() {
|
||||
error: () => {
|
||||
alert("Couldn't create new browser.");
|
||||
},
|
||||
success: function(response) {
|
||||
success: response => {
|
||||
// show dialog
|
||||
Galaxy.modal.show({
|
||||
title: _l("New Visualization"),
|
||||
body: self.template_view_new(response),
|
||||
body: this.template_view_new(response),
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
Cancel: () => {
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
Create: function() {
|
||||
self.create_browser($("#new-title").val(), $("#new-dbkey").val());
|
||||
Create: () => {
|
||||
this.create_browser($("#new-title").val(), $("#new-dbkey").val());
|
||||
Galaxy.modal.hide();
|
||||
}
|
||||
}
|
||||
@@ -548,10 +535,10 @@ var TracksterView = Backbone.View.extend({
|
||||
$("#overlay").css("overflow", "auto");
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
|
||||
// new browser form
|
||||
template_view_new: function(response) {
|
||||
template_view_new(response) {
|
||||
// start template
|
||||
var html =
|
||||
'<form id="new-browser-form" action="javascript:void(0);" method="post" onsubmit="return false;">' +
|
||||
@@ -568,7 +555,7 @@ var TracksterView = Backbone.View.extend({
|
||||
'<select name="dbkey" id="new-dbkey">';
|
||||
|
||||
// add dbkeys
|
||||
for (var i = 0; i < response.length; i++) {
|
||||
for (let i = 0; i < response.length; i++) {
|
||||
html += `<option value="${response[i][1]}">${response[i][0]}</option>`;
|
||||
}
|
||||
|
||||
@@ -579,13 +566,48 @@ var TracksterView = Backbone.View.extend({
|
||||
|
||||
// return
|
||||
return html;
|
||||
},
|
||||
}
|
||||
|
||||
// initialization for editor-specific functions.
|
||||
init_editor() {
|
||||
// set title
|
||||
$("#center .unified-panel-title").text(`${this.ui.view.config.get_value("name")} (${this.ui.view.dbkey})`);
|
||||
|
||||
// add dataset
|
||||
if (window.galaxy_config.app.add_dataset)
|
||||
$.ajax({
|
||||
url: `${Galaxy.root}api/datasets/${window.galaxy_config.app.add_dataset}`,
|
||||
data: { hda_ldda: "hda", data_type: "track_config" },
|
||||
dataType: "json",
|
||||
success: track_data => {
|
||||
this.ui.view.add_drawable(tracks.object_from_template(track_data, this.ui.view, this.ui.view));
|
||||
}
|
||||
});
|
||||
|
||||
// initialize icons
|
||||
$("#add-bookmark-button").click(() => {
|
||||
// add new bookmark.
|
||||
var position = `${this.ui.view.chrom}:${this.ui.view.low}-${this.ui.view.high}`;
|
||||
|
||||
var annotation = "Bookmark description";
|
||||
return this.ui.add_bookmark(position, annotation, true);
|
||||
});
|
||||
|
||||
// initialize keyboard
|
||||
this.ui.init_keyboard_nav(this.ui.view);
|
||||
|
||||
$(window).on("beforeunload", () => {
|
||||
if (this.ui.view.has_changes) {
|
||||
return "There are unsaved changes to your visualization that will be lost if you leave this page.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// create
|
||||
create_browser: function(name, dbkey) {
|
||||
create_browser(name, dbkey) {
|
||||
$(document).trigger("convert_to_values");
|
||||
|
||||
view = ui.create_visualization(
|
||||
this.ui.create_visualization(
|
||||
{
|
||||
container: $("#center .unified-panel-body"),
|
||||
name: name,
|
||||
@@ -598,46 +620,11 @@ var TracksterView = Backbone.View.extend({
|
||||
this.init_editor();
|
||||
|
||||
// modify view setting
|
||||
view.editor = true;
|
||||
},
|
||||
|
||||
// initialization for editor-specific functions.
|
||||
init_editor: function() {
|
||||
// set title
|
||||
$("#center .unified-panel-title").text(`${view.config.get_value("name")} (${view.dbkey})`);
|
||||
|
||||
// add dataset
|
||||
if (window.galaxy_config.app.add_dataset)
|
||||
$.ajax({
|
||||
url: `${Galaxy.root}api/datasets/${window.galaxy_config.app.add_dataset}`,
|
||||
data: { hda_ldda: "hda", data_type: "track_config" },
|
||||
dataType: "json",
|
||||
success: function(track_data) {
|
||||
view.add_drawable(tracks.object_from_template(track_data, view, view));
|
||||
}
|
||||
});
|
||||
|
||||
// initialize icons
|
||||
$("#add-bookmark-button").click(() => {
|
||||
// add new bookmark.
|
||||
var position = `${view.chrom}:${view.low}-${view.high}`;
|
||||
|
||||
var annotation = "Bookmark description";
|
||||
return ui.add_bookmark(position, annotation, true);
|
||||
});
|
||||
|
||||
// initialize keyboard
|
||||
ui.init_keyboard_nav(view);
|
||||
|
||||
$(window).on("beforeunload", () => {
|
||||
if (view.has_changes) {
|
||||
return "There are unsaved changes to your visualization that will be lost if you leave this page.";
|
||||
}
|
||||
});
|
||||
this.ui.view.editor = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
TracksterUI: TracksterUI,
|
||||
GalaxyApp: TracksterView
|
||||
GalaxyApp: TracksterUIView
|
||||
};
|
||||
|
||||
@@ -151,7 +151,7 @@ var NumberFilter = function(obj_dict) {
|
||||
.addClass("elt-label")
|
||||
.appendTo(filter.parent_div);
|
||||
|
||||
var name_span = $("<span/>")
|
||||
$("<span/>")
|
||||
.addClass("slider-name")
|
||||
.text(`${filter.name} `)
|
||||
.appendTo(filter_label);
|
||||
@@ -341,9 +341,6 @@ extend(NumberFilter.prototype, {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Keep value function.
|
||||
var filter = this;
|
||||
|
||||
// Do filtering.
|
||||
var to_filter = element[this.index];
|
||||
if (to_filter instanceof Array) {
|
||||
@@ -482,7 +479,7 @@ var FiltersManager = function(track, obj_dict) {
|
||||
filter.height_icon.addClass("active").show();
|
||||
}
|
||||
} else {
|
||||
console.log("ERROR: unsupported filter: ", name, type);
|
||||
console.log("ERROR: unsupported filter: ", filters_dict[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,6 +653,7 @@ extend(FiltersManager.prototype, {
|
||||
// Remove current filter.
|
||||
filters = filters.slice(1);
|
||||
|
||||
// DBTODO: This will never work, run_tool_url doesn't exist?
|
||||
$.getJSON(run_tool_url, url_params, response => {
|
||||
if (response.error) {
|
||||
// General error.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ extend(FeatureSlotter.prototype, {
|
||||
|
||||
var draw_end = Math.ceil(feature[2] * this.w_scale);
|
||||
var f_name = feature[3];
|
||||
var text_align;
|
||||
//var text_align;
|
||||
|
||||
// Update start, end drawing locations to include feature name.
|
||||
// Try to put the name on the left, if not, put on right.
|
||||
@@ -55,10 +55,10 @@ extend(FeatureSlotter.prototype, {
|
||||
var text_len = this.measureText(f_name).width + (LABEL_SPACING + PACK_SPACING);
|
||||
if (draw_start - text_len >= 0) {
|
||||
draw_start -= text_len;
|
||||
text_align = "left";
|
||||
//text_align = "left";
|
||||
} else {
|
||||
draw_end += text_len;
|
||||
text_align = "right";
|
||||
//text_align = "right";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ extend(FeatureSlotter.prototype, {
|
||||
// Loop through features to (a) find those that are not yet slotted and (b) update
|
||||
// those that are slotted if new information is availabe. For (a), features already
|
||||
// slotted (based on slotting from other tiles) will retain their current slot.
|
||||
for (var i = 0, len = features.length; i < len; i++) {
|
||||
for (let i = 0, len = features.length; i < len; i++) {
|
||||
feature = features[i];
|
||||
feature_uid = feature[0];
|
||||
var slotted_info = this.slots[feature_uid];
|
||||
@@ -163,7 +163,7 @@ extend(FeatureSlotter.prototype, {
|
||||
// Slot unslotted features.
|
||||
|
||||
// Do slotting.
|
||||
for (var i = 0, len = undone.length; i < len; i++) {
|
||||
for (let i = 0, len = undone.length; i < len; i++) {
|
||||
feature = features[undone[i]];
|
||||
feature_uid = feature[0];
|
||||
var draw_coords = this._get_draw_coords(feature);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import _l from "utils/localization";
|
||||
import * as _ from "libs/underscore";
|
||||
import * as Backbone from "libs/backbone";
|
||||
import visualization from "viz/visualization";
|
||||
import viz_views from "viz/viz_views";
|
||||
import util from "viz/trackster/util";
|
||||
@@ -13,6 +14,9 @@ import bbi from "viz/bbi-data-manager";
|
||||
import "ui/editable-text";
|
||||
var extend = _.extend;
|
||||
|
||||
/* global $ */
|
||||
/* global Galaxy */
|
||||
|
||||
// ---- Web UI specific utilities ----
|
||||
|
||||
/**
|
||||
@@ -24,9 +28,9 @@ var html_elt_js_obj_dict = {};
|
||||
/**
|
||||
* Designates an HTML as a container.
|
||||
*/
|
||||
var is_container = (element, obj) => {
|
||||
function is_container(element, obj) {
|
||||
html_elt_js_obj_dict[element.attr("id")] = obj;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Make `element` moveable within parent and sibling elements by dragging `handle` (a selector).
|
||||
@@ -37,7 +41,7 @@ var is_container = (element, obj) => {
|
||||
* @param container_selector selector used to identify possible containers for this element
|
||||
* @param element_js_obj JavaScript object associated with element; used
|
||||
*/
|
||||
var moveable = (element, handle_class, container_selector, element_js_obj) => {
|
||||
function moveable(element, handle_class, container_selector, element_js_obj) {
|
||||
// HACK: set default value for container selector.
|
||||
container_selector = ".group";
|
||||
|
||||
@@ -48,11 +52,9 @@ var moveable = (element, handle_class, container_selector, element_js_obj) => {
|
||||
element
|
||||
.bind("drag", { handle: `.${handle_class}`, relative: true }, function(e, d) {
|
||||
var element = $(this);
|
||||
var parent = $(this).parent();
|
||||
|
||||
var // Only sorting amongst tracks and groups.
|
||||
children = parent.children(".track,.group");
|
||||
|
||||
var parent = element.parent();
|
||||
// Only sorting amongst tracks and groups.
|
||||
var children = parent.children(".track,.group");
|
||||
var this_obj = html_elt_js_obj_dict[$(this).attr("id")];
|
||||
var child;
|
||||
var container;
|
||||
@@ -144,46 +146,47 @@ var moveable = (element, handle_class, container_selector, element_js_obj) => {
|
||||
.bind("dragend", function() {
|
||||
$(this).removeClass("dragging");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Init constants & functions used throughout trackster.
|
||||
*/
|
||||
var // Padding at the top of tracks for error messages
|
||||
ERROR_PADDING = 20;
|
||||
|
||||
var // Maximum number of rows un a slotted track
|
||||
MAX_FEATURE_DEPTH = 100;
|
||||
// Padding at the top of tracks for error messages
|
||||
const ERROR_PADDING = 20;
|
||||
|
||||
var // Minimum width for window for squish to be used.
|
||||
MIN_SQUISH_VIEW_WIDTH = 12000;
|
||||
// Maximum number of rows un a slotted track
|
||||
const MAX_FEATURE_DEPTH = 100;
|
||||
|
||||
var // Number of pixels per tile, not including left offset.
|
||||
TILE_SIZE = 400;
|
||||
// Minimum width for window for squish to be used.
|
||||
const MIN_SQUISH_VIEW_WIDTH = 12000;
|
||||
|
||||
var DEFAULT_DATA_QUERY_WAIT = 5000;
|
||||
// Number of pixels per tile, not including left offset.
|
||||
const TILE_SIZE = 400;
|
||||
|
||||
var // Maximum number of chromosomes that are selectable at any one time.
|
||||
MAX_CHROMS_SELECTABLE = 100;
|
||||
const DEFAULT_DATA_QUERY_WAIT = 5000;
|
||||
|
||||
var DATA_ERROR = "Cannot display dataset due to an error. ";
|
||||
// Maximum number of chromosomes that are selectable at any one time.
|
||||
const MAX_CHROMS_SELECTABLE = 100;
|
||||
|
||||
var DATA_NOCONVERTER = "A converter for this dataset is not installed. Please check your datatypes_conf.xml file.";
|
||||
const DATA_ERROR = "Cannot display dataset due to an error. ";
|
||||
|
||||
var DATA_NONE = "No data for this chrom/contig.";
|
||||
const DATA_NOCONVERTER = "A converter for this dataset is not installed. Please check your datatypes_conf.xml file.";
|
||||
|
||||
var DATA_PENDING =
|
||||
const DATA_NONE = "No data for this chrom/contig.";
|
||||
|
||||
const DATA_PENDING =
|
||||
"Preparing data. This can take a while for a large dataset. " +
|
||||
"If the visualization is saved and closed, preparation will continue in the background.";
|
||||
|
||||
var DATA_CANNOT_RUN_TOOL = "Tool cannot be rerun: ";
|
||||
var DATA_LOADING = "Loading data...";
|
||||
var DATA_OK = "Ready for display";
|
||||
var TILE_CACHE_SIZE = 10;
|
||||
var DATA_CACHE_SIZE = 20;
|
||||
|
||||
var // Numerical/continuous data display modes.
|
||||
CONTINUOUS_DATA_MODES = ["Histogram", "Line", "Filled", "Intensity"];
|
||||
const DATA_CANNOT_RUN_TOOL = "Tool cannot be rerun: ";
|
||||
//var DATA_LOADING = "Loading data...";
|
||||
const DATA_OK = "Ready for display";
|
||||
const TILE_CACHE_SIZE = 10;
|
||||
//var DATA_CACHE_SIZE = 20;
|
||||
//
|
||||
// Numerical/continuous data display modes.
|
||||
const CONTINUOUS_DATA_MODES = ["Histogram", "Line", "Filled", "Intensity"];
|
||||
|
||||
/**
|
||||
* Round a number to a given number of decimal places.
|
||||
@@ -248,7 +251,10 @@ var Drawable = function(view, container, obj_dict) {
|
||||
this.action_icons = {};
|
||||
|
||||
// -- Set up drawable configuration. --
|
||||
this.config = config_mod.ConfigSettingCollection.from_models_and_saved_values(this.config_params, obj_dict.prefs);
|
||||
this.config = config_mod.ConfigSettingCollection.from_models_and_saved_values(
|
||||
this.build_config_params(),
|
||||
obj_dict.prefs
|
||||
);
|
||||
|
||||
// If there's no saved name, use object name.
|
||||
if (!this.config.get_value("name")) {
|
||||
@@ -342,6 +348,10 @@ extend(Drawable.prototype, {
|
||||
}
|
||||
],
|
||||
|
||||
build_config_params: function() {
|
||||
return this.config_params;
|
||||
},
|
||||
|
||||
config_onchange: function() {},
|
||||
|
||||
init: function() {},
|
||||
@@ -723,7 +733,6 @@ extend(DrawableGroup.prototype, Drawable.prototype, DrawableCollection.prototype
|
||||
for (i = 0; i < num_drawables; i++) {
|
||||
drawable = this.drawables[i];
|
||||
if (drawable.get_type() !== a_type) {
|
||||
can_composite = false;
|
||||
break;
|
||||
}
|
||||
if (drawable instanceof FeatureTrack) {
|
||||
@@ -772,16 +781,12 @@ extend(DrawableGroup.prototype, Drawable.prototype, DrawableCollection.prototype
|
||||
// manager.
|
||||
//
|
||||
this.filters_manager.remove_all();
|
||||
var filters;
|
||||
var new_filter;
|
||||
var min;
|
||||
var max;
|
||||
for (var filter_name in shared_filters) {
|
||||
filters = shared_filters[filter_name];
|
||||
let filters = shared_filters[filter_name];
|
||||
if (filters.length === num_feature_tracks) {
|
||||
// Add new filter.
|
||||
// FIXME: can filter.copy() be used?
|
||||
new_filter = new filters_mod.NumberFilter({
|
||||
let new_filter = new filters_mod.NumberFilter({
|
||||
name: filters[0].name,
|
||||
index: filters[0].index
|
||||
});
|
||||
@@ -834,7 +839,7 @@ extend(DrawableGroup.prototype, Drawable.prototype, DrawableCollection.prototype
|
||||
name: this.config.get_value("name"),
|
||||
drawables: this.drawables
|
||||
});
|
||||
var index = this.container.replace_drawable(this, composite_track, true);
|
||||
this.container.replace_drawable(this, composite_track, true);
|
||||
composite_track.request_draw();
|
||||
},
|
||||
|
||||
@@ -981,7 +986,8 @@ var TracksterView = Backbone.View.extend({
|
||||
this.intro_div = $("<div/>")
|
||||
.addClass("intro")
|
||||
.appendTo(this.viewport_container);
|
||||
var add_tracks_button = $("<div/>")
|
||||
// Add tracks button
|
||||
$("<div/>")
|
||||
.text("Add Datasets to Visualization")
|
||||
.addClass("action-button")
|
||||
.appendTo(this.intro_div)
|
||||
@@ -1270,11 +1276,11 @@ var TracksterView = Backbone.View.extend({
|
||||
$(window).bind("resize", function() {
|
||||
// Stop previous timer.
|
||||
if (this.resize_timer) {
|
||||
clearTimeout(this.resize_timer);
|
||||
window.clearTimeout(this.resize_timer);
|
||||
}
|
||||
|
||||
// When function activated, resize window and redraw.
|
||||
this.resize_timer = setTimeout(() => {
|
||||
this.resize_timer = window.setTimeout(() => {
|
||||
view.resize_window();
|
||||
}, 500);
|
||||
});
|
||||
@@ -1309,18 +1315,17 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
trigger_navigate: function(new_chrom, new_low, new_high, delay) {
|
||||
// Stop previous timer.
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
window.clearTimeout(this.timer);
|
||||
}
|
||||
|
||||
if (delay) {
|
||||
// To aggregate calls, use timer and only navigate once
|
||||
// location has stabilized.
|
||||
var self = this;
|
||||
this.timer = setTimeout(() => {
|
||||
self.trigger("navigate", `${new_chrom}:${new_low}-${new_high}`);
|
||||
this.timer = window.setTimeout(() => {
|
||||
this.trigger("navigate", `${new_chrom}:${new_low}-${new_high}`);
|
||||
}, 500);
|
||||
} else {
|
||||
view.trigger("navigate", `${new_chrom}:${new_low}-${new_high}`);
|
||||
this.trigger("navigate", `${new_chrom}:${new_low}-${new_high}`);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1343,13 +1348,12 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
load_chroms: function(url_parms) {
|
||||
url_parms.num = MAX_CHROMS_SELECTABLE;
|
||||
|
||||
var view = this;
|
||||
var chrom_data = $.Deferred();
|
||||
$.ajax({
|
||||
url: `${Galaxy.root}api/genomes/${this.dbkey}`,
|
||||
data: url_parms,
|
||||
dataType: "json",
|
||||
success: function(result) {
|
||||
success: result => {
|
||||
// Do nothing if could not load chroms.
|
||||
if (result.chrom_info.length === 0) {
|
||||
return;
|
||||
@@ -1357,34 +1361,34 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
|
||||
// Load chroms.
|
||||
if (result.reference) {
|
||||
var ref_track = new ReferenceTrack(view);
|
||||
view.add_label_track(ref_track);
|
||||
view.reference_track = ref_track;
|
||||
var ref_track = new ReferenceTrack(this);
|
||||
this.add_label_track(ref_track);
|
||||
this.reference_track = ref_track;
|
||||
}
|
||||
view.chrom_data = result.chrom_info;
|
||||
this.chrom_data = result.chrom_info;
|
||||
|
||||
view.chrom_select.html("");
|
||||
view.chrom_select.append($('<option value="">Select Chrom/Contig</option>'));
|
||||
this.chrom_select.html("");
|
||||
this.chrom_select.append($('<option value="">Select Chrom/Contig</option>'));
|
||||
|
||||
for (var i = 0, len = view.chrom_data.length; i < len; i++) {
|
||||
var chrom = view.chrom_data[i].chrom;
|
||||
for (var i = 0, len = this.chrom_data.length; i < len; i++) {
|
||||
var chrom = this.chrom_data[i].chrom;
|
||||
var chrom_option = $("<option>");
|
||||
chrom_option.text(chrom);
|
||||
chrom_option.val(chrom);
|
||||
view.chrom_select.append(chrom_option);
|
||||
this.chrom_select.append(chrom_option);
|
||||
}
|
||||
if (result.prev_chroms) {
|
||||
view.chrom_select.append($(`<option value="previous">Previous ${MAX_CHROMS_SELECTABLE}</option>`));
|
||||
this.chrom_select.append($(`<option value="previous">Previous ${MAX_CHROMS_SELECTABLE}</option>`));
|
||||
}
|
||||
if (result.next_chroms) {
|
||||
view.chrom_select.append($(`<option value="next">Next ${MAX_CHROMS_SELECTABLE}</option>`));
|
||||
this.chrom_select.append($(`<option value="next">Next ${MAX_CHROMS_SELECTABLE}</option>`));
|
||||
}
|
||||
view.chrom_start_index = result.start_index;
|
||||
this.chrom_start_index = result.start_index;
|
||||
|
||||
chrom_data.resolve(result.chrom_info);
|
||||
},
|
||||
error: function() {
|
||||
alert(`Could not load chroms for this dbkey: ${view.dbkey}`);
|
||||
alert(`Could not load chroms for this dbkey: ${this.dbkey}`);
|
||||
}
|
||||
});
|
||||
return chrom_data;
|
||||
@@ -1491,7 +1495,7 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
str = str.replace(/,/g, "");
|
||||
|
||||
// Replace colons and hyphens with space for easy parsing.
|
||||
str = str.replace(/:|\-/g, " ");
|
||||
str = str.replace(/:|-/g, " ");
|
||||
|
||||
// Parse new location.
|
||||
var chrom_pos = str.split(/\s+/);
|
||||
@@ -1537,10 +1541,10 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
|
||||
// Set up timeout to redraw with more data when moving stops.
|
||||
if (this.redraw_on_move_fn) {
|
||||
clearTimeout(this.redraw_on_move_fn);
|
||||
window.clearTimeout(this.redraw_on_move_fn);
|
||||
}
|
||||
|
||||
this.redraw_on_move_fn = setTimeout(() => {
|
||||
this.redraw_on_move_fn = window.setTimeout(() => {
|
||||
view.request_redraw();
|
||||
}, 200);
|
||||
|
||||
@@ -1617,7 +1621,7 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
|
||||
// Set up redraw if it has not been requested since last redraw.
|
||||
if (!this.requested_redraw) {
|
||||
requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(() => {
|
||||
view._redraw();
|
||||
});
|
||||
this.requested_redraw = true;
|
||||
@@ -1779,8 +1783,8 @@ extend(TracksterView.prototype, DrawableCollection.prototype, {
|
||||
this.overview_box.height(this.default_overview_height);
|
||||
this.overview_close.hide();
|
||||
this.overview_highlight.hide();
|
||||
view.resize_window();
|
||||
view.overview_drawable = null;
|
||||
this.resize_window();
|
||||
this.overview_drawable = null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1828,7 +1832,7 @@ var ToolParameterView = Backbone.View.extend({
|
||||
var param = this.model;
|
||||
|
||||
// Param label.
|
||||
var label_div = $("<div>")
|
||||
$("<div>")
|
||||
.addClass("param-label")
|
||||
.text(param.get("label"))
|
||||
.appendTo(param_div);
|
||||
@@ -1881,7 +1885,7 @@ var TracksterToolView = Backbone.View.extend({
|
||||
});
|
||||
|
||||
// Add name, inputs.
|
||||
var name_div = $("<div class='tool-name'>")
|
||||
$("<div class='tool-name'>")
|
||||
.appendTo(parent_div)
|
||||
.text(tool.get("name"));
|
||||
tool.get("inputs").each(param => {
|
||||
@@ -1989,44 +1993,42 @@ var TracksterToolView = Backbone.View.extend({
|
||||
regions: [region.toJSON()]
|
||||
};
|
||||
|
||||
var current_track = track;
|
||||
|
||||
var // Set name of track to include tool name, parameters, and region used.
|
||||
track_name = tool.get("name") + current_track.tool_region_and_parameters_str(region);
|
||||
// Set name of track to include tool name, parameters, and region used.
|
||||
var track_name = tool.get("name") + track.tool_region_and_parameters_str(region);
|
||||
|
||||
var container;
|
||||
|
||||
// If track not in a group, create a group for it and add new track to group. If track
|
||||
// already in group, add track to group.
|
||||
if (current_track.container === view) {
|
||||
if (track.container === track.view) {
|
||||
// Create new group.
|
||||
var group = new DrawableGroup(view, view, {
|
||||
var group = new DrawableGroup(track.view, track.view, {
|
||||
name: track.config.get_value("name")
|
||||
});
|
||||
|
||||
// Replace track with group.
|
||||
var index = current_track.container.replace_drawable(current_track, group, false);
|
||||
var index = track.container.replace_drawable(track, group, false);
|
||||
|
||||
// Update HTML.
|
||||
// FIXME: this is ugly way to replace a track with a group -- make this easier via
|
||||
// a Drawable or DrawableCollection function.
|
||||
group.container_div.insertBefore(current_track.view.content_div.children()[index]);
|
||||
group.add_drawable(current_track);
|
||||
current_track.container_div.appendTo(group.content_div);
|
||||
group.container_div.insertBefore(track.view.content_div.children()[index]);
|
||||
group.add_drawable(track);
|
||||
track.container_div.appendTo(group.content_div);
|
||||
container = group;
|
||||
} else {
|
||||
// Use current group.
|
||||
container = current_track.container;
|
||||
container = track.container;
|
||||
}
|
||||
|
||||
// Create and init new track.
|
||||
var new_track = new current_track.constructor(view, container, {
|
||||
var new_track = new track.constructor(track.view, container, {
|
||||
name: track_name,
|
||||
hda_ldda: "hda"
|
||||
});
|
||||
new_track.init_for_tool_data();
|
||||
new_track.change_mode(current_track.mode);
|
||||
new_track.set_filters_manager(current_track.filters_manager.copy(new_track));
|
||||
new_track.change_mode(track.mode);
|
||||
new_track.set_filters_manager(track.filters_manager.copy(new_track));
|
||||
new_track.update_icons();
|
||||
container.add_drawable(new_track);
|
||||
new_track.tiles_div.text("Starting job.");
|
||||
@@ -2441,12 +2443,17 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
name: "param_space_viz_icon",
|
||||
title: _l("Tool parameter space visualization"),
|
||||
css_class: "arrow-split",
|
||||
on_click_fn: function(track) {
|
||||
var html = `<strong>Tool</strong>:${track.tool.get(
|
||||
"name"
|
||||
)}<br/><strong>Dataset</strong>:${track.config.get_value(
|
||||
"name"
|
||||
)}<br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>`;
|
||||
on_click_fn: track => {
|
||||
var html = `
|
||||
<strong>Tool</strong>:${track.tool.get("name")}<br/>
|
||||
<strong>Dataset</strong>:${track.config.get_value("name")}<br/>
|
||||
<strong>Region(s)</strong>:
|
||||
<select name="regions">
|
||||
<option value="cur">current viewing area</option>
|
||||
<option value="bookmarks">bookmarks</option>
|
||||
<option value="both">current viewing area and bookmarks</option>
|
||||
</select>
|
||||
`;
|
||||
|
||||
var cancel_fn = () => {
|
||||
Galaxy.modal.hide();
|
||||
@@ -2454,22 +2461,22 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
};
|
||||
|
||||
var ok_fn = () => {
|
||||
var regions_to_use = $('select[name="regions"] option:selected').val(),
|
||||
regions,
|
||||
view_region = new visualization.GenomeRegion({
|
||||
chrom: view.chrom,
|
||||
start: view.low,
|
||||
end: view.high
|
||||
}),
|
||||
bookmarked_regions = _.map(
|
||||
$(".bookmark"),
|
||||
elt =>
|
||||
new visualization.GenomeRegion({
|
||||
from_str: $(elt)
|
||||
.children(".position")
|
||||
.text()
|
||||
})
|
||||
);
|
||||
var regions_to_use = $('select[name="regions"] option:selected').val();
|
||||
var regions;
|
||||
var view_region = new visualization.GenomeRegion({
|
||||
chrom: this.view.chrom,
|
||||
start: this.view.low,
|
||||
end: this.view.high
|
||||
});
|
||||
var bookmarked_regions = _.map(
|
||||
$(".bookmark"),
|
||||
elt =>
|
||||
new visualization.GenomeRegion({
|
||||
from_str: $(elt)
|
||||
.children(".position")
|
||||
.text()
|
||||
})
|
||||
);
|
||||
|
||||
// Get regions for visualization.
|
||||
if (regions_to_use === "cur") {
|
||||
@@ -2493,6 +2500,8 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
})}`;
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO: Re-enable this when functional.
|
||||
var check_enter_esc = e => {
|
||||
if ((e.keyCode || e.which) === 27) {
|
||||
// Escape key
|
||||
@@ -2502,6 +2511,7 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
ok_fn();
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// show dialog
|
||||
Galaxy.modal.show({
|
||||
@@ -2732,7 +2742,7 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
track.container_div.addClass("pending");
|
||||
track.show_message(DATA_PENDING);
|
||||
//$("<img/>").attr("src", image_path + "/yui/rel_interstitial_loading.gif").appendTo(track.tiles_div);
|
||||
setTimeout(() => {
|
||||
window.setTimeout(() => {
|
||||
track.init();
|
||||
}, track.data_query_wait);
|
||||
} else if (result === "data" || result.status === "data") {
|
||||
@@ -3040,7 +3050,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
var clear_after = options && options.clear_after;
|
||||
var low = this.view.low;
|
||||
var high = this.view.high;
|
||||
var range = high - low;
|
||||
//var range = high - low;
|
||||
var width = this.view.container.width();
|
||||
var w_scale = this.view.resolution_px_b;
|
||||
var resolution = 1 / w_scale;
|
||||
@@ -3049,7 +3059,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
if (this.is_overview) {
|
||||
low = this.view.max_low;
|
||||
high = this.view.max_high;
|
||||
w_scale = width / (view.max_high - view.max_low);
|
||||
w_scale = width / (this.view.max_high - this.view.max_low);
|
||||
resolution = 1 / w_scale;
|
||||
}
|
||||
|
||||
@@ -3105,17 +3115,16 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
}
|
||||
|
||||
// When all tiles are drawn, call post-draw actions.
|
||||
var track = this;
|
||||
$.when.apply($, tile_promises).then(() => {
|
||||
// Step (c) for (re)moving tiles when clear_after is true:
|
||||
track.tiles_div.children(".remove").remove();
|
||||
this.tiles_div.children(".remove").remove();
|
||||
|
||||
// Only do postdraw actions for tiles; instances where tiles may not be drawn include:
|
||||
// (a) ReferenceTrack without sufficient resolution;
|
||||
// (b) data_fetch = false.
|
||||
tiles = _.filter(tiles, t => t !== null);
|
||||
if (tiles.length !== 0) {
|
||||
track.postdraw_actions(tiles, width, w_scale, clear_after);
|
||||
this.postdraw_actions(tiles, width, w_scale, clear_after);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -3124,18 +3133,17 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
* Add a maximum/minimum label to track.
|
||||
*/
|
||||
_add_yaxis_label: function(type, on_change) {
|
||||
var track = this;
|
||||
var css_class = type === "max" ? "top" : "bottom";
|
||||
var text = type === "max" ? "max" : "min";
|
||||
var pref_name = type === "max" ? "max_value" : "min_value";
|
||||
var label = this.container_div.find(`.yaxislabel.${css_class}`);
|
||||
var value = round(track.config.get_value(pref_name), 1);
|
||||
var value = round(this.config.get_value(pref_name), 1);
|
||||
|
||||
// Default action for on_change is to redraw track.
|
||||
on_change =
|
||||
on_change ||
|
||||
(() => {
|
||||
track.request_draw({ clear_tile_cache: true });
|
||||
this.request_draw({ clear_tile_cache: true });
|
||||
});
|
||||
|
||||
if (label.length !== 0) {
|
||||
@@ -3149,7 +3157,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
num_cols: 12,
|
||||
on_finish: function(new_val) {
|
||||
$(".tooltip").remove();
|
||||
track.config.set_value(pref_name, round(new_val, 1));
|
||||
this.config.set_value(pref_name, round(new_val, 1));
|
||||
on_change();
|
||||
},
|
||||
help_text: `Set ${text} value`
|
||||
@@ -3176,18 +3184,17 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
|
||||
// Clear because this is set when drawing.
|
||||
this.max_height_px = 0;
|
||||
var track = this;
|
||||
_.each(tiles, tile => {
|
||||
if (!(tile instanceof LineTrackTile)) {
|
||||
tile.html_elt.remove();
|
||||
track.draw_helper(tile.region, w_scale, {
|
||||
this.draw_helper(tile.region, w_scale, {
|
||||
force: true,
|
||||
mode: "Coverage"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
track._add_yaxis_label("max");
|
||||
this._add_yaxis_label("max");
|
||||
} else {
|
||||
// -- Drawing in non-Coverage mode. --
|
||||
|
||||
@@ -3247,19 +3254,16 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
var mode = options.mode || this.mode;
|
||||
var resolution = 1 / w_scale;
|
||||
|
||||
var // Useful vars.
|
||||
track = this;
|
||||
|
||||
var drawables = this._get_drawables();
|
||||
var key = this._gen_tile_cache_key(w_scale, region);
|
||||
|
||||
var is_tile = o => o && "track" in o;
|
||||
|
||||
// Check tile cache, if found show existing tile in correct position
|
||||
var tile = force ? undefined : track.tile_cache.get_elt(key);
|
||||
var tile = force ? undefined : this.tile_cache.get_elt(key);
|
||||
if (tile) {
|
||||
if (is_tile(tile)) {
|
||||
track.show_tile(tile, w_scale);
|
||||
this.show_tile(tile, w_scale);
|
||||
}
|
||||
return tile;
|
||||
}
|
||||
@@ -3277,16 +3281,16 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
// Map drawable object to data needed for drawing.
|
||||
var tile_data = _.map(drawables, (
|
||||
d // Get the track data/promise.
|
||||
) => d.data_manager.get_data(region, data_mode, resolution, track.data_url_extra_params));
|
||||
) => d.data_manager.get_data(region, data_mode, resolution, this.data_url_extra_params));
|
||||
|
||||
// Get reference data/promise.
|
||||
if (view.reference_track) {
|
||||
if (this.view.reference_track) {
|
||||
tile_data.push(
|
||||
view.reference_track.data_manager.get_data(
|
||||
this.view.reference_track.data_manager.get_data(
|
||||
region,
|
||||
mode,
|
||||
resolution,
|
||||
view.reference_track.data_url_extra_params
|
||||
this.view.reference_track.data_url_extra_params
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -3298,7 +3302,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
// When data is available, draw tile.
|
||||
//
|
||||
var tile_drawn = $.Deferred();
|
||||
track.tile_cache.set_elt(key, tile_drawn);
|
||||
this.tile_cache.set_elt(key, tile_drawn);
|
||||
$.when.apply($, get_tile_data()).then(() => {
|
||||
var tile_data = get_tile_data();
|
||||
var tracks_data = tile_data;
|
||||
@@ -3309,41 +3313,36 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
// Deferred, try again from the top. NOTE: this condition could (should?) be handled by the
|
||||
// GenomeDataManager in visualization module.
|
||||
if (_.find(tile_data, d => util.is_deferred(d))) {
|
||||
track.tile_cache.set_elt(key, undefined);
|
||||
$.when(track.draw_helper(region, w_scale, options)).then(tile => {
|
||||
this.tile_cache.set_elt(key, undefined);
|
||||
$.when(this.draw_helper(region, w_scale, options)).then(tile => {
|
||||
tile_drawn.resolve(tile);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// If sequence data is available, subset to get only data in region.
|
||||
if (view.reference_track) {
|
||||
seq_data = view.reference_track.data_manager.subset_entry(tile_data.pop(), region);
|
||||
if (this.view.reference_track) {
|
||||
seq_data = this.view.reference_track.data_manager.subset_entry(tile_data.pop(), region);
|
||||
}
|
||||
|
||||
// Get drawing modes, heights for all tracks.
|
||||
var drawing_modes = [];
|
||||
|
||||
var drawing_heights = [];
|
||||
|
||||
_.each(drawables, (d, i) => {
|
||||
var mode = d.mode;
|
||||
var data = tracks_data[i];
|
||||
if (mode === "Auto") {
|
||||
mode = d.get_mode(data);
|
||||
d.update_auto_mode(mode);
|
||||
if (d.mode === "Auto") {
|
||||
d.mode = d.get_mode(data);
|
||||
d.update_auto_mode(d.mode);
|
||||
}
|
||||
drawing_modes.push(mode);
|
||||
drawing_heights.push(d.get_canvas_height(data, mode, w_scale, width));
|
||||
drawing_modes.push(d.mode);
|
||||
drawing_heights.push(d.get_canvas_height(data, d.mode, w_scale, width));
|
||||
});
|
||||
|
||||
var canvas = track.view.canvas_manager.new_canvas();
|
||||
var canvas = this.view.canvas_manager.new_canvas();
|
||||
var tile_low = region.get("start");
|
||||
var tile_high = region.get("end");
|
||||
var all_data_index = 0;
|
||||
|
||||
var width = Math.ceil((tile_high - tile_low) * w_scale) + track.left_offset;
|
||||
|
||||
var width = Math.ceil((tile_high - tile_low) * w_scale) + this.left_offset;
|
||||
var height = _.max(drawing_heights);
|
||||
var tile;
|
||||
|
||||
@@ -3354,7 +3353,7 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
// Height is specified in options or is the height found above.
|
||||
canvas.height = options.height || height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.translate(track.left_offset, 0);
|
||||
ctx.translate(this.left_offset, 0);
|
||||
if (drawables.length > 1) {
|
||||
ctx.globalAlpha = 0.5;
|
||||
ctx.globalCompositeOperation = "source-over";
|
||||
@@ -3365,8 +3364,8 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
|
||||
// Don't cache, show if no tile.
|
||||
if (tile !== undefined) {
|
||||
track.tile_cache.set_elt(key, tile);
|
||||
track.show_tile(tile, w_scale);
|
||||
this.tile_cache.set_elt(key, tile);
|
||||
this.show_tile(tile, w_scale);
|
||||
}
|
||||
|
||||
tile_drawn.resolve(tile);
|
||||
@@ -3428,7 +3427,6 @@ extend(TiledTrack.prototype, Drawable.prototype, Track.prototype, {
|
||||
* an existing tile rather than reshowing it.
|
||||
*/
|
||||
show_tile: function(tile, w_scale) {
|
||||
var track = this;
|
||||
var tile_element = tile.html_elt;
|
||||
|
||||
// -- Show/move tile element. --
|
||||
@@ -3785,7 +3783,7 @@ extend(CompositeTrack.prototype, TiledTrack.prototype, {
|
||||
}
|
||||
|
||||
// Replace track with group.
|
||||
var index = this.container.replace_drawable(this, group, true);
|
||||
this.container.replace_drawable(this, group, true);
|
||||
group.request_draw({ clear_tile_cache: true });
|
||||
},
|
||||
|
||||
@@ -3819,7 +3817,6 @@ extend(CompositeTrack.prototype, TiledTrack.prototype, {
|
||||
* Update minimum, maximum for component tracks.
|
||||
*/
|
||||
update_all_min_max: function() {
|
||||
var track = this;
|
||||
var min_value = this.config.get_value("min_value");
|
||||
var max_value = this.config.get_value("max_value");
|
||||
_.each(this.drawables, d => {
|
||||
@@ -4127,7 +4124,8 @@ extend(DiagonalHeatmapTrack.prototype, Drawable.prototype, TiledTrack.prototype,
|
||||
hda_ldda: track.dataset.get("hda_ldda")
|
||||
},
|
||||
result => {
|
||||
var data = result.data;
|
||||
// What does this do? Is it meant to be attached to some higher scope state object?
|
||||
// var data = result.data;
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -4163,10 +4161,9 @@ var FeatureTrack = function(view, container, obj_dict) {
|
||||
this.slotters = {};
|
||||
this.start_end_dct = {};
|
||||
this.left_offset = 200;
|
||||
|
||||
// this.painter = painters.LinkedFeaturePainter;
|
||||
this.set_painter_from_config();
|
||||
};
|
||||
|
||||
extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
display_modes: ["Auto", "Coverage", "Dense", "Squish", "Pack"],
|
||||
|
||||
@@ -4258,9 +4255,6 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
postdraw_actions: function(tiles, width, w_scale, clear_after) {
|
||||
TiledTrack.prototype.postdraw_actions.call(this, tiles, width, w_scale, clear_after);
|
||||
|
||||
var track = this;
|
||||
var i;
|
||||
|
||||
var line_track_tiles = _.filter(tiles, t => t instanceof LineTrackTile);
|
||||
|
||||
//
|
||||
@@ -4277,7 +4271,6 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
});
|
||||
|
||||
// Draw incomplete features on each tile.
|
||||
var self = this;
|
||||
_.each(tiles, tile => {
|
||||
// Remove features already drawn on tile originally.
|
||||
var tile_incomplete_features = _.omit(
|
||||
@@ -4296,16 +4289,16 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
data: _.values(tile_incomplete_features)
|
||||
};
|
||||
|
||||
var new_canvas = self.view.canvas_manager.new_canvas();
|
||||
var new_canvas = this.view.canvas_manager.new_canvas();
|
||||
var new_canvas_ctx = new_canvas.getContext("2d");
|
||||
new_canvas.height = Math.max(
|
||||
tile.canvas.height,
|
||||
self.get_canvas_height(features, tile.mode, tile.w_scale, 100)
|
||||
this.get_canvas_height(features, tile.mode, tile.w_scale, 100)
|
||||
);
|
||||
new_canvas.width = tile.canvas.width;
|
||||
new_canvas_ctx.drawImage(tile.canvas, 0, 0);
|
||||
new_canvas_ctx.translate(track.left_offset, 0);
|
||||
var new_tile = self.draw_tile(
|
||||
new_canvas_ctx.translate(this.left_offset, 0);
|
||||
var new_tile = this.draw_tile(
|
||||
features,
|
||||
new_canvas_ctx,
|
||||
tile.mode,
|
||||
@@ -4348,8 +4341,8 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
//
|
||||
|
||||
// Update filtering UI.
|
||||
if (track.filters_manager) {
|
||||
var filters = track.filters_manager.filters;
|
||||
if (this.filters_manager) {
|
||||
var filters = this.filters_manager.filters;
|
||||
var f;
|
||||
for (f = 0; f < filters.length; f++) {
|
||||
filters[f].update_ui_elt();
|
||||
@@ -4361,7 +4354,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
|
||||
var example_feature;
|
||||
var filter;
|
||||
for (i = 0; i < tiles.length; i++) {
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
if (tiles[i].data.length) {
|
||||
example_feature = tiles[i].data[0];
|
||||
for (f = 0; f < filters.length; f++) {
|
||||
@@ -4375,12 +4368,12 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
}
|
||||
|
||||
// If filter availability changed, hide filter div if necessary and update menu.
|
||||
if (track.filters_available !== filters_available) {
|
||||
track.filters_available = filters_available;
|
||||
if (!track.filters_available) {
|
||||
track.filters_manager.hide();
|
||||
if (this.filters_available !== filters_available) {
|
||||
this.filters_available = filters_available;
|
||||
if (!this.filters_available) {
|
||||
this.filters_manager.hide();
|
||||
}
|
||||
track.update_icons();
|
||||
this.update_icons();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4389,7 +4382,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
//
|
||||
if (tiles[0] instanceof FeatureTrackTile) {
|
||||
var all_slotted = true;
|
||||
for (i = 0; i < tiles.length; i++) {
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
if (!tiles[i].all_slotted) {
|
||||
all_slotted = false;
|
||||
break;
|
||||
@@ -4557,6 +4550,7 @@ extend(FeatureTrack.prototype, Drawable.prototype, TiledTrack.prototype, {
|
||||
);
|
||||
|
||||
var feature_mapper = null;
|
||||
var incomplete_features = null;
|
||||
|
||||
ctx.fillStyle = this.config.get_value("block_color");
|
||||
ctx.font = ctx.canvas.manager.default_font;
|
||||
|
||||
@@ -5,7 +5,6 @@ import util_mod from "viz/trackster/util";
|
||||
import config_mod from "utils/config";
|
||||
import GridView from "mvc/grid/grid-view";
|
||||
import Tabs from "mvc/ui/ui-tabs";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
/**
|
||||
* Mixin for returning custom JSON representation from toJSON. Class attribute to_json_keys defines a set of attributes
|
||||
* to include in the representation; to_json_mappers defines mappers for returned objects.
|
||||
@@ -1109,12 +1108,11 @@ var TrackBrowserRouter = Backbone.Router.extend({
|
||||
// Can't put regular expression in routes dictionary.
|
||||
// NOTE: parentheses are used to denote parameters returned to callback.
|
||||
this.route(/([\w]+)$/, "change_location");
|
||||
this.route(/([\w\+]+\:[\d,]+-[\d,]+)$/, "change_location");
|
||||
this.route(/([\w+]+:[\d,]+-[\d,]+)$/, "change_location");
|
||||
|
||||
// Handle navigate events from view.
|
||||
var self = this;
|
||||
self.view.on("navigate", new_loc => {
|
||||
self.navigate(new_loc);
|
||||
this.view.on("navigate", new_loc => {
|
||||
this.navigate(new_loc);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</datatype>
|
||||
<datatype extension="qname_sorted.bam" type="galaxy.datatypes.binary:BamQuerynameSorted" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension and sorted by queryname." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM">
|
||||
</datatype>
|
||||
<datatype extension="bam_native" type="galaxy.datatypes.binary:BamNative" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM">
|
||||
<datatype extension="unsorted.bam" type="galaxy.datatypes.binary:BamNative" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM">
|
||||
<converter file="bam_to_bigwig_converter.xml" target_datatype="bigwig"/>
|
||||
<converter file="to_coordinate_sorted_bam.xml" target_datatype="bam"/>
|
||||
<converter file="to_qname_sorted_bam.xml" target_datatype="qname_sorted.bam"/>
|
||||
@@ -299,7 +299,7 @@
|
||||
<datatype extension="qual454" type="galaxy.datatypes.qualityscore:QualityScore454" display_in_upload="true"/>
|
||||
<datatype extension="roadmaps" type="galaxy.datatypes.assembly:Roadmaps" display_in_upload="false"/>
|
||||
<datatype extension="sam" type="galaxy.datatypes.tabular:Sam" display_in_upload="true">
|
||||
<converter file="sam_to_bam_native.xml" target_datatype="bam_native"/>
|
||||
<converter file="sam_to_unsorted_bam.xml" target_datatype="unsorted.bam"/>
|
||||
<converter file="to_coordinate_sorted_bam.xml" target_datatype="bam"/>
|
||||
<converter file="to_qname_sorted_bam.xml" target_datatype="qname_sorted.bam"/>
|
||||
<converter file="sam_to_bigwig_converter.xml" target_datatype="bigwig"/>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,145 @@
|
||||
January 2018 Galaxy Release (v 18.01)
|
||||
===========================================================
|
||||
|
||||
.. include:: _header.rst
|
||||
|
||||
Schedule
|
||||
Highlights
|
||||
===========================================================
|
||||
* Planned Freeze Date: 2018-01-08
|
||||
* Planned Release Date: 2018-01-29
|
||||
|
||||
**Performance and User Experience Improvements**
|
||||
We made Galaxy more lively and responsive. Homepage, published workflows, published/saved histories, and data libraries should all load much faster now. Importing data from FTP will also take less of your time.
|
||||
We achieved this by optimizing database queries, implementing cache, rethinking presentation, and adding progress bars and loading indicators where needed. See the `list of related performance pull requests`_.
|
||||
|
||||
**Web Server and Configuration**
|
||||
The default web server used by Galaxy has changed from Paste to `uWSGI <https://uwsgi-docs.readthedocs.io/>`__ and the default configuration file for Galaxy is now ``config/galaxy.yml`` instead of ``config/galaxy.ini``.
|
||||
uWSGI is more production ready and allows Galaxy to scale better in its default
|
||||
configuration. In the future uWSGI will allow Galaxy to setup GIE proxies without additional
|
||||
configuration and use modern web technologies such as web sockets.
|
||||
Read more about the server, configuration, and documentation changes in the `uWSGI details`_ section of this document.
|
||||
|
||||
**Dataset Collection Usability**
|
||||
This release has significantly improved the usability of Galaxy dataset collections. Dozens of improvements
|
||||
to collections have been made, some of the key highlights include:
|
||||
|
||||
- Data library folders can now be sent to histories as a dataset collection. `Pull Request 4998`_, `Pull Request 5080`_
|
||||
- Failed dataset collection elements can now be fixed using job re-running (thanks to `@mvdbeek <https://github.com/mvdbeek>`__). `Pull Request 5321`_, `Pull Request 5247`_, `Pull Request 5270`_
|
||||
- Collections now appear with state and progress bars in the history panel and contained datasets
|
||||
are hidden by default (with help from `@mvdbeek <https://github.com/mvdbeek>`__).
|
||||
`Pull Request 5013`_, `Pull Request 5078`_
|
||||
- We added intuitive workflow post job actions for dataset collections. `Pull Request 5416`_, `Pull Request 5418`_, `Pull Request 5414`_
|
||||
- The web interface now supports collections with arbitrary nesting and size (with help
|
||||
from `@mvdbeek <https://github.com/mvdbeek>`__). `Pull Request 4942`_, `Pull Request 4934`_, `Pull Request 5091`_
|
||||
- More robust nametag discovery and propagation when using collections. `Pull Request 5403`_
|
||||
|
||||
**Client Architecture**
|
||||
The architecture for the client code that powers the Galaxy user interface has been significantly
|
||||
overhauled. The code base has been converted to `ES6 <http://es6-features.org/>`__,
|
||||
`Yarn <https://github.com/yarnpkg/yarn>`__ now powers the build and dependency management of the code,
|
||||
`Prettier <https://prettier.io/>`__ is now used to ensure consistent code formatting,
|
||||
and the `VueJS <https://vuejs.org/>`__ framework has been integrated. Taken together, these changes are
|
||||
enabling Galaxy developers to write usable, responsive client code more quickly and concisely than
|
||||
previously possible. A big thanks goes out to community contributions from
|
||||
`@anuprulez <https://github.com/anuprulez>`__ and `@anatskiy <https://github.com/anatskiy>`__ that are
|
||||
already converting existing Galaxy components to reactive VueJS ones. See the `list of related client pull requests`_.
|
||||
|
||||
**New BAM datatypes**
|
||||
Previously Galaxy only supported coordinate sorted BAM files by default (the ``bam`` datatype). In addition, this
|
||||
release of Galaxy now supports three new types of BAM:
|
||||
|
||||
- ``qname_sorted.bam``, that ensures that the file is queryname sorted (e.g. ``SO:queryname``);
|
||||
- ``qname_input_sorted.bam``, that can be used to describe the output of aligners which generally keep mate pairs adjacent
|
||||
- ``unsorted.bam``, that makes no assumptions about the sort order of the file.
|
||||
|
||||
A huge thanks goes out to `@bgruening <https://github.com/bgruening>`__ and `@mvdbeek <https://github.com/mvdbeek>`__ who
|
||||
implemented these datatypes.
|
||||
|
||||
`Pull Request 5180`_, `Pull Request 5589`_, `Pull Request 5532`_, `Pull Request 5644`_, `Pull Request 5674`_
|
||||
|
||||
**Experimental Job Caching**
|
||||
Galaxy can now be configured to allow users the option of skipping duplicated jobs if one with
|
||||
identical parameters has been previously executed and simply reuse the previously generated outputs.
|
||||
This contribution is thanks to `@mvdbeek <https://github.com/mvdbeek>`__.
|
||||
|
||||
`Pull Request 4690`_
|
||||
|
||||
|
||||
Get Galaxy
|
||||
==========
|
||||
|
||||
The code lives at `Github <https://github.com/galaxyproject/galaxy>`__ and you should have `Git <https://git-scm.com/>`__ to obtain it.
|
||||
|
||||
To get a new Galaxy repository run:
|
||||
.. code-block:: shell
|
||||
|
||||
$ git clone -b release_18.01 https://github.com/galaxyproject/galaxy.git
|
||||
|
||||
To update an existing Galaxy repository run:
|
||||
.. code-block:: shell
|
||||
|
||||
$ git checkout release_18.01 && git pull --ff-only origin release_18.01
|
||||
|
||||
See the `community hub <https://galaxyproject.org/develop/source-code/>`__ for additional details regarding the source code locations.
|
||||
|
||||
|
||||
Security
|
||||
========
|
||||
|
||||
Breaking Changes
|
||||
================
|
||||
|
||||
We have reworked the **Galaxy Webhook** interface so if you have custom webhooks at your instance
|
||||
you need to take the following steps in order to make them work:
|
||||
|
||||
1. Rename the main config file: <name>.yml -> config.yml
|
||||
2. In the config file, rename the name attribute: name -> id
|
||||
3. Put all files into the plugin's root folder, which should contain only four files: ``config.yml`` (mandatory), ``__init__.py`` (optional), ``script.js`` (optional), ``styles.css`` (optional)
|
||||
|
||||
Deprecation Notices
|
||||
===================
|
||||
|
||||
* This is the last release we are shipping JavaScript source maps for Galaxy client.
|
||||
|
||||
Removal Notices
|
||||
===============
|
||||
The following features that have been deprecated in the past releases are being removed in 18.01:
|
||||
|
||||
* Sample tracking
|
||||
* Sample request and external services management
|
||||
* Legacy library interface for Administrators
|
||||
|
||||
In addition to that, the PlantTribes datatypes have been commented out in the source code. Uncomment them if you want to re-enable it.
|
||||
|
||||
uWSGI details
|
||||
=============
|
||||
|
||||
To minimize the impact of this change on existing Galaxy instances, if a Galaxy has a ``galaxy.ini``
|
||||
file configured, it will continue to use Paste by default unless additional steps are
|
||||
taken by the administrator (Galaxy can be forced to start under uWSGI even with an older configuration file
|
||||
by setting ``APP_WEBSERVER=uwsgi`` in the environment). As part of the transition to YAML-based
|
||||
configuration files, we have implemented a schema to validate Galaxy configuration files. Run
|
||||
``make config-validate`` from Galaxy's root directory to validate a schema and ``make config-lint`` to
|
||||
check for best practices. While there is no need to convert your configuration file (``galaxy.ini`` hasn't
|
||||
been deprecated), you can run ``make config-convert-dry-run`` and ``make config-convert``
|
||||
to respectively test and perform the conversion of an ``ini`` configuration file to a YAML one.
|
||||
|
||||
These are big changes that affect many parts of Galaxy's administration documentation and makes
|
||||
this documentation very dependent on which Galaxy version they are targeting. To address this, we have
|
||||
moved a significant amount of administration documentation into Galaxy's code
|
||||
base and made it available on a per-release basis. The latest administration documentation for
|
||||
the previous release of Galaxy (17.09) which reference ``galaxy.ini`` files and Paste servers can
|
||||
be found `here <https://docs.galaxyproject.org/en/release_17.09/admin/index.html>`__, while documentation for this release can be found `here <https://docs.galaxyproject.org/en/release_18.01/admin/index.html>`__.
|
||||
|
||||
`Pull Request 4475`_, `Pull Request 5135`_, `Pull Request 5390`_, `Pull Request 5373`_,
|
||||
`Pull Request 5105`_, `Pull Request 5441`_
|
||||
|
||||
Release Notes
|
||||
=============
|
||||
|
||||
.. include:: 18.01.rst
|
||||
:start-after: announce_start
|
||||
|
||||
Security patch details
|
||||
======================
|
||||
|
||||
.. include:: _thanks.rst
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
===========================================================
|
||||
May 2018 Galaxy Release (v 18.05)
|
||||
===========================================================
|
||||
|
||||
|
||||
Schedule
|
||||
===========================================================
|
||||
* Planned Freeze Date: 2018-05-07
|
||||
* Planned Release Date: 2018-05-28
|
||||
@@ -4,6 +4,7 @@ Releases
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
18.01_announce
|
||||
17.09_announce
|
||||
17.05_announce
|
||||
17.01_announce
|
||||
|
||||
@@ -85,7 +85,12 @@ class DockerContainer(Container):
|
||||
# }
|
||||
# ]
|
||||
rval = []
|
||||
port_mappings = self.inspect[0]['NetworkSettings']['Ports']
|
||||
try:
|
||||
port_mappings = self.inspect[0]['NetworkSettings']['Ports']
|
||||
except (IndexError, KeyError) as exc:
|
||||
log.warning("Failed to get ports for container %s from `docker inspect` output at "
|
||||
"[0]['NetworkSettings']['Ports']: %s: %s", self.id, exc.__class__.__name__, str(exc))
|
||||
return None
|
||||
for port_name in port_mappings:
|
||||
for binding in port_mappings[port_name]:
|
||||
rval.append(ContainerPort(
|
||||
@@ -165,7 +170,12 @@ class DockerService(Container):
|
||||
# }
|
||||
# ]
|
||||
rval = []
|
||||
port_mappings = self.inspect[0]['Endpoint']['Ports']
|
||||
try:
|
||||
port_mappings = self.inspect[0]['Endpoint']['Ports']
|
||||
except (IndexError, KeyError) as exc:
|
||||
log.warning("Failed to get ports for container %s from `docker service inspect` output at "
|
||||
"[0]['Endpoint']['Ports']: %s: %s", self.id, exc.__class__.__name__, str(exc))
|
||||
return None
|
||||
for binding in port_mappings:
|
||||
rval.append(ContainerPort(
|
||||
binding['TargetPort'],
|
||||
|
||||
@@ -192,7 +192,7 @@ class BamNative(Binary):
|
||||
"""Class describing a BAM binary file that is not necessarily sorted"""
|
||||
edam_format = "format_2572"
|
||||
edam_data = "data_0863"
|
||||
file_ext = "bam_native"
|
||||
file_ext = "unsorted.bam"
|
||||
sort_flag = None
|
||||
|
||||
MetadataElement(name="bam_index", desc="BAM Index File", param=metadata.FileParameter, file_ext="bai", readonly=True, no_value=None, visible=False, optional=True)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
> temp.bg && bedGraphToBigWig temp.bg '$chromInfo' '$output']]>
|
||||
</command>
|
||||
<inputs>
|
||||
<param format="bam,bam_native" name="input" type="data" label="Choose BAM file"/>
|
||||
<param format="bam,unsorted.bam" name="input" type="data" label="Choose BAM file"/>
|
||||
</inputs>
|
||||
<outputs>
|
||||
<data format="bigwig" name="output"/>
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
<tool id="CONVERTER_sam_to_bam_native" name="Convert SAM to BAM native - without sorting" version="1.0.0" profile="18.01">
|
||||
<tool id="CONVERTER_sam_to_unsorted_bam" name="Convert SAM to BAM without sorting" version="1.0.0" profile="18.01">
|
||||
<requirements>
|
||||
<requirement type="package" version="1.6">samtools</requirement>
|
||||
</requirements>
|
||||
@@ -15,7 +15,7 @@
|
||||
<param name="input" type="data" format="sam" label="SAM file"/>
|
||||
</inputs>
|
||||
<outputs>
|
||||
<data name="output" format="bam_native"/>
|
||||
<data name="output" format="unsorted.bam"/>
|
||||
</outputs>
|
||||
<help>
|
||||
</help>
|
||||
@@ -12,7 +12,7 @@
|
||||
]]>
|
||||
</command>
|
||||
<inputs>
|
||||
<param format="sam,bam_native,qname_sorted.bam" name="input" type="data" label="Choose a BAM native or queryname sortedfile"/>
|
||||
<param format="sam,unsorted.bam,qname_sorted.bam" name="input" type="data" label="Choose a BAM native or queryname sortedfile"/>
|
||||
</inputs>
|
||||
<outputs>
|
||||
<data format="bam" name="output"/>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
]]>
|
||||
</command>
|
||||
<inputs>
|
||||
<param format="sam,bam_native" name="input" type="data" label="Choose a BAM native or queryname sortedfile"/>
|
||||
<param format="sam,unsorted.bam" name="input" type="data" label="Choose a BAM native or queryname sortedfile"/>
|
||||
</inputs>
|
||||
<outputs>
|
||||
<data format="qname_sorted.bam" name="output"/>
|
||||
|
||||
@@ -344,7 +344,7 @@ def guess_ext(fname, sniff_order):
|
||||
'bam'
|
||||
>>> fname = get_test_fname('3unsorted.bam')
|
||||
>>> guess_ext(fname, sniff_order)
|
||||
'bam_native'
|
||||
'unsorted.bam'
|
||||
>>> fname = get_test_fname('test.idpDB')
|
||||
>>> guess_ext(fname, sniff_order)
|
||||
'idpdb'
|
||||
|
||||
@@ -34,7 +34,7 @@ class FilterFactory(object):
|
||||
filters = deepcopy(self.default_filters)
|
||||
if trans.user:
|
||||
for name, value in trans.user.preferences.items():
|
||||
if value.strip():
|
||||
if value and value.strip():
|
||||
user_filters = listify(value, do_strip=True)
|
||||
category = ''
|
||||
if name == 'toolbox_tool_filters':
|
||||
|
||||
@@ -622,7 +622,7 @@ def _verify_extra_files_content(extra_files, hda_id, dataset_fetcher, test_data_
|
||||
_verify_composite_datatype_file_content(filepath, hda_id, base_name=filename, attributes=attributes, dataset_fetcher=dataset_fetcher, test_data_path_builder=test_data_path_builder, keep_outputs_dir=keep_outputs_dir)
|
||||
|
||||
|
||||
def verify_tool(tool_id, galaxy_interactor, resource_parameters={}, register_job_data=None, test_index=0, tool_version=None):
|
||||
def verify_tool(tool_id, galaxy_interactor, resource_parameters={}, register_job_data=None, test_index=0, tool_version=None, quiet=False):
|
||||
tool_test_dicts = galaxy_interactor.get_tool_tests(tool_id, tool_version=tool_version)
|
||||
tool_test_dict = tool_test_dicts[test_index]
|
||||
testdef = ToolTestDescription(tool_test_dict)
|
||||
@@ -642,6 +642,7 @@ def verify_tool(tool_id, galaxy_interactor, resource_parameters={}, register_job
|
||||
job_output_exceptions = None
|
||||
tool_execution_exception = None
|
||||
expected_failure_occurred = False
|
||||
begin_time = time.time()
|
||||
try:
|
||||
try:
|
||||
tool_response = galaxy_interactor.run_tool(testdef, test_history, resource_parameters=resource_parameters)
|
||||
@@ -662,7 +663,7 @@ def verify_tool(tool_id, galaxy_interactor, resource_parameters={}, register_job
|
||||
assert data_list or data_collection_list
|
||||
|
||||
try:
|
||||
job_stdio = _verify_outputs(testdef, test_history, jobs, tool_id, data_list, data_collection_list, galaxy_interactor)
|
||||
job_stdio = _verify_outputs(testdef, test_history, jobs, tool_id, data_list, data_collection_list, galaxy_interactor, quiet=quiet)
|
||||
except JobOutputsError as e:
|
||||
job_stdio = e.job_stdio
|
||||
job_output_exceptions = e.output_exceptions
|
||||
@@ -671,16 +672,26 @@ def verify_tool(tool_id, galaxy_interactor, resource_parameters={}, register_job
|
||||
job_output_exceptions = [e]
|
||||
raise e
|
||||
finally:
|
||||
job_data = {}
|
||||
if tool_inputs is not None:
|
||||
job_data["inputs"] = tool_inputs
|
||||
if job_stdio is not None:
|
||||
job_data["job"] = job_stdio
|
||||
if job_output_exceptions:
|
||||
job_data["output_problems"] = [str(_) for _ in job_output_exceptions]
|
||||
if tool_execution_exception:
|
||||
job_data["execution_problem"] = str(tool_execution_exception)
|
||||
if register_job_data is not None:
|
||||
end_time = time.time()
|
||||
job_data = {
|
||||
"tool_id": tool_id,
|
||||
"tool_version": tool_version,
|
||||
"test_index": test_index,
|
||||
"time_seconds": end_time - begin_time,
|
||||
}
|
||||
if tool_inputs is not None:
|
||||
job_data["inputs"] = tool_inputs
|
||||
if job_stdio is not None:
|
||||
job_data["job"] = job_stdio
|
||||
status = "success"
|
||||
if job_output_exceptions:
|
||||
job_data["output_problems"] = [str(_) for _ in job_output_exceptions]
|
||||
status = "failure"
|
||||
if tool_execution_exception:
|
||||
job_data["execution_problem"] = str(tool_execution_exception)
|
||||
status = "error"
|
||||
job_data["status"] = status
|
||||
register_job_data(job_data)
|
||||
|
||||
galaxy_interactor.delete_history(test_history)
|
||||
@@ -698,7 +709,7 @@ def _handle_def_errors(testdef):
|
||||
raise Exception("Test parse failure")
|
||||
|
||||
|
||||
def _verify_outputs(testdef, history, jobs, tool_id, data_list, data_collection_list, galaxy_interactor):
|
||||
def _verify_outputs(testdef, history, jobs, tool_id, data_list, data_collection_list, galaxy_interactor, quiet=False):
|
||||
assert len(jobs) == 1, "Test framework logic error, somehow tool test resulted in more than one job."
|
||||
job = jobs[0]
|
||||
|
||||
@@ -713,7 +724,7 @@ def _verify_outputs(testdef, history, jobs, tool_id, data_list, data_collection_
|
||||
found_exceptions = []
|
||||
|
||||
def register_exception(e):
|
||||
if not found_exceptions:
|
||||
if not found_exceptions and not quiet:
|
||||
# Only print this stuff out once.
|
||||
for stream in ['stdout', 'stderr']:
|
||||
if stream in job_stdio:
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
|
||||
from galaxy.tools.verify.interactor import GalaxyInteractorApi, verify_tool
|
||||
|
||||
DESCRIPTION = "Script to quickly run a tool test against a running Galaxy instance."
|
||||
DESCRIPTION = """Script to quickly run a tool test against a running Galaxy instance."""
|
||||
ALL_TESTS = "*all_tests*"
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
@@ -20,35 +23,70 @@ def main(argv=None):
|
||||
"keep_outputs_dir": args.output,
|
||||
}
|
||||
tool_id = args.tool_id
|
||||
test_index = int(args.test_index)
|
||||
tool_version = args.tool_version
|
||||
|
||||
galaxy_interactor = GalaxyInteractorApi(**galaxy_interactor_kwds)
|
||||
raw_test_index = args.test_index
|
||||
if raw_test_index == ALL_TESTS:
|
||||
tool_test_dicts = galaxy_interactor.get_tool_tests(tool_id, tool_version=tool_version)
|
||||
test_indices = list(range(len(tool_test_dicts)))
|
||||
else:
|
||||
test_indices = [int(raw_test_index)]
|
||||
|
||||
test_results = []
|
||||
|
||||
def _register_job_data(job_data):
|
||||
test_results.append({
|
||||
'id': tool_id + "-" + str(test_index),
|
||||
'has_data': True,
|
||||
'data': job_data,
|
||||
})
|
||||
if args.append:
|
||||
with open(args.output_json, "r") as f:
|
||||
previous_results = json.load(f)
|
||||
test_results = previous_results["tests"]
|
||||
|
||||
try:
|
||||
verify_tool(
|
||||
tool_id, galaxy_interactor, test_index=test_index, tool_version=tool_version, register_job_data=_register_job_data
|
||||
)
|
||||
finally:
|
||||
report_obj = {
|
||||
'version': '0.1',
|
||||
'tests': test_results,
|
||||
}
|
||||
output_json = args.output_json
|
||||
if output_json:
|
||||
exceptions = []
|
||||
verbose = args.verbose
|
||||
for test_index in test_indices:
|
||||
if tool_version:
|
||||
tool_id_and_version = "%s/%s" % (tool_id, tool_version)
|
||||
else:
|
||||
tool_id_and_version = tool_id
|
||||
|
||||
test_identifier = "tool %s test # %d" % (tool_id_and_version, test_index)
|
||||
|
||||
def register(job_data):
|
||||
test_results.append({
|
||||
'id': tool_id + "-" + str(test_index),
|
||||
'has_data': True,
|
||||
'data': job_data,
|
||||
})
|
||||
|
||||
try:
|
||||
verify_tool(
|
||||
tool_id, galaxy_interactor, test_index=test_index, tool_version=tool_version,
|
||||
register_job_data=register, quiet=not verbose
|
||||
)
|
||||
|
||||
if verbose:
|
||||
print("%s passed" % test_identifier)
|
||||
|
||||
except Exception as e:
|
||||
if verbose:
|
||||
print("%s failed, %s" % (test_identifier, e))
|
||||
exceptions.append(e)
|
||||
|
||||
report_obj = {
|
||||
'version': '0.1',
|
||||
'tests': test_results,
|
||||
}
|
||||
output_json = args.output_json
|
||||
if output_json:
|
||||
if args.output_json == "-":
|
||||
assert not args.append
|
||||
print(json.dumps(report_obj))
|
||||
else:
|
||||
with open(args.output_json, "w") as f:
|
||||
print(report_obj)
|
||||
json.dump(report_obj, f)
|
||||
|
||||
if exceptions:
|
||||
raise exceptions[0]
|
||||
|
||||
|
||||
def _arg_parser():
|
||||
parser = argparse.ArgumentParser(description=DESCRIPTION)
|
||||
@@ -57,9 +95,11 @@ def _arg_parser():
|
||||
parser.add_argument('-a', '--admin-key', default=None, help='Galaxy Admin API Key')
|
||||
parser.add_argument('-t', '--tool-id', default=None, help='Tool ID')
|
||||
parser.add_argument('--tool-version', default=None, help='Tool Version')
|
||||
parser.add_argument('-i', '--test-index', default=0, help='Tool Test Index (starting at 0)')
|
||||
parser.add_argument('-i', '--test-index', default=ALL_TESTS, help='Tool Test Index (starting at 0) - by default all tests will run.')
|
||||
parser.add_argument('-o', '--output', default=None, help='directory to dump outputs to')
|
||||
parser.add_argument('-j', '--output_json', default=None, help='output metadata json')
|
||||
parser.add_argument('--append', default=False, action="store_true", help="Extend a test record json (created with --output-json) with additional tests.")
|
||||
parser.add_argument('-j', '--output-json', default=None, help='output metadata json')
|
||||
parser.add_argument('--verbose', default=False, action="store_true", help="Verbose logging.")
|
||||
return parser
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import shlex
|
||||
import stat
|
||||
import string
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
from itertools import product
|
||||
from subprocess import PIPE, Popen
|
||||
@@ -442,7 +443,20 @@ class InteractiveEnvironmentRequest(object):
|
||||
"""
|
||||
run_args = self.container_run_args(image, env_override, volumes)
|
||||
container = self.attr.container_interface.run_in_container(None, **run_args)
|
||||
container_port = self._find_port_mapping(container.ports)
|
||||
attempt = 0
|
||||
container_ports = container.ports
|
||||
while container_ports is None and attempt < 30:
|
||||
# TODO: it would be better to do this in /interactive_environments/ready so the client doesn't block here,
|
||||
# but _find_port_mapping needs certain non-persisted data (the port configured to be published) and the
|
||||
# proxy manager doesn't have an update method, so that'd require bigger changes than I have the time for
|
||||
# right now
|
||||
attempt += 1
|
||||
log.warning("Sleeping for 2 seconds while waiting for container %s ports", container.id)
|
||||
time.sleep(2)
|
||||
container_ports = container.ports
|
||||
if container_ports is None:
|
||||
raise Exception("Failed to determine ports for container '%s' after 30 attempts" % container.id)
|
||||
container_port = self._find_port_mapping(container_ports)
|
||||
log.debug("Container '%s' accessible at: %s:%s", container.id, container_port.hostaddr, container_port.hostport)
|
||||
self.attr.proxy_request = self.trans.app.proxy_manager.setup_proxy(
|
||||
self.trans,
|
||||
|
||||
@@ -270,6 +270,14 @@ class InteractiveEnvironmentPlugin(VisualizationPlugin):
|
||||
context['base_url'] = 'interactive_environments'
|
||||
super(InteractiveEnvironmentPlugin, self).__init__(app, path, name, config, context=context, **kwargs)
|
||||
|
||||
def _error_template(self, trans):
|
||||
return trans.fill_template('message.mako',
|
||||
message='Loading the interactive environment failed, please contact the {admin_tag} for assistance'.format(
|
||||
admin_tag='<a href="mailto:{admin_mail}">Galaxy administrator</a>'.format(
|
||||
admin_mail=trans.app.config.error_email_to)
|
||||
if trans.app.config.error_email_to else 'Galaxy administrator'),
|
||||
status='error')
|
||||
|
||||
def _render(self, render_vars, trans=None, embedded=None, **kwargs):
|
||||
"""
|
||||
Override to add interactive environment specific template vars.
|
||||
@@ -295,16 +303,15 @@ class InteractiveEnvironmentPlugin(VisualizationPlugin):
|
||||
request = self.INTENV_REQUEST_FACTORY(trans, self)
|
||||
except Exception:
|
||||
log.exception("IE plugin request handling failed")
|
||||
return trans.fill_template('message.mako',
|
||||
message='Loading the interactive environment failed, please contact the {admin_tag} for assistance'.format(
|
||||
admin_tag='<a href="mailto:{admin_mail}">Galaxy administrator</a>'.format(
|
||||
admin_mail=trans.app.config.error_email_to)
|
||||
if trans.app.config.error_email_to else 'Galaxy administrator'),
|
||||
status='error')
|
||||
return self._error_template(trans)
|
||||
render_vars["ie_request"] = request
|
||||
|
||||
template_filename = self.config['entry_point']['file']
|
||||
return trans.fill_template(template_filename, template_lookup=self.template_lookup, **render_vars)
|
||||
try:
|
||||
return trans.fill_template(template_filename, template_lookup=self.template_lookup, **render_vars)
|
||||
except Exception:
|
||||
log.exception("IE plugin template fill failed")
|
||||
return self._error_template(trans)
|
||||
|
||||
def _get_url(self):
|
||||
return url_for('interactive_environment_plugin', visualization_name=self.name)
|
||||
|
||||
@@ -494,11 +494,10 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
history = trans.sa_session.query(model.History).options(
|
||||
eagerload_all('active_datasets.creating_job_associations.job.workflow_invocation_step.workflow_invocation.workflow'),
|
||||
).get(id)
|
||||
assert history
|
||||
# TODO: formalize to trans.show_error
|
||||
assert (history.user and (history.user.id == trans.user.id) or
|
||||
(history.id == trans.history.id) or
|
||||
(trans.user_is_admin()))
|
||||
if not (history and ((history.user and trans.user and history.user.id == trans.user.id) or
|
||||
(trans.history and history.id == trans.history.id) or
|
||||
trans.user_is_admin())):
|
||||
return trans.show_error_message("Cannot display history structure.")
|
||||
# Resolve jobs and workflow invocations for the datasets in the history
|
||||
# items is filled with items (hdas, jobs, or workflows) that go at the
|
||||
# top level
|
||||
@@ -1127,7 +1126,7 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
@web.expose
|
||||
def purge_deleted_datasets(self, trans):
|
||||
count = 0
|
||||
if trans.app.config.allow_user_dataset_purge:
|
||||
if trans.app.config.allow_user_dataset_purge and trans.history:
|
||||
for hda in trans.history.datasets:
|
||||
if not hda.deleted or hda.purged:
|
||||
continue
|
||||
@@ -1145,7 +1144,8 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
except Exception:
|
||||
log.exception('Unable to purge dataset (%s) on purge of hda (%s):' % (hda.dataset.id, hda.id))
|
||||
count += 1
|
||||
return trans.show_ok_message("%d datasets have been deleted permanently" % count, refresh_frames=['history'])
|
||||
return trans.show_ok_message("%d datasets have been deleted permanently" % count, refresh_frames=['history'])
|
||||
return trans.show_error_message("Cannot purge deleted datasets from this session.")
|
||||
|
||||
@web.expose
|
||||
def delete(self, trans, id, purge=False):
|
||||
|
||||
@@ -925,7 +925,9 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
Check whether token fits the user and then activate the user's account.
|
||||
"""
|
||||
params = util.Params(kwd, sanitize=False)
|
||||
email = unquote(params.get('email', None))
|
||||
email = params.get('email', None)
|
||||
if email is not None:
|
||||
email = unquote(email)
|
||||
activation_token = params.get('activation_token', None)
|
||||
|
||||
if email is None or activation_token is None:
|
||||
@@ -934,6 +936,9 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
else:
|
||||
# Find the user
|
||||
user = trans.sa_session.query(trans.app.model.User).filter(trans.app.model.User.table.c.email == email).first()
|
||||
if not user:
|
||||
# Probably wrong email address
|
||||
return trans.show_error_message("You are using an invalid activation link. Try to log in and we will send you a new activation email. <br><a href='%s'>Go to login page.</a>") % web.url_for(controller="root", action="index")
|
||||
# If the user is active already don't try to activate
|
||||
if user.active is True:
|
||||
return trans.show_ok_message("Your account is already active. Nothing has changed. <br><a href='%s'>Go to login page.</a>") % web.url_for(controller='root', action='index')
|
||||
|
||||
@@ -43,6 +43,7 @@ def copy_sample_file(app, filename, dest_path=None):
|
||||
"""
|
||||
Copies a sample file at `filename` to `the dest_path`
|
||||
directory and strips the '.sample' extensions from `filename`.
|
||||
Returns the path to the copied file (with the .sample extension).
|
||||
"""
|
||||
if dest_path is None:
|
||||
dest_path = os.path.abspath(app.config.tool_data_path)
|
||||
@@ -56,8 +57,10 @@ def copy_sample_file(app, filename, dest_path=None):
|
||||
shutil.copy(full_source_path, full_destination_path)
|
||||
# Only create the .loc file if it does not yet exist. We don't overwrite it in case it
|
||||
# contains stuff proprietary to the local instance.
|
||||
if not os.path.lexists(os.path.join(dest_path, copied_file)):
|
||||
non_sample_path = os.path.join(dest_path, copied_file)
|
||||
if not os.path.lexists(non_sample_path):
|
||||
shutil.copy(full_source_path, os.path.join(dest_path, copied_file))
|
||||
return non_sample_path
|
||||
|
||||
|
||||
def copy_sample_files(app, sample_files, tool_path=None, sample_files_copied=None, dest_path=None):
|
||||
@@ -159,10 +162,10 @@ def handle_missing_index_file(app, tool_path, sample_files, repository_tools_tup
|
||||
for sample_file in sample_files:
|
||||
sample_file_name = basic_util.strip_path(sample_file)
|
||||
if sample_file_name == '%s.sample' % missing_file_name:
|
||||
copy_sample_file(app, os.path.join(tool_path, sample_file))
|
||||
target_path = copy_sample_file(app, os.path.join(tool_path, sample_file))
|
||||
if options.tool_data_table and options.tool_data_table.missing_index_file:
|
||||
options.tool_data_table.handle_found_index_file(options.missing_index_file)
|
||||
sample_files_copied.append(options.missing_index_file)
|
||||
options.tool_data_table.handle_found_index_file(target_path)
|
||||
sample_files_copied.append(target_path)
|
||||
break
|
||||
return repository_tools_tups, sample_files_copied
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ except ImportError:
|
||||
return x
|
||||
|
||||
from base.driver_util import setup_keep_outdir, target_url_parts
|
||||
from base.instrument import register_job_data
|
||||
from galaxy.tools import DataManagerTool # noqa: I201
|
||||
from galaxy.tools.verify.interactor import GalaxyInteractorApi, verify_tool # noqa: I201
|
||||
from .twilltestcase import TwillTestCase
|
||||
@@ -37,7 +38,7 @@ class ToolTestCase(TwillTestCase):
|
||||
tool_id = self.tool_id
|
||||
assert tool_id
|
||||
|
||||
verify_tool(tool_id, self.galaxy_interactor, resource_parameters=resource_parameters, test_index=test_index, tool_version=tool_version)
|
||||
verify_tool(tool_id, self.galaxy_interactor, resource_parameters=resource_parameters, test_index=test_index, tool_version=tool_version, register_job_data=register_job_data)
|
||||
|
||||
|
||||
@nottest
|
||||
|
||||
+4
-4
@@ -23,13 +23,13 @@
|
||||
</command>
|
||||
<inputs>
|
||||
<param name="input1" type="data" format="sam" label="SAM file" optional="true"/>
|
||||
<param name="input2" type="data" format="bam_native" label="Unsorted BAM file" optional="true"/>
|
||||
<param name="input2" type="data" format="unsorted.bam" label="Unsorted BAM file" optional="true"/>
|
||||
<param name="input3" type="data" format="bam" label="BAM file sorted by coordinate" optional="true"/>
|
||||
<param name="input4" type="data" format="qname_sorted.bam" label="BAM file sorted by queryname" optional="true"/>
|
||||
<param name="input5" type="data" format="qname_input_sorted.bam" label="BAM file with sort order determined by the aligner" optional="true"/>
|
||||
</inputs>
|
||||
<outputs>
|
||||
<data name="bam_native_output" format="bam_native">
|
||||
<data name="bam_native_output" format="unsorted.bam">
|
||||
<filter>input1 or input2</filter>
|
||||
</data>
|
||||
<data name="bam_output" format="bam">
|
||||
@@ -46,12 +46,12 @@
|
||||
<!-- Test that bam native output won't be sorted-->
|
||||
<test>
|
||||
<param name="input1" value="sam_with_header.sam" ftype="sam"/>
|
||||
<output name="bam_native_output" file="bam_native_from_sam.bam" ftype="bam_native"/>
|
||||
<output name="bam_native_output" file="bam_native_from_sam.bam" ftype="unsorted.bam"/>
|
||||
</test>
|
||||
<!-- Test that sam input is properly converted to bam native -->
|
||||
<test>
|
||||
<param name="input2" value="sam_with_header.sam" ftype="sam"/>
|
||||
<output name="bam_native_output" file="bam_native_from_sam.bam" ftype="bam_native"/>
|
||||
<output name="bam_native_output" file="bam_native_from_sam.bam" ftype="unsorted.bam"/>
|
||||
</test>
|
||||
<!-- Test that sam input is properly converted to bam -->
|
||||
<test>
|
||||
@@ -22,7 +22,7 @@
|
||||
<converter file="fastqsangerbz2_to_fastqsanger.xml" target_datatype="fastqsanger"/>
|
||||
</datatype>
|
||||
<datatype extension="sam" type="galaxy.datatypes.tabular:Sam" display_in_upload="true">
|
||||
<converter file="sam_to_bam_native.xml" target_datatype="bam_native"/>
|
||||
<converter file="sam_to_unsorted_bam.xml" target_datatype="unsorted.bam"/>
|
||||
<converter file="to_qname_sorted_bam.xml" target_datatype="qname_sorted.bam"/>
|
||||
<converter file="to_coordinate_sorted_bam.xml" target_datatype="bam"/>
|
||||
<converter file="sam_to_bigwig_converter.xml" target_datatype="bigwig"/>
|
||||
@@ -30,7 +30,7 @@
|
||||
<datatype extension="bam" type="galaxy.datatypes.binary:Bam" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://galaxyproject.org/learn/datatypes/#bam" />
|
||||
<datatype extension="qname_input_sorted.bam" type="galaxy.datatypes.binary:BamInputSorted" mimetype="application/octet-stream" display_in_upload="false" description="A binary file compressed in the BGZF format with a '.bam' file extension and sorted based on the aligner output." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM"/>
|
||||
<datatype extension="qname_sorted.bam" type="galaxy.datatypes.binary:BamQuerynameSorted" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension and sorted by queryname." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM"/>
|
||||
<datatype extension="bam_native" type="galaxy.datatypes.binary:BamNative" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM">
|
||||
<datatype extension="unsorted.bam" type="galaxy.datatypes.binary:BamNative" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM">
|
||||
<converter file="bam_to_bigwig_converter.xml" target_datatype="bigwig"/>
|
||||
<converter file="to_coordinate_sorted_bam.xml" target_datatype="bam"/>
|
||||
<converter file="to_qname_sorted_bam.xml" target_datatype="qname_sorted.bam"/>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<tool file="column_multi_param.xml" />
|
||||
<tool file="special_params.xml" />
|
||||
<tool file="section.xml" />
|
||||
<tool file="sam_to_bam_native.xml" />
|
||||
<tool file="sam_to_unsorted_bam.xml" />
|
||||
<tool file="top_level_data.xml" />
|
||||
<tool file="validation_default.xml" />
|
||||
<tool file="validation_sanitizer.xml" />
|
||||
|
||||
Reference in New Issue
Block a user