mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'visualization_header' into dev
This commit is contained in:
@@ -17,13 +17,13 @@ import Workflows from "mvc/workflow/workflow";
|
||||
import HistoryImport from "components/HistoryImport.vue";
|
||||
import HistoryView from "components/HistoryView.vue";
|
||||
import HistoryList from "mvc/history/history-list";
|
||||
import PluginList from "components/PluginList.vue";
|
||||
import ToolFormComposite from "mvc/tool/tool-form-composite";
|
||||
import QueryStringParsing from "utils/query-string-parsing";
|
||||
import Utils from "utils/utils";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import DatasetError from "mvc/dataset/dataset-error";
|
||||
import DatasetEditAttributes from "mvc/dataset/dataset-edit-attributes";
|
||||
import Visualization from "mvc/visualization/visualization-view";
|
||||
import Citations from "components/Citations.vue";
|
||||
import DisplayStructure from "components/DisplayStructured.vue";
|
||||
import Vue from "vue";
|
||||
@@ -57,9 +57,9 @@ window.app = function app(options, bootstrapped) {
|
||||
"(/)pages(/)create(/)": "show_pages_create",
|
||||
"(/)pages(/)edit(/)": "show_pages_edit",
|
||||
"(/)pages(/)(:action_id)": "show_pages",
|
||||
"(/)visualizations(/)": "show_plugins",
|
||||
"(/)visualizations(/)edit(/)": "show_visualizations_edit",
|
||||
"(/)visualizations/show/(:visualization_id)": "show_visualizations_client",
|
||||
"(/)visualizations/dataset_id=(:dataset_id)": "show_visualizations_selector",
|
||||
"(/)visualizations/(:action_id)": "show_visualizations",
|
||||
"(/)workflows/import_workflow": "show_import_workflow",
|
||||
"(/)workflows/run(/)": "show_run",
|
||||
@@ -101,14 +101,11 @@ window.app = function app(options, bootstrapped) {
|
||||
var model = new UserPreferences.Model({
|
||||
user_id: Galaxy.params.id
|
||||
});
|
||||
this.page.display(new FormWrapper.View(_.extend(
|
||||
model.get(form_id),
|
||||
{active_tab: "user"}
|
||||
)));
|
||||
this.page.display(new FormWrapper.View(_.extend(model.get(form_id), { active_tab: "user" })));
|
||||
},
|
||||
|
||||
show_visualizations: function(action_id) {
|
||||
var activeTab = action_id=="list_published"?"shared":"visualization";
|
||||
var activeTab = action_id == "list_published" ? "shared" : "visualization";
|
||||
this.page.display(
|
||||
new GridShared.View({
|
||||
action_id: action_id,
|
||||
@@ -129,14 +126,6 @@ window.app = function app(options, bootstrapped) {
|
||||
);
|
||||
},
|
||||
|
||||
show_visualizations_selector: function(dataset_id) {
|
||||
this.page.display(
|
||||
new Visualization.View({
|
||||
dataset_id: dataset_id
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
show_workflows_published: function() {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
@@ -215,7 +204,7 @@ window.app = function app(options, bootstrapped) {
|
||||
},
|
||||
|
||||
show_pages: function(action_id) {
|
||||
var activeTab = action_id=="list_published"?"shared":"user";
|
||||
var activeTab = action_id == "list_published" ? "shared" : "user";
|
||||
this.page.display(
|
||||
new GridShared.View({
|
||||
action_id: action_id,
|
||||
@@ -246,6 +235,13 @@ window.app = function app(options, bootstrapped) {
|
||||
);
|
||||
},
|
||||
|
||||
show_plugins: function() {
|
||||
var pluginListInstance = Vue.extend(PluginList);
|
||||
var vm = document.createElement("div");
|
||||
this.page.display(vm);
|
||||
new pluginListInstance().$mount(vm);
|
||||
},
|
||||
|
||||
show_workflows: function() {
|
||||
this.page.display(new Workflows.View());
|
||||
},
|
||||
@@ -331,10 +327,7 @@ window.app = function app(options, bootstrapped) {
|
||||
Utils.get({
|
||||
url: `${Galaxy.root}api/workflows/${Utils.getQueryString("id")}/download?style=run`,
|
||||
success: response => {
|
||||
this.page.display(new ToolFormComposite.View(_.extend(
|
||||
response,
|
||||
{active_tab: "workflow"}
|
||||
)));
|
||||
this.page.display(new ToolFormComposite.View(_.extend(response, { active_tab: "workflow" })));
|
||||
},
|
||||
error: response => {
|
||||
var error_msg = response.err_msg || "Error occurred while loading the resource.";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="portlet-content">
|
||||
<div v-if="errormessage" class="ui-message alert alert-danger">
|
||||
<div v-if="errormessage" class="ui-message ui-show alert alert-danger">
|
||||
{{ errormessage }}
|
||||
</div>
|
||||
<div class="portlet-body">
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.ui-message {
|
||||
.ui-show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="ui-thumbnails">
|
||||
<div v-if="error" class="ui-message ui-show alert alert-danger">
|
||||
{{ error }}
|
||||
</div>
|
||||
<div v-else class="ui-thumbnails-grid">
|
||||
<input class="search-query parent-width" name="query" placeholder="search visualizations" autocomplete="off" type="text" v-model="search">
|
||||
<div v-for="plugin in plugins">
|
||||
<table v-if="match(plugin)">
|
||||
<tr class="ui-thumbnails-item" @click="select(plugin)">
|
||||
<td>
|
||||
<img v-if="plugin.logo" class="ui-thumbnails-image" :src="plugin.logo"/>
|
||||
<div v-else class="ui-thumbnails-icon fa fa-eye"/>
|
||||
</td>
|
||||
<td>
|
||||
<div class="ui-thumbnails-description-title ui-form-info">
|
||||
{{ plugin.html }}
|
||||
</div>
|
||||
<div class="ui-thumbnails-description-text ui-form-info">
|
||||
{{ plugin.description }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="!fixed">
|
||||
<td/>
|
||||
<td v-if="plugin.name == name">
|
||||
<div v-if="hdas && hdas.length > 0">
|
||||
<div class="ui-form-info ui-bold">Select a dataset to visualize:</div>
|
||||
<div class="ui-select">
|
||||
<select class="select" v-model="selected">
|
||||
<option v-for="file in hdas" :value="file.id">{{ file.name }}</option>
|
||||
</select>
|
||||
<div class="icon-dropdown fa fa-caret-down"/>
|
||||
</div>
|
||||
<button type="button" class="ui-button-default ui-float-left btn btn-primary" @click="create(plugin)">
|
||||
<i class="icon fa fa-check ui-margin-right"/>
|
||||
<span class="title">Create Visualization</span>
|
||||
</button>
|
||||
</div>
|
||||
<div v-else class="ui-message ui-show alert alert-danger">
|
||||
There is no suitable dataset in your current history which can be visualized with this plugin.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from "axios";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
plugins: [],
|
||||
hdas: [],
|
||||
search: "",
|
||||
selected: null,
|
||||
name: null,
|
||||
error: null,
|
||||
fixed: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let url = `${Galaxy.root}api/plugins`;
|
||||
let dataset_id = Galaxy.params.dataset_id;
|
||||
if (dataset_id) {
|
||||
this.fixed = true;
|
||||
this.selected = dataset_id;
|
||||
url += `?dataset_id=${dataset_id}`;
|
||||
}
|
||||
axios.get(url)
|
||||
.then(response => {
|
||||
this.plugins = response.data;
|
||||
})
|
||||
.catch(e => {
|
||||
this.error = this._errorMessage(e);
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
select: function(plugin) {
|
||||
if (this.fixed) {
|
||||
this.create(plugin);
|
||||
} else {
|
||||
let history_id = Galaxy.currHistoryPanel && Galaxy.currHistoryPanel.model.id;
|
||||
if (history_id) {
|
||||
axios.get(`${Galaxy.root}api/plugins/${plugin.name}?history_id=${history_id}`)
|
||||
.then(response => {
|
||||
this.name = plugin.name;
|
||||
this.hdas = response.data && response.data.hdas;
|
||||
if (this.hdas && this.hdas.length > 0) {
|
||||
this.selected = this.hdas[0].id;
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
this.error = this._errorMessage(e);
|
||||
})
|
||||
} else {
|
||||
this.error = "This option requires an accessible history.";
|
||||
}
|
||||
}
|
||||
},
|
||||
create: function(plugin) {
|
||||
let href = `${plugin.href}?dataset_id=${this.selected}`;
|
||||
if (plugin.target == "_top") {
|
||||
window.location.href = href;
|
||||
} else {
|
||||
$("#galaxy_main").attr("src", href);
|
||||
}
|
||||
},
|
||||
match: function(plugin) {
|
||||
return !this.search ||
|
||||
plugin.name.indexOf(this.search) != -1 ||
|
||||
(plugin.description && plugin.description.indexOf(this.search) != -1);
|
||||
},
|
||||
_errorMessage: function(e) {
|
||||
let message = e && e.response && e.response.data && e.response.data.err_msg;
|
||||
return message || "Request failed for unkown reason.";
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.ui-show {
|
||||
display: block;
|
||||
margin-top: 0px;
|
||||
}
|
||||
.ui-bold {
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.ui-float-left {
|
||||
float: left;
|
||||
margin-top:10px;
|
||||
}
|
||||
</style>
|
||||
@@ -42,6 +42,33 @@ var Collection = Backbone.Collection.extend({
|
||||
url: "workflows/list"
|
||||
});
|
||||
|
||||
//
|
||||
// Visualization tab.
|
||||
//
|
||||
this.add({
|
||||
id: "visualization",
|
||||
title: _l("Visualize"),
|
||||
url: "visualizations/list",
|
||||
tooltip: _l("Visualize datasets"),
|
||||
disabled: !Galaxy.user.id,
|
||||
menu: [
|
||||
{
|
||||
title: _l("Create Visualization"),
|
||||
url: "visualizations"
|
||||
},
|
||||
{
|
||||
title: _l("Interactive Environments"),
|
||||
url: "visualization/gie_list",
|
||||
target: "galaxy_main"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Visualizations"),
|
||||
url: "visualizations/list",
|
||||
target: "_frame"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
//
|
||||
// 'Shared Items' or Libraries tab.
|
||||
//
|
||||
@@ -74,34 +101,6 @@ var Collection = Backbone.Collection.extend({
|
||||
]
|
||||
});
|
||||
|
||||
//
|
||||
// Visualization tab.
|
||||
//
|
||||
this.add({
|
||||
id: "visualization",
|
||||
title: _l("Visualization"),
|
||||
url: "visualizations/list",
|
||||
tooltip: _l("Visualize datasets"),
|
||||
disabled: !Galaxy.user.id,
|
||||
menu: [
|
||||
{
|
||||
title: _l("New Track Browser"),
|
||||
url: "visualization/trackster",
|
||||
target: "_frame"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Visualizations"),
|
||||
url: "visualizations/list",
|
||||
target: "_frame"
|
||||
},
|
||||
{
|
||||
title: _l("Interactive Environments"),
|
||||
url: "visualization/gie_list",
|
||||
target: "galaxy_main"
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
//
|
||||
// Webhooks
|
||||
//
|
||||
@@ -272,20 +271,25 @@ var Collection = Backbone.Collection.extend({
|
||||
target: "_top",
|
||||
divider: true
|
||||
},
|
||||
{
|
||||
title: _l("Saved Histories"),
|
||||
url: "histories/list",
|
||||
target: "_top"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Datasets"),
|
||||
url: "datasets/list",
|
||||
target: "_top"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Histories"),
|
||||
url: "histories/list",
|
||||
target: "_top"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Pages"),
|
||||
url: "pages/list",
|
||||
target: "_top"
|
||||
},
|
||||
{
|
||||
title: _l("Saved Visualizations"),
|
||||
url: "visualizations/list",
|
||||
target: "_top"
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -340,13 +344,13 @@ var Tab = Backbone.View.extend({
|
||||
.attr("title", this.model.get("tooltip"))
|
||||
.tooltip("destroy");
|
||||
this.model.get("tooltip") && this.$toggle.tooltip({ placement: "bottom" });
|
||||
if(!this.model.get("menu")){
|
||||
if (!this.model.get("menu")) {
|
||||
this.$dropdown
|
||||
.removeClass()
|
||||
.addClass("dropdown")
|
||||
.addClass(this.model.get("disabled") && "disabled")
|
||||
.addClass(this.model.get("active") && "active");
|
||||
};
|
||||
}
|
||||
if (this.model.get("menu") && this.model.get("show_menu")) {
|
||||
this.$menu.show();
|
||||
$("#dd-helper")
|
||||
|
||||
@@ -261,7 +261,7 @@ var DatasetListItemEdit = _super.extend(
|
||||
}
|
||||
|
||||
if (visualizations.length >= 1) {
|
||||
var url = Galaxy.root + "visualizations/dataset_id=" + this.model.get("id");
|
||||
var url = Galaxy.root + "plugins?dataset_id=" + this.model.get("id");
|
||||
return $("<a/>")
|
||||
.addClass("visualization-link icon-btn")
|
||||
.attr("href", url)
|
||||
|
||||
@@ -6,7 +6,7 @@ var View = Backbone.View.extend({
|
||||
this.model = new Backbone.Model(options);
|
||||
this.url = this.model.get("url");
|
||||
this.redirect = this.model.get("redirect");
|
||||
if (options && options.active_tab){
|
||||
if (options && options.active_tab) {
|
||||
this.active_tab = options.active_tab;
|
||||
}
|
||||
this.setElement("<div/>");
|
||||
|
||||
@@ -9,7 +9,7 @@ var View = Backbone.View.extend({
|
||||
this.model = new Backbone.Model(options);
|
||||
this.item = this.model.get("item");
|
||||
this.title = this.model.get("plural");
|
||||
if (options && options.active_tab){
|
||||
if (options && options.active_tab) {
|
||||
this.active_tab = options.active_tab;
|
||||
}
|
||||
$.ajax({
|
||||
|
||||
@@ -107,10 +107,9 @@ var View = Backbone.View.extend({
|
||||
var self = this;
|
||||
LoadingIndicator.markViewAsLoading(this);
|
||||
|
||||
if(options.action_id == "list_published"){
|
||||
if (options.action_id == "list_published") {
|
||||
this.active_tab = "shared";
|
||||
}
|
||||
else if (options.action_id = "list"){
|
||||
} else if ((options.action_id = "list")) {
|
||||
this.active_tab = "user";
|
||||
}
|
||||
this.model = new Backbone.Model();
|
||||
|
||||
@@ -15,7 +15,7 @@ var View = Backbone.View.extend({
|
||||
this.modal = parent.Galaxy.modal || new Modal.View();
|
||||
this.model = (options && options.model) || new Backbone.Model(options);
|
||||
this.deferred = new Deferred();
|
||||
if (options && options.active_tab){
|
||||
if (options && options.active_tab) {
|
||||
this.active_tab = options.active_tab;
|
||||
}
|
||||
this.setElement(
|
||||
@@ -303,17 +303,17 @@ var View = Backbone.View.extend({
|
||||
});
|
||||
this._append(this.$steps, this.history_form.$el);
|
||||
},
|
||||
|
||||
|
||||
/** Render Workflow Options */
|
||||
_renderResourceParameters: function() {
|
||||
this.workflow_resource_parameters_form = null;
|
||||
if(!_.isEmpty(this.model.get('workflow_resource_parameters'))){
|
||||
if (!_.isEmpty(this.model.get("workflow_resource_parameters"))) {
|
||||
this.workflow_resource_parameters_form = new Form({
|
||||
cls : 'ui-portlet-narrow',
|
||||
title : '<b>Workflow Resource Options</b>',
|
||||
inputs : this.model.get('workflow_resource_parameters')
|
||||
cls: "ui-portlet-narrow",
|
||||
title: "<b>Workflow Resource Options</b>",
|
||||
inputs: this.model.get("workflow_resource_parameters")
|
||||
});
|
||||
this._append( this.$steps, this.workflow_resource_parameters_form.$el );
|
||||
this._append(this.$steps, this.workflow_resource_parameters_form.$el);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -538,7 +538,9 @@ var View = Backbone.View.extend({
|
||||
var job_def = {
|
||||
new_history_name: history_form_data["new_history|name"] ? history_form_data["new_history|name"] : null,
|
||||
history_id: !history_form_data["new_history|name"] ? this.model.get("history_id") : null,
|
||||
resource_params: this.workflow_resource_parameters_form ? this.workflow_resource_parameters_form.data.create() : {},
|
||||
resource_params: this.workflow_resource_parameters_form
|
||||
? this.workflow_resource_parameters_form.data.create()
|
||||
: {},
|
||||
replacement_params: this.wp_form ? this.wp_form.data.create() : {},
|
||||
parameters: {},
|
||||
// Tool form will submit flat maps for each parameter
|
||||
|
||||
@@ -14,7 +14,8 @@ var ButtonDefault = Backbone.View.extend({
|
||||
wait_text: "Sending...",
|
||||
wait_cls: "btn btn-info",
|
||||
disabled: false,
|
||||
percentage: -1
|
||||
percentage: -1,
|
||||
visible: true
|
||||
}).set(options);
|
||||
this.setElement(
|
||||
$("<button/>")
|
||||
@@ -36,6 +37,7 @@ var ButtonDefault = Backbone.View.extend({
|
||||
.addClass(options.disabled && "disabled")
|
||||
.attr("id", options.id)
|
||||
.attr("disabled", options.disabled)
|
||||
.css("display", options.visible ? "inline-block" : "none")
|
||||
.off("click")
|
||||
.on("click", () => {
|
||||
$(".tooltip").hide();
|
||||
@@ -60,12 +62,12 @@ var ButtonDefault = Backbone.View.extend({
|
||||
|
||||
/** Show button */
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
this.model.set("visible", true);
|
||||
},
|
||||
|
||||
/** Hide button */
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
this.model.set("visible", false);
|
||||
},
|
||||
|
||||
/** Disable button */
|
||||
@@ -101,6 +103,7 @@ var ButtonLink = ButtonDefault.extend({
|
||||
(options && options.model) ||
|
||||
new Backbone.Model({
|
||||
id: Utils.uid(),
|
||||
visible: true,
|
||||
title: "",
|
||||
icon: "",
|
||||
cls: ""
|
||||
@@ -122,6 +125,7 @@ var ButtonLink = ButtonDefault.extend({
|
||||
target: options.target || "_top",
|
||||
disabled: options.disabled
|
||||
})
|
||||
.css("display", options.visible ? "inline-block" : "none")
|
||||
.tooltip({ placement: "bottom" })
|
||||
.off("click")
|
||||
.on("click", () => {
|
||||
@@ -141,6 +145,7 @@ var ButtonCheck = Backbone.View.extend({
|
||||
title: "Select/Unselect all",
|
||||
icons: ["fa-square-o", "fa-minus-square-o", "fa-check-square-o"],
|
||||
value: 0,
|
||||
visible: true,
|
||||
onchange: function() {}
|
||||
}).set(options);
|
||||
this.setElement(
|
||||
@@ -157,6 +162,7 @@ var ButtonCheck = Backbone.View.extend({
|
||||
var options = this.model.attributes;
|
||||
this.$el
|
||||
.addClass("ui-button-check")
|
||||
.css("display", options.visible ? "inline-block" : "none")
|
||||
.off("click")
|
||||
.on("click", () => {
|
||||
self.model.set("value", (self.model.get("value") === 0 && 2) || 0);
|
||||
@@ -196,6 +202,7 @@ var ButtonIcon = ButtonDefault.extend({
|
||||
id: Utils.uid(),
|
||||
title: "",
|
||||
icon: "",
|
||||
visible: true,
|
||||
cls: "ui-button-icon",
|
||||
disabled: false
|
||||
}).set(options);
|
||||
@@ -217,6 +224,7 @@ var ButtonIcon = ButtonDefault.extend({
|
||||
.removeClass()
|
||||
.addClass(options.cls)
|
||||
.addClass(options.disabled && "disabled")
|
||||
.css("display", options.visible ? "inline-block" : "none")
|
||||
.attr("disabled", options.disabled)
|
||||
.attr("id", options.id)
|
||||
.off("click")
|
||||
|
||||
@@ -47,7 +47,7 @@ export var Message = Backbone.View.extend({
|
||||
fade: true
|
||||
}).set(options);
|
||||
this.listenTo(this.model, "change", this.render, this);
|
||||
if (options && options.active_tab){
|
||||
if (options && options.active_tab) {
|
||||
this.active_tab = options.active_tab;
|
||||
}
|
||||
this.render();
|
||||
|
||||
@@ -8,9 +8,9 @@ export default Backbone.Model.extend({
|
||||
date: null,
|
||||
state: "",
|
||||
state_info: "",
|
||||
modified: false,
|
||||
modified: true,
|
||||
dataset_id: "",
|
||||
dataset_id_job: ""
|
||||
dataset_id_job: null
|
||||
},
|
||||
|
||||
initialize: function(options, viz_options) {
|
||||
@@ -89,15 +89,16 @@ export default Backbone.Model.extend({
|
||||
}
|
||||
console.debug("model::save() - Saving failed.");
|
||||
});
|
||||
console.debug("model::save() - Saved with configuration:");
|
||||
console.debug(this.chart_last);
|
||||
console.debug("model::save() - Saving with configuration.");
|
||||
},
|
||||
|
||||
/** Load nested models/collections from packed dictionary */
|
||||
load: function(chart_parsed) {
|
||||
var d = chart_parsed || this.chart_dict;
|
||||
console.debug("model::load() - Attempting to load with configuration:");
|
||||
console.debug(d);
|
||||
if (d) {
|
||||
console.debug("model::load() - Attempting to load with configuration:");
|
||||
console.debug(d);
|
||||
}
|
||||
this.reset();
|
||||
if (d && d.attributes) {
|
||||
this.set(d.attributes);
|
||||
@@ -109,9 +110,11 @@ export default Backbone.Model.extend({
|
||||
this.trigger("load");
|
||||
console.debug("model::load() - Loading chart model " + d.attributes.type + ".");
|
||||
return true;
|
||||
} else {
|
||||
this.set("modified", true);
|
||||
this.trigger("load");
|
||||
console.debug("model::load() - Visualization attributes unavailable.");
|
||||
return false;
|
||||
}
|
||||
this.trigger("load");
|
||||
console.debug("model::load() - Visualization attributes unavailable.");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -125,6 +125,9 @@ var _fillFromCache = function(options) {
|
||||
});
|
||||
if (limit === 0) {
|
||||
console.debug("tabular-datasets::_fillFromCache() - No data available.");
|
||||
if (options.chart) {
|
||||
options.chart.state("failed", "No data available.");
|
||||
}
|
||||
}
|
||||
var results = [];
|
||||
groups.each(function(group, group_index) {
|
||||
|
||||
@@ -28,7 +28,7 @@ var requestCharts = function(chart, module) {
|
||||
});
|
||||
columns_string = columns_string.substring(0, columns_string.length - 2);
|
||||
return {
|
||||
tool_id: "charts",
|
||||
tool_id: "toolshed.g2.bx.psu.edu/repos/iuc/charts/charts/1.0.1",
|
||||
inputs: {
|
||||
input: {
|
||||
id: chart.get("dataset_id"),
|
||||
@@ -44,12 +44,19 @@ var requestCharts = function(chart, module) {
|
||||
/** Submit job request to charts tool */
|
||||
var request = function(chart, parameters, success, error) {
|
||||
chart.state("wait", "Requesting job results...");
|
||||
if (chart.get("modified")) {
|
||||
cleanup(chart);
|
||||
if (chart.get("modified") && chart.get("dataset_id_job")) {
|
||||
Utils.request({
|
||||
type: "PUT",
|
||||
url: Galaxy.root + "api/histories/none/contents/" + chart.get("dataset_id_job"),
|
||||
data: { deleted: true },
|
||||
success: () => {
|
||||
refreshHdas();
|
||||
}
|
||||
});
|
||||
chart.set("dataset_id_job", null);
|
||||
chart.set("modified", false);
|
||||
}
|
||||
var dataset_id_job = chart.get("dataset_id_job");
|
||||
if (dataset_id_job !== "") {
|
||||
if (chart.get("dataset_id_job")) {
|
||||
wait(chart, success, error);
|
||||
} else {
|
||||
chart.state("wait", "Sending job request...");
|
||||
@@ -95,22 +102,6 @@ var request = function(chart, parameters, success, error) {
|
||||
}
|
||||
};
|
||||
|
||||
/* Remove previous data when re-running jobs */
|
||||
var cleanup = function(chart) {
|
||||
var previous = chart.get("dataset_id_job");
|
||||
if (previous !== "") {
|
||||
Utils.request({
|
||||
type: "PUT",
|
||||
url: Galaxy.root + "api/histories/none/contents/" + previous,
|
||||
data: { deleted: true },
|
||||
success: function() {
|
||||
refreshHdas();
|
||||
}
|
||||
});
|
||||
chart.set("dataset_id_job", "");
|
||||
}
|
||||
};
|
||||
|
||||
/** Request job details */
|
||||
var wait = function(chart, success, error) {
|
||||
Utils.request({
|
||||
|
||||
@@ -66,6 +66,7 @@ var GroupView = Backbone.View.extend({
|
||||
cls: "ui-portlet-plain",
|
||||
onchange: function() {
|
||||
self.group.set(self.form.data.create());
|
||||
self.chart.set("modified", true);
|
||||
self.chart.trigger("redraw");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,6 +7,13 @@ export default Backbone.View.extend({
|
||||
initialize: function(app) {
|
||||
this.app = app;
|
||||
this.model = new Backbone.Model({ visible: true });
|
||||
this.execute_button = new Ui.ButtonIcon({
|
||||
icon: "fa-check-square",
|
||||
tooltip: "Confirm",
|
||||
onclick: () => {
|
||||
app.chart.trigger("redraw", true);
|
||||
}
|
||||
});
|
||||
this.export_button = new Ui.ButtonMenu({
|
||||
icon: "fa-camera",
|
||||
tooltip: "Export"
|
||||
@@ -72,53 +79,50 @@ export default Backbone.View.extend({
|
||||
});
|
||||
}
|
||||
});
|
||||
this.buttons = [
|
||||
new Ui.ButtonIcon({
|
||||
icon: "fa-angle-double-left",
|
||||
tooltip: "Show",
|
||||
cls: "ui-button-icon charts-fullscreen-button",
|
||||
onclick: () => {
|
||||
this.model.set("visible", true);
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
this.left_button = new Ui.ButtonIcon({
|
||||
icon: "fa-angle-double-left",
|
||||
tooltip: "Show",
|
||||
onclick: () => {
|
||||
this.model.set("visible", true);
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
}
|
||||
});
|
||||
this.right_button = new Ui.ButtonIcon({
|
||||
icon: "fa-angle-double-right",
|
||||
tooltip: "Hide",
|
||||
onclick: () => {
|
||||
this.model.set("visible", false);
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
}
|
||||
});
|
||||
this.save_button = new Ui.ButtonIcon({
|
||||
icon: "fa-save",
|
||||
tooltip: "Save",
|
||||
onclick: () => {
|
||||
if (app.chart.get("title")) {
|
||||
app.message.update({
|
||||
message: `Saving '${app.chart.get(
|
||||
"title"
|
||||
)}'. It will appear in the list of 'Saved Visualizations'.`,
|
||||
status: "success"
|
||||
});
|
||||
app.chart.save({
|
||||
error: () => {
|
||||
app.message.update({
|
||||
message: "Could not save visualization.",
|
||||
status: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
app.message.update({
|
||||
message: "Please provide a name.",
|
||||
status: "danger"
|
||||
});
|
||||
}
|
||||
}),
|
||||
new Ui.ButtonIcon({
|
||||
icon: "fa-angle-double-right",
|
||||
tooltip: "Hide",
|
||||
onclick: () => {
|
||||
this.model.set("visible", false);
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
}
|
||||
}),
|
||||
this.export_button,
|
||||
new Ui.ButtonIcon({
|
||||
icon: "fa-save",
|
||||
tooltip: "Save",
|
||||
onclick: () => {
|
||||
if (app.chart.get("title")) {
|
||||
app.message.update({
|
||||
message: `Saving '${app.chart.get(
|
||||
"title"
|
||||
)}'. It will appear in the list of 'Saved Visualizations'.`,
|
||||
status: "success"
|
||||
});
|
||||
app.chart.save({
|
||||
error: () => {
|
||||
app.message.update({
|
||||
message: "Could not save visualization.",
|
||||
status: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
app.message.update({
|
||||
message: "Please provide a name.",
|
||||
status: "danger"
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
];
|
||||
}
|
||||
});
|
||||
this.buttons = [this.left_button, this.right_button, this.execute_button, this.export_button, this.save_button];
|
||||
this.setElement("<div/>");
|
||||
for (let b of this.buttons) {
|
||||
this.$el.append(b.$el);
|
||||
@@ -130,7 +134,11 @@ export default Backbone.View.extend({
|
||||
render: function() {
|
||||
var visible = this.model.get("visible");
|
||||
this.app.$el[visible ? "removeClass" : "addClass"]("charts-fullscreen");
|
||||
this.execute_button.model.set("visible", visible && !!this.app.chart.plugin.specs.confirm);
|
||||
this.save_button.model.set("visible", visible);
|
||||
this.export_button.model.set("visible", visible);
|
||||
this.right_button.model.set("visible", visible);
|
||||
this.left_button.model.set("visible", !visible);
|
||||
var exports = this.app.chart.plugin.specs.exports || [];
|
||||
this.export_button.collection.each(model => {
|
||||
model.set("visible", exports.indexOf(model.get("key")) !== -1);
|
||||
|
||||
@@ -25,11 +25,15 @@ export default Backbone.View.extend({
|
||||
this.$text = this.$(".text");
|
||||
this._fullscreen(this.$el, 20);
|
||||
this._createContainer("div");
|
||||
this.chart.on("redraw", function() {
|
||||
self.app.deferred.execute(function(process) {
|
||||
console.debug("viewer:redraw() - Redrawing...");
|
||||
self._draw(process, self.chart);
|
||||
});
|
||||
this.chart.on("redraw", function(confirmed) {
|
||||
if (!self.chart.get("modified") || !self.chart.plugin.specs.confirm || confirmed) {
|
||||
self.app.deferred.execute(function(process) {
|
||||
console.debug("viewer:redraw() - Redrawing...");
|
||||
self._draw(process, self.chart);
|
||||
});
|
||||
} else {
|
||||
self.chart.state("info", "Please confirm the settings before rendering the results.");
|
||||
}
|
||||
});
|
||||
this.chart.on("set:state", function() {
|
||||
var $container = self.$(".charts-viewer-container");
|
||||
@@ -49,6 +53,10 @@ export default Backbone.View.extend({
|
||||
$icon.addClass("icon fa fa-warning");
|
||||
$container.hide();
|
||||
break;
|
||||
case "info":
|
||||
$icon.addClass("icon fa fa-info");
|
||||
$container.hide();
|
||||
break;
|
||||
default:
|
||||
$icon.addClass("icon fa fa-spinner fa-spin");
|
||||
$container.show();
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Visualization selection grid
|
||||
*/
|
||||
import Thumbnails from "mvc/ui/ui-thumbnails";
|
||||
var View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.setElement($("<div/>"));
|
||||
this.model = new Backbone.Model();
|
||||
this.active_tab = "visualization";
|
||||
$.ajax({
|
||||
url: `${Galaxy.root}api/datasets/${options.dataset_id}`
|
||||
}).done(dataset => {
|
||||
if (dataset.visualizations.length === 0) {
|
||||
self.$el.append(
|
||||
$("<div/>")
|
||||
.addClass("errormessagelarge")
|
||||
.append(
|
||||
$("<p/>").text(
|
||||
"Unfortunately we could not identify a suitable plugin. Feel free to contact us if you are aware of visualizations for this datatype."
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
self.model.set({ dataset: dataset });
|
||||
self.render();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
var dataset = this.model.get("dataset");
|
||||
this.vis_index = {};
|
||||
this.vis_array = [];
|
||||
_.each(
|
||||
dataset.visualizations.sort(function(a, b) {
|
||||
return a.html < b.html ? -1 : 1;
|
||||
}),
|
||||
function(v, id) {
|
||||
var dict = {
|
||||
id: id,
|
||||
name: v.name,
|
||||
keywords: v.keywords || [],
|
||||
title: v.html,
|
||||
image_src: v.logo ? Galaxy.root + v.logo : null,
|
||||
description: v.description || "No description available.",
|
||||
regular: v.regular,
|
||||
visualization: v
|
||||
};
|
||||
self.vis_index[dict.id] = dict;
|
||||
self.vis_array.push(dict);
|
||||
}
|
||||
);
|
||||
this.types = new Thumbnails.View({
|
||||
title_default: "Suggested plugins",
|
||||
title_list: "List of available plugins",
|
||||
collection: this.vis_array,
|
||||
onclick: function(id) {
|
||||
var vis_type = self.vis_index[id];
|
||||
$("#galaxy_main").attr("src", vis_type.visualization.href);
|
||||
}
|
||||
});
|
||||
this.$el.empty().append(this.types.$el);
|
||||
}
|
||||
});
|
||||
export default { View: View };
|
||||
@@ -1211,7 +1211,7 @@ var Circster = Backbone.View.extend({
|
||||
icon_class: "cross-circle",
|
||||
title: _l("Close"),
|
||||
on_click: function() {
|
||||
window.location = `${Galaxy.root}visualizations/list`;
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -874,7 +874,7 @@ var SweepsterVisualizationView = Backbone.View.extend({
|
||||
icon_class: "cross-circle",
|
||||
title: _l("Close"),
|
||||
on_click: function() {
|
||||
window.location = "${h.url_for( controller='visualization', action='list' )}";
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -95,7 +95,7 @@ class TracksterUI extends Backbone.Model {
|
||||
this.view.has_changes = false;
|
||||
|
||||
// Needed to set URL when first saving a visualization.
|
||||
window.history.pushState({}, "", vis_info.url + window.location.hash);
|
||||
window.history.pushState({}, "", vis_info.url + window.top.location.hash);
|
||||
})
|
||||
.error(() => {
|
||||
// show dialog
|
||||
@@ -151,7 +151,7 @@ class TracksterUI extends Backbone.Model {
|
||||
icon_class: "globe",
|
||||
title: _l("Circster"),
|
||||
on_click: () => {
|
||||
window.location = `${this.baseURL}visualization/circster?id=${this.view.vis_id}`;
|
||||
window.top.location = `${this.baseURL}visualization/circster?id=${this.view.vis_id}`;
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -354,17 +354,17 @@ class TracksterUI extends Backbone.Model {
|
||||
},
|
||||
"Leave without Saving": () => {
|
||||
$(window).off("beforeunload");
|
||||
window.location = `${Galaxy.root}visualization`;
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
},
|
||||
Save: () => {
|
||||
$.when(this.save_viz()).then(() => {
|
||||
window.location = `${Galaxy.root}visualization`;
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
window.location = `${Galaxy.root}visualization`;
|
||||
window.top.location = `${Galaxy.root}visualization`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -433,7 +433,7 @@ class TracksterUIView extends Backbone.View {
|
||||
"Not available."}</b></li><li>or create a new session with this dataset as the only track</li></ul></p>`,
|
||||
buttons: {
|
||||
Cancel: () => {
|
||||
window.location = `${Galaxy.root}visualizations/list`;
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
"View in saved visualization": () => {
|
||||
this.view_in_saved(dataset_params);
|
||||
@@ -456,14 +456,14 @@ class TracksterUIView extends Backbone.View {
|
||||
body: tracks_grid.$el,
|
||||
buttons: {
|
||||
Cancel: () => {
|
||||
window.location = `${Galaxy.root}visualizations/list`;
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
"Add to visualization": () => {
|
||||
$(window.parent.document)
|
||||
.find("input[name=id]:checked")
|
||||
.each(() => {
|
||||
dataset_params.id = $(this).val();
|
||||
window.location = `${Galaxy.root}visualization/trackster?${$.param(dataset_params)}`;
|
||||
window.top.location = `${Galaxy.root}visualization/trackster?${$.param(dataset_params)}`;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -509,7 +509,7 @@ class TracksterUIView extends Backbone.View {
|
||||
body: this.template_view_new(response),
|
||||
buttons: {
|
||||
Cancel: () => {
|
||||
window.location = `${Galaxy.root}visualizations/list`;
|
||||
window.top.location = `${Galaxy.root}visualizations/list`;
|
||||
},
|
||||
Create: () => {
|
||||
this.create_browser($("#new-title").val(), $("#new-dbkey").val());
|
||||
@@ -562,7 +562,7 @@ class TracksterUIView extends Backbone.View {
|
||||
// close selection/finalize template
|
||||
html += `</select></div><div style="clear: both;"></div></div><div class="form-row">Is the build not listed here? <a href="${
|
||||
Galaxy.root
|
||||
}custom_builds">Add a Custom Build</a></div></form>`;
|
||||
}custom_builds" target="_top">Add a Custom Build</a></div></form>`;
|
||||
|
||||
// return
|
||||
return html;
|
||||
|
||||
@@ -2493,7 +2493,7 @@ extend(Track.prototype, Drawable.prototype, {
|
||||
Galaxy.modal.hide();
|
||||
|
||||
// Go to visualization.
|
||||
window.location.href = `${Galaxy.root}visualization/sweepster?${$.param({
|
||||
window.top.location.href = `${Galaxy.root}visualization/sweepster?${$.param({
|
||||
dataset_id: track.dataset.id,
|
||||
hda_ldda: track.dataset.get("hda_ldda"),
|
||||
regions: JSON.stringify(new Backbone.Collection(regions).toJSON())
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
.ui-button-icon {
|
||||
display: block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.ui-button-icon {
|
||||
background: white;
|
||||
color: #666;
|
||||
border-color: white;
|
||||
@@ -15,9 +13,9 @@
|
||||
font-size: 1.2em;
|
||||
line-height: 1.2em;
|
||||
}
|
||||
}
|
||||
.ui-button-icon.charts-fullscreen-button {
|
||||
display: none;
|
||||
.fa-check-square {
|
||||
color: @panel-success-text;
|
||||
}
|
||||
}
|
||||
}
|
||||
.charts-center {
|
||||
@@ -111,13 +109,6 @@
|
||||
.charts-buttons {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
.ui-button-icon,
|
||||
.ui-button-menu {
|
||||
display: none;
|
||||
}
|
||||
.ui-button-icon.charts-fullscreen-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.charts-center {
|
||||
width: 100%;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
|
||||
<visualization name="CSG Viewer">
|
||||
<description>Constructive Solid Geometry (CSG) viewer.</description>
|
||||
<data_sources>
|
||||
<data_source>
|
||||
<model_class>HistoryDatasetAssociation</model_class>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
|
||||
<visualization name="Graph Visualization">
|
||||
<description>Cytoscape-based graph visualization plugin.</description>
|
||||
<data_sources>
|
||||
<data_source>
|
||||
<model_class>HistoryDatasetAssociation</model_class>
|
||||
@@ -22,4 +23,4 @@
|
||||
<param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
|
||||
</params>
|
||||
<template>graphviz.mako</template>
|
||||
</visualization>
|
||||
</visualization>
|
||||
@@ -7,4 +7,15 @@
|
||||
<description>Applies hierarchical clustering to a matrix using R. The data has to be provided in 3-column format. The result is displayed as clustered heatmap.</description>
|
||||
<entry_point entry_point_type="chart" src="../heatmap_default/static/script.js" load="heatmap_cluster"/>
|
||||
<expand macro="shared"/>
|
||||
<specs>
|
||||
<tag>svg</tag>
|
||||
<use_panels>yes</use_panels>
|
||||
<zoomable>true</zoomable>
|
||||
<confirm>True</confirm>
|
||||
<exports>
|
||||
<exports>pdf</exports>
|
||||
<exports>png</exports>
|
||||
<exports>svg</exports>
|
||||
</exports>
|
||||
</specs>
|
||||
</visualization>
|
||||
@@ -7,4 +7,14 @@
|
||||
<description>Renders a heatmap from matrix data provided in 3-column format (x, y, observation).</description>
|
||||
<entry_point entry_point_type="chart" src="../heatmap_default/static/script.js" load="heatmap_default"/>
|
||||
<expand macro="shared"/>
|
||||
<specs>
|
||||
<tag>svg</tag>
|
||||
<use_panels>yes</use_panels>
|
||||
<zoomable>true</zoomable>
|
||||
<exports>
|
||||
<exports>pdf</exports>
|
||||
<exports>png</exports>
|
||||
<exports>svg</exports>
|
||||
</exports>
|
||||
</specs>
|
||||
</visualization>
|
||||
@@ -11,16 +11,6 @@
|
||||
<params>
|
||||
<param type="dataset" var_name_in_template="hda" required="true">dataset_id</param>
|
||||
</params>
|
||||
<specs>
|
||||
<tag>svg</tag>
|
||||
<use_panels>yes</use_panels>
|
||||
<zoomable>true</zoomable>
|
||||
<exports>
|
||||
<exports>pdf</exports>
|
||||
<exports>png</exports>
|
||||
<exports>svg</exports>
|
||||
</exports>
|
||||
</specs>
|
||||
<groups>
|
||||
<input>
|
||||
<label>Provide a label</label>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<entry_point entry_point_type="chart" src="../jqplot_bar/static/script.js" load="jqplot_box"/>
|
||||
<specs>
|
||||
<expand macro="specs"/>
|
||||
<confirm>True</confirm>
|
||||
</specs>
|
||||
<groups>
|
||||
<expand macro="groups"/>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<entry_point entry_point_type="chart" src="../jqplot_bar/static/script.js" load="jqplot_histogram"/>
|
||||
<specs>
|
||||
<expand macro="specs"/>
|
||||
<confirm>True</confirm>
|
||||
</specs>
|
||||
<groups>
|
||||
<expand macro="groups"/>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -105,6 +105,7 @@ var PieWrapper = Backbone.View.extend({
|
||||
var targets = options.targets;
|
||||
var process = options.process;
|
||||
Datasets.request({
|
||||
chart: chart,
|
||||
dataset_id: chart.get("dataset_id"),
|
||||
dataset_groups: chart.groups,
|
||||
success: function(groups) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -10,6 +10,7 @@
|
||||
<specs>
|
||||
<expand macro="specs"/>
|
||||
<use_panels>no</use_panels>
|
||||
<confirm>True</confirm>
|
||||
</specs>
|
||||
<groups>
|
||||
<expand macro="groups"/>
|
||||
|
||||
+1
@@ -10,6 +10,7 @@
|
||||
<specs>
|
||||
<expand macro="specs"/>
|
||||
<use_panels>no</use_panels>
|
||||
<confirm>True</confirm>
|
||||
</specs>
|
||||
<groups>
|
||||
<expand macro="groups"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
|
||||
<visualization name="Phyloviz">
|
||||
<description>Phylogenetic data analysis from multiple data sources.</description>
|
||||
<data_sources>
|
||||
<data_source>
|
||||
<model_class>HistoryDatasetAssociation</model_class>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
@@ -8,10 +8,59 @@ import "../../../../../client/galaxy/scripts/ui/peek-column-selector";
|
||||
import "../../../../../client/galaxy/scripts/ui/pagination";
|
||||
import "jquery-ui-bundle";
|
||||
import "bootstrap";
|
||||
import * as VisualizationModel from "../../../../../client/galaxy/scripts/mvc/visualization/visualization-model";
|
||||
|
||||
//TODO: Finish unlinking this from the Galaxy codebase (package it, use that way?)
|
||||
|
||||
var Visualization = Backbone.Model.extend({
|
||||
/** default attributes for a model */
|
||||
defaults: {
|
||||
config: {}
|
||||
},
|
||||
|
||||
/** override urlRoot to handle prefix */
|
||||
urlRoot: function() {
|
||||
var apiUrl = "api/visualizations";
|
||||
return Galaxy.root + apiUrl;
|
||||
},
|
||||
|
||||
/** Set up the model, determine if accessible, bind listeners
|
||||
* @see Backbone.Model#initialize
|
||||
*/
|
||||
initialize: function(data) {
|
||||
// munge config sub-object here since bbone won't handle defaults with this
|
||||
if (_.isObject(data.config) && _.isObject(this.defaults.config)) {
|
||||
_.defaults(data.config, this.defaults.config);
|
||||
}
|
||||
|
||||
this._setUpListeners();
|
||||
},
|
||||
|
||||
/** set up any event listeners */
|
||||
_setUpListeners: function() {},
|
||||
|
||||
/** override set to properly allow update and trigger change when setting the sub-obj 'config' */
|
||||
set: function(key, val) {
|
||||
if (key === "config") {
|
||||
var oldConfig = this.get("config");
|
||||
if (_.isObject(oldConfig)) {
|
||||
val = _.extend(_.clone(oldConfig), val);
|
||||
}
|
||||
}
|
||||
Backbone.Model.prototype.set.call(this, key, val);
|
||||
return this;
|
||||
},
|
||||
|
||||
/** String representation */
|
||||
toString: function() {
|
||||
var idAndTitle = this.get("id") || "";
|
||||
if (this.get("title")) {
|
||||
idAndTitle += `:${this.get("title")}`;
|
||||
}
|
||||
return `Visualization(${idAndTitle})`;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Two Variable scatterplot visualization using d3
|
||||
* Uses semi transparent circles to show density of data in x, y grid
|
||||
@@ -382,7 +431,7 @@ var ScatterplotConfigEditor = Backbone.View.extend({
|
||||
/** initialize requires a configuration Object containing a dataset Object */
|
||||
initialize: function(attributes) {
|
||||
if (!this.model) {
|
||||
this.model = new VisualizationModel.Visualization({ type: "scatterplot" });
|
||||
this.model = new Visualization({ type: "scatterplot" });
|
||||
}
|
||||
//this.log( this + '.initialize, attributes:', attributes );
|
||||
|
||||
@@ -986,7 +1035,7 @@ var ScatterplotDisplay = Backbone.View.extend({
|
||||
return "ScatterplotView()";
|
||||
}
|
||||
});
|
||||
var ScatterplotModel = VisualizationModel.Visualization.extend({
|
||||
var ScatterplotModel = Visualization.extend({
|
||||
defaults: {
|
||||
type: "scatterplot",
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.9 KiB |
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
|
||||
<visualization name="Trackster">
|
||||
<!--not tested yet -->
|
||||
<visualization name=" Trackster">
|
||||
<description>Fast, interactive visualization for large, NGS/HTS datasets using only a web browser.</description>
|
||||
<data_sources>
|
||||
<data_source>
|
||||
<model_class>HistoryDatasetAssociation</model_class>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE visualization SYSTEM "../../visualization.dtd">
|
||||
<visualization name="Unipept Taxonomy Viewer">
|
||||
<description>Interactive Unipept Tree viewer.</description>
|
||||
<data_sources>
|
||||
<data_source>
|
||||
<model_class>HistoryDatasetAssociation</model_class>
|
||||
|
||||
@@ -18,6 +18,7 @@ _.extend(window.bundleEntries || {}, {
|
||||
});
|
||||
};
|
||||
Datasets.request({
|
||||
chart : options.chart,
|
||||
dataset_id : options.chart.get( 'dataset_id' ),
|
||||
dataset_groups : options.chart.groups,
|
||||
success : function( result ) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -64,9 +64,6 @@ class VisualizationsConfigParser(object):
|
||||
if not returned['name']:
|
||||
raise ParsingException('Visualization needs a name attribute.')
|
||||
|
||||
# a regular visualization for a certain datatype is highlighted in the ui
|
||||
returned['regular'] = xml_tree.get('regular', False)
|
||||
|
||||
# allow manually turning off a vis by checking for a disabled property
|
||||
if 'disabled' in xml_tree.attrib:
|
||||
log.info('Visualizations plugin disabled: %s. Skipping...', returned['name'])
|
||||
|
||||
@@ -14,6 +14,7 @@ from galaxy.visualization.plugins import (
|
||||
resource_parser,
|
||||
utils
|
||||
)
|
||||
from galaxy.web import url_for
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -96,10 +97,6 @@ class VisualizationPlugin(ServesStaticPluginMixin, ServesTemplatesPluginMixin):
|
||||
A plugin that instantiates resources, serves static files, and uses mako
|
||||
templates to render web pages.
|
||||
"""
|
||||
# AKA: MakoVisualizationPlugin
|
||||
# config[ 'entry_point' ][ 'type' ] == 'mako'
|
||||
# TODO: concept/name collision between plugin config and visualization config
|
||||
|
||||
def __init__(self, app, path, name, config, context=None, **kwargs):
|
||||
context = context or {}
|
||||
self.app = app
|
||||
@@ -146,7 +143,6 @@ class VisualizationPlugin(ServesStaticPluginMixin, ServesTemplatesPluginMixin):
|
||||
'name' : self.name,
|
||||
'html' : self.config.get('name'),
|
||||
'description' : self.config.get('description'),
|
||||
'regular' : self.config.get('regular'),
|
||||
'logo' : self.config.get('logo'),
|
||||
'title' : self.config.get('title'),
|
||||
'target' : self.config.get('render_target', 'galaxy_main'),
|
||||
@@ -155,9 +151,15 @@ class VisualizationPlugin(ServesStaticPluginMixin, ServesTemplatesPluginMixin):
|
||||
'settings' : self.config.get('settings'),
|
||||
'groups' : self.config.get('groups'),
|
||||
'specs' : self.config.get('specs'),
|
||||
'static_url' : None if not self.serves_static else '/'.join(['plugins', self.static_url]) # Todo: refactor so this isn't generated here
|
||||
'static_url' : None if not self.serves_static else '/'.join(['plugins', self.static_url]),
|
||||
'href' : self._get_url()
|
||||
}
|
||||
|
||||
def _get_url(self):
|
||||
if self.name in self.app.visualizations_registry.BUILT_IN_VISUALIZATIONS:
|
||||
return url_for(controller='visualization', action=self.name)
|
||||
return url_for('visualization_plugin', visualization_name=self.name)
|
||||
|
||||
def _get_saved_visualization_config(self, visualization, revision=None, **kwargs):
|
||||
"""
|
||||
Return the config of a saved visualization and revision.
|
||||
@@ -198,7 +200,6 @@ class VisualizationPlugin(ServesStaticPluginMixin, ServesTemplatesPluginMixin):
|
||||
# further parse config to resources (models, etc.) used in template based on registry config
|
||||
resources = self._config_to_resources(trans, config)
|
||||
render_vars.update(resources)
|
||||
|
||||
return render_vars
|
||||
|
||||
def _build_config(self, config, trans=None, **kwargs):
|
||||
@@ -312,6 +313,9 @@ class InteractiveEnvironmentPlugin(VisualizationPlugin):
|
||||
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)
|
||||
|
||||
|
||||
class ScriptVisualizationPlugin(VisualizationPlugin):
|
||||
"""
|
||||
|
||||
@@ -16,10 +16,8 @@ from galaxy.util import (
|
||||
)
|
||||
from galaxy.visualization.plugins import (
|
||||
config_parser,
|
||||
plugin as vis_plugins,
|
||||
utils as vis_utils
|
||||
plugin as vis_plugins
|
||||
)
|
||||
from galaxy.web import url_for
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -38,9 +36,7 @@ class VisualizationsRegistry(object):
|
||||
BASE_URL = 'visualizations'
|
||||
#: name of files to search for additional template lookup directories
|
||||
TEMPLATE_PATHS_CONFIG = 'additional_template_paths.xml'
|
||||
# these should be handled somewhat differently - and be passed onto their resp. methods in ctrl.visualization
|
||||
# TODO: change/remove if/when they can be updated to use this system
|
||||
#: any built in visualizations that have their own render method in ctrls/visualization
|
||||
#: built-in visualizations
|
||||
BUILT_IN_VISUALIZATIONS = [
|
||||
'trackster',
|
||||
'circster',
|
||||
@@ -117,20 +113,15 @@ class VisualizationsRegistry(object):
|
||||
for plugin_path in self._find_plugins():
|
||||
try:
|
||||
plugin = self._load_plugin(plugin_path)
|
||||
|
||||
if plugin and plugin.name not in self.plugins:
|
||||
self.plugins[plugin.name] = plugin
|
||||
log.info('%s, loaded plugin: %s', self, plugin.name)
|
||||
# NOTE: prevent silent, implicit overwrite here (two plugins in two diff directories)
|
||||
# TODO: overwriting may be desired
|
||||
elif plugin and plugin.name in self.plugins:
|
||||
log.warning('%s, plugin with name already exists: %s. Skipping...', self, plugin.name)
|
||||
|
||||
except Exception:
|
||||
if not self.skip_bad_plugins:
|
||||
raise
|
||||
log.exception('Plugin loading raised exception: %s. Skipping...', plugin_path)
|
||||
|
||||
return self.plugins
|
||||
|
||||
def _find_plugins(self):
|
||||
@@ -230,19 +221,24 @@ class VisualizationsRegistry(object):
|
||||
raise ObjectNotFound('Unknown or invalid visualization: ' + key)
|
||||
return self.plugins[key]
|
||||
|
||||
def get_plugins(self):
|
||||
result = []
|
||||
for plugin in self.plugins.itervalues():
|
||||
result.append(plugin.to_dict())
|
||||
return sorted(result, key=lambda k: k.get('html'))
|
||||
|
||||
# -- building links to visualizations from objects --
|
||||
def get_visualizations(self, trans, target_object):
|
||||
"""
|
||||
Get the names of visualizations usable on the `target_object` and
|
||||
the urls to call in order to render the visualizations.
|
||||
"""
|
||||
# TODO:?? a list of objects? YAGNI?
|
||||
applicable_visualizations = []
|
||||
for vis_name in self.plugins:
|
||||
url_data = self.get_visualization(trans, vis_name, target_object)
|
||||
if url_data:
|
||||
applicable_visualizations.append(url_data)
|
||||
return applicable_visualizations
|
||||
return sorted(applicable_visualizations, key=lambda k: k.get('html'))
|
||||
|
||||
def get_visualization(self, trans, visualization_name, target_object):
|
||||
"""
|
||||
@@ -250,29 +246,15 @@ class VisualizationsRegistry(object):
|
||||
`visualization_name` if it's applicable to `target_object` or
|
||||
`None` if it's not.
|
||||
"""
|
||||
# log.debug( 'VisReg.get_visualization: %s, %s', visualization_name, target_object )
|
||||
visualization = self.plugins.get(visualization_name, None)
|
||||
if not visualization:
|
||||
return None
|
||||
|
||||
data_sources = visualization.config['data_sources']
|
||||
for data_source in data_sources:
|
||||
# currently a model class is required
|
||||
model_class = data_source['model_class']
|
||||
if not isinstance(target_object, model_class):
|
||||
continue
|
||||
|
||||
# TODO: not true: must have test currently
|
||||
tests = data_source['tests']
|
||||
if tests and not self.is_object_applicable(trans, target_object, tests):
|
||||
continue
|
||||
|
||||
# remap some of these vars for direct use in ui.js, PopupMenu (e.g. text->html)
|
||||
param_data = data_source['to_params']
|
||||
response = visualization.to_dict()
|
||||
response['href'] = self.get_visualization_url(trans, target_object, visualization, param_data)
|
||||
return response
|
||||
return None
|
||||
if visualization is not None:
|
||||
data_sources = visualization.config['data_sources']
|
||||
for data_source in data_sources:
|
||||
model_class = data_source['model_class']
|
||||
if isinstance(target_object, model_class):
|
||||
tests = data_source['tests']
|
||||
if tests is None or self.is_object_applicable(trans, target_object, tests):
|
||||
return visualization.to_dict()
|
||||
|
||||
def is_object_applicable(self, trans, target_object, data_source_tests):
|
||||
"""
|
||||
@@ -308,53 +290,3 @@ class VisualizationsRegistry(object):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_visualization_url(self, trans, target_object, visualization, param_data):
|
||||
"""
|
||||
Generates a url for the visualization with `visualization`
|
||||
for use with the given `target_object` with a query string built
|
||||
from the configuration data in `param_data`.
|
||||
"""
|
||||
# precondition: the target_object should be usable by the visualization (accrd. to data_sources)
|
||||
# convert params using vis.data_source.to_params
|
||||
params = self.get_url_params(trans, target_object, param_data)
|
||||
|
||||
# we want existing visualizations to work as normal but still be part of the registry (without mod'ing)
|
||||
# so generate their urls differently
|
||||
url = None
|
||||
if visualization.name in self.BUILT_IN_VISUALIZATIONS:
|
||||
url = url_for(controller='visualization', action=visualization.name, **params)
|
||||
# TODO: needs to be split off as it's own registry
|
||||
elif isinstance(visualization, vis_plugins.InteractiveEnvironmentPlugin):
|
||||
url = url_for('interactive_environment_plugin', visualization_name=visualization.name, **params)
|
||||
else:
|
||||
url = url_for('visualization_plugin', visualization_name=visualization.name, **params)
|
||||
|
||||
# TODO:?? not sure if embedded would fit/used here? or added in client...
|
||||
return url
|
||||
|
||||
def get_url_params(self, trans, target_object, param_data):
|
||||
"""
|
||||
Convert the applicable objects and assoc. data into a param dict
|
||||
for a url query string to add to the url that loads the visualization.
|
||||
"""
|
||||
params = {}
|
||||
for to_param_name, to_param_data in param_data.items():
|
||||
# TODO??: look into params as well? what is required, etc.
|
||||
target_attr = to_param_data.get('param_attr', None)
|
||||
assign = to_param_data.get('assign', None)
|
||||
# one or the other is needed
|
||||
# assign takes precedence (goes last, overwrites)?
|
||||
# NOTE this is only one level
|
||||
|
||||
if target_attr and vis_utils.hasattr_recursive(target_object, target_attr):
|
||||
params[to_param_name] = vis_utils.getattr_recursive(target_object, target_attr)
|
||||
|
||||
if assign:
|
||||
params[to_param_name] = assign
|
||||
|
||||
# NOTE!: don't expose raw ids: encode id, _id
|
||||
# TODO: double encodes if from config
|
||||
if params:
|
||||
params = trans.security.encode_dict_ids(params)
|
||||
return params
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
"""
|
||||
Plugins resource control over the API.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from galaxy import exceptions
|
||||
from galaxy.managers import hdas, histories
|
||||
from galaxy.web import _future_expose_api as expose_api
|
||||
from galaxy.web.base.controller import BaseAPIController
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PluginsController(BaseAPIController):
|
||||
"""
|
||||
RESTful controller for interactions with plugins.
|
||||
"""
|
||||
|
||||
def __init__(self, app):
|
||||
super(PluginsController, self).__init__(app)
|
||||
self.hda_manager = hdas.HDAManager(app)
|
||||
self.history_manager = histories.HistoryManager(app)
|
||||
|
||||
@expose_api
|
||||
def index(self, trans, **kwargs):
|
||||
"""
|
||||
GET /api/plugins:
|
||||
"""
|
||||
registry = self._get_registry(trans)
|
||||
dataset_id = kwargs.get("dataset_id")
|
||||
if dataset_id is not None:
|
||||
hda = self.hda_manager.get_accessible(self.decode_id(dataset_id), trans.user)
|
||||
return registry.get_visualizations(trans, hda)
|
||||
else:
|
||||
return registry.get_plugins()
|
||||
|
||||
@expose_api
|
||||
def show(self, trans, id, **kwargs):
|
||||
"""
|
||||
GET /api/plugins/{id}:
|
||||
"""
|
||||
registry = self._get_registry(trans)
|
||||
result = {}
|
||||
history_id = kwargs.get("history_id")
|
||||
if history_id is not None:
|
||||
history = self.history_manager.get_owned(trans.security.decode_id(history_id), trans.user, current_history=trans.history)
|
||||
result["hdas"] = []
|
||||
for hda in history.datasets:
|
||||
if registry.get_visualization(trans, id, hda):
|
||||
result["hdas"].append({
|
||||
"id": trans.security.encode_id(hda.id),
|
||||
"name": hda.name
|
||||
})
|
||||
return result
|
||||
|
||||
def _get_registry(self, trans):
|
||||
if not trans.app.visualizations_registry:
|
||||
raise exceptions.MessageException("The visualization registry has not been configured.")
|
||||
return trans.app.visualizations_registry
|
||||
@@ -108,7 +108,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
|
||||
webapp.add_client_route('/user')
|
||||
webapp.add_client_route('/user/{form_id}')
|
||||
webapp.add_client_route('/openids/list')
|
||||
webapp.add_client_route('/visualizations/dataset_id={dataset_id}')
|
||||
webapp.add_client_route('/visualizations')
|
||||
webapp.add_client_route('/visualizations/edit')
|
||||
webapp.add_client_route('/visualizations/list_published')
|
||||
webapp.add_client_route('/visualizations/list')
|
||||
@@ -306,6 +306,7 @@ def populate_api_routes(webapp, app):
|
||||
webapp.mapper.connect('/api/genomes/{id}/indexes', controller='genomes', action='indexes')
|
||||
webapp.mapper.connect('/api/genomes/{id}/sequences', controller='genomes', action='sequences')
|
||||
webapp.mapper.resource('visualization', 'visualizations', path_prefix='/api')
|
||||
webapp.mapper.resource('plugins', 'plugins', path_prefix='/api')
|
||||
webapp.mapper.connect('/api/workflows/build_module', action='build_module', controller="workflows")
|
||||
webapp.mapper.connect('/api/workflows/menu', action='get_workflow_menu', controller="workflows", conditions=dict(method=["GET"]))
|
||||
webapp.mapper.connect('/api/workflows/menu', action='set_workflow_menu', controller="workflows", conditions=dict(method=["PUT"]))
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -188,6 +188,7 @@ class MockTrans(object):
|
||||
|
||||
|
||||
class MockVisualizationsRegistry(object):
|
||||
BUILT_IN_VISUALIZATIONS = ['trackster']
|
||||
|
||||
def get_visualizations(self, trans, target):
|
||||
return []
|
||||
|
||||
@@ -64,7 +64,7 @@ class VisualizationsRegistry_TestCase(unittest.TestCase):
|
||||
self.assertEqual(trackster.name, 'trackster')
|
||||
self.assertEqual(trackster.path, os.path.join(expected_plugins_path, 'trackster'))
|
||||
self.assertEqual(trackster.base_url, '/'.join([plugin_mgr.base_url, trackster.name]))
|
||||
self.assertFalse(trackster.serves_static)
|
||||
self.assertTrue(trackster.serves_static)
|
||||
self.assertFalse(trackster.serves_templates)
|
||||
|
||||
def test_plugin_load(self):
|
||||
|
||||
Reference in New Issue
Block a user