mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge pull request #5212 from guerler/remove_gridhelper_001
Remove html producing grid helpers
This commit is contained in:
@@ -39,8 +39,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin/users_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -49,8 +48,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin/roles_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -59,8 +57,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin/groups_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -69,8 +66,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin_toolshed/browse_repositories`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -79,8 +75,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin/tool_versions_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -89,8 +84,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}admin/quotas_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -105,8 +99,7 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}forms/forms_list`,
|
||||
url_data: Galaxy.params,
|
||||
dict_format: true
|
||||
url_data: Galaxy.params
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
@@ -47,6 +47,7 @@ window.app = function app(options, bootstrapped) {
|
||||
"(/)tours(/)(:tour_id)": "show_tours",
|
||||
"(/)user(/)": "show_user",
|
||||
"(/)user(/)(:form_id)": "show_user_form",
|
||||
"(/)openids(/)list": "show_openids",
|
||||
"(/)pages(/)create(/)": "show_pages_create",
|
||||
"(/)pages(/)edit(/)": "show_pages_edit",
|
||||
"(/)pages(/)(:action_id)": "show_pages",
|
||||
@@ -115,8 +116,7 @@ window.app = function app(options, bootstrapped) {
|
||||
show_workflows_published: function() {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}workflow/list_published`,
|
||||
dict_format: true
|
||||
url_base: `${Galaxy.root}workflow/list_published`
|
||||
})
|
||||
);
|
||||
},
|
||||
@@ -157,11 +157,18 @@ window.app = function app(options, bootstrapped) {
|
||||
);
|
||||
},
|
||||
|
||||
show_openids: function() {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}user/openids_list`
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
show_datasets: function() {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
url_base: `${Galaxy.root}dataset/list`,
|
||||
dict_format: true
|
||||
url_base: `${Galaxy.root}dataset/list`
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
@@ -328,7 +328,6 @@ WYMeditor.editor.prototype.dialog = function(dialogType, dialogFeatures, bodyHtm
|
||||
|
||||
var grid = new GridView({
|
||||
url_base: item_info.list_ajax_url,
|
||||
dict_format: true,
|
||||
embedded: true
|
||||
});
|
||||
Galaxy.modal.show({
|
||||
@@ -422,7 +421,6 @@ WYMeditor.editor.prototype.dialog = function(dialogType, dialogFeatures, bodyHtm
|
||||
|
||||
var grid = new GridView({
|
||||
url_base: item_info.list_ajax_url,
|
||||
dict_format: true,
|
||||
embedded: true
|
||||
});
|
||||
Galaxy.modal.show({
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
// legacy grid model, used by reports and toolshed
|
||||
export default Backbone.Model.extend({
|
||||
defaults: {
|
||||
url_base: "",
|
||||
async: false,
|
||||
async_ops: [],
|
||||
categorical_filters: [],
|
||||
filters: {},
|
||||
sort_key: null,
|
||||
show_item_checkboxes: false,
|
||||
advanced_search: false,
|
||||
cur_page: 1,
|
||||
num_pages: 1,
|
||||
operation: undefined,
|
||||
item_ids: undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* Return true if operation can be done asynchronously.
|
||||
*/
|
||||
can_async_op: function(op) {
|
||||
return _.indexOf(this.attributes.async_ops, op) !== -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add filtering criterion.
|
||||
*/
|
||||
add_filter: function(key, value, append) {
|
||||
// Update URL arg with new condition.
|
||||
if (append) {
|
||||
// Update or append value.
|
||||
var cur_val = this.attributes.filters[key];
|
||||
|
||||
var new_val;
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
new_val = value;
|
||||
} else if (typeof cur_val == "string") {
|
||||
if (cur_val == "All" || cur_val == value) {
|
||||
new_val = value;
|
||||
} else {
|
||||
// Replace string with array.
|
||||
var values = [];
|
||||
values[0] = cur_val;
|
||||
values[1] = value;
|
||||
new_val = values;
|
||||
}
|
||||
} else {
|
||||
// Current value is an array.
|
||||
new_val = cur_val;
|
||||
if (new_val.indexOf(value) === -1) {
|
||||
new_val.push(value);
|
||||
}
|
||||
}
|
||||
this.attributes.filters[key] = new_val;
|
||||
} else {
|
||||
// Replace value.
|
||||
this.attributes.filters[key] = value;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove filtering criterion.
|
||||
*/
|
||||
remove_filter: function(key, condition) {
|
||||
var cur_val = this.attributes.filters[key];
|
||||
if (cur_val === null || cur_val === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof cur_val === "string") {
|
||||
// overwrite/remove condition.
|
||||
this.attributes.filters[key] = "";
|
||||
} else {
|
||||
// filter contains an array of conditions.
|
||||
var condition_index = _.indexOf(cur_val, condition);
|
||||
if (condition_index !== -1) {
|
||||
cur_val[condition_index] = "";
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns URL data for obtaining a new grid.
|
||||
*/
|
||||
get_url_data: function() {
|
||||
var url_data = {
|
||||
async: this.attributes.async,
|
||||
sort: this.attributes.sort_key,
|
||||
page: this.attributes.cur_page,
|
||||
show_item_checkboxes: this.attributes.show_item_checkboxes,
|
||||
advanced_search: this.attributes.advanced_search
|
||||
};
|
||||
|
||||
// Add operation, item_ids only if they have values.
|
||||
if (this.attributes.operation) {
|
||||
url_data.operation = this.attributes.operation;
|
||||
}
|
||||
if (this.attributes.item_ids) {
|
||||
url_data.id = this.attributes.item_ids;
|
||||
}
|
||||
|
||||
// Add filter arguments to data, placing "f-" in front of all arguments.
|
||||
var self = this;
|
||||
_.each(_.pairs(self.attributes.filters), k => {
|
||||
url_data[`f-${k[0]}`] = k[1];
|
||||
});
|
||||
return url_data;
|
||||
},
|
||||
|
||||
// Return URL for obtaining a new grid
|
||||
get_url: function(args) {
|
||||
return `${this.get("url_base")}?${$.param(this.get_url_data())}&${$.param(args)}`;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,547 @@
|
||||
// dependencies
|
||||
import Utils from "utils/utils";
|
||||
// grid view templates
|
||||
export default {
|
||||
// template
|
||||
grid: function(options) {
|
||||
var tmpl = "";
|
||||
if (options.embedded) {
|
||||
tmpl = this.grid_header(options) + this.grid_table(options);
|
||||
} else {
|
||||
tmpl = `<div class="loading-elt-overlay"></div><table><tr><td width="75%">${this.grid_header(
|
||||
options
|
||||
)}</td><td></td><td></td></tr><tr><td width="100%" id="grid-message" valign="top"></td><td></td><td></td></tr></table>${this.grid_table(
|
||||
options
|
||||
)}`;
|
||||
}
|
||||
|
||||
// add info text
|
||||
if (options.info_text) {
|
||||
tmpl += `<br><div class="toolParamHelp" style="clear: both;">${options.info_text}</div>`;
|
||||
}
|
||||
|
||||
// return
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
grid_table: function() {
|
||||
return `
|
||||
<form method="post" onsubmit="return false;">
|
||||
<table id="grid-table" class="grid">
|
||||
<thead id="grid-table-header"></thead>
|
||||
<tbody id="grid-table-body"></tbody>
|
||||
<tfoot id="grid-table-footer"></tfoot>
|
||||
</table>
|
||||
</form>`;
|
||||
},
|
||||
|
||||
// template
|
||||
grid_header: function(options) {
|
||||
var tmpl = '<div class="grid-header">';
|
||||
if (!options.embedded) {
|
||||
tmpl += `<h2>${options.title}</h2>`;
|
||||
}
|
||||
if (options.global_actions) {
|
||||
tmpl += '<ul class="manage-table-actions">';
|
||||
var show_popup = options.global_actions.length >= 3;
|
||||
if (show_popup) {
|
||||
tmpl +=
|
||||
'<li><a class="action-button" id="popup-global-actions" class="menubutton">Actions</a></li>' +
|
||||
'<div popupmenu="popup-global-actions">';
|
||||
}
|
||||
for (let action of options.global_actions) {
|
||||
tmpl += `<li><a class="action-button use-target" target="${action.target}" href="${
|
||||
action.url_args
|
||||
}" onclick="return false;" >${action.label}</a></li>`;
|
||||
}
|
||||
if (show_popup) {
|
||||
tmpl += "</div>";
|
||||
}
|
||||
tmpl += "</ul>";
|
||||
}
|
||||
if (options.insert) {
|
||||
tmpl += options.insert;
|
||||
}
|
||||
|
||||
// add grid filters
|
||||
tmpl += this.grid_filters(options);
|
||||
tmpl += "</div>";
|
||||
|
||||
// return template
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
header: function(options) {
|
||||
// start
|
||||
var tmpl = "<tr>";
|
||||
|
||||
// add checkbox
|
||||
if (options.show_item_checkboxes) {
|
||||
tmpl += "<th>";
|
||||
if (options.items.length > 0) {
|
||||
tmpl +=
|
||||
'<input type="checkbox" id="check_all" name=select_all_checkbox value="true">' +
|
||||
'<input type="hidden" name=select_all_checkbox value="true">';
|
||||
}
|
||||
tmpl += "</th>";
|
||||
}
|
||||
|
||||
// create header elements
|
||||
for (let column of options.columns) {
|
||||
if (column.visible) {
|
||||
tmpl += `<th id="${column.key}-header">`;
|
||||
if (column.href) {
|
||||
tmpl += `<a href="${column.href}" class="sort-link" sort_key="${column.key}">${column.label}</a>`;
|
||||
} else {
|
||||
tmpl += column.label;
|
||||
}
|
||||
tmpl += `<span class="sort-arrow">${column.extra}</span></th>`;
|
||||
}
|
||||
}
|
||||
|
||||
// finalize
|
||||
tmpl += "</tr>";
|
||||
|
||||
// return template
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
body: function(options) {
|
||||
// initialize
|
||||
var tmpl = "";
|
||||
var items_length = options.items.length;
|
||||
|
||||
// empty grid?
|
||||
if (items_length === 0) {
|
||||
// No results.
|
||||
tmpl += '<tr><td colspan="100"><em>No Items</em></td></tr>';
|
||||
}
|
||||
|
||||
// create rows
|
||||
for (let item of options.items) {
|
||||
// Tag current
|
||||
tmpl += "<tr ";
|
||||
if (options.current_item_id == item.id) {
|
||||
tmpl += 'class="current"';
|
||||
}
|
||||
tmpl += ">";
|
||||
|
||||
// Item selection column
|
||||
if (options.show_item_checkboxes) {
|
||||
tmpl += `<td style="width: 1.5em;"><input type="checkbox" name="id" value="${item.encode_id}" id="${
|
||||
item.encode_id
|
||||
}" class="grid-row-select-checkbox" /></td>`;
|
||||
}
|
||||
|
||||
// Data columns
|
||||
for (let column of options.columns) {
|
||||
if (column.visible) {
|
||||
// Nowrap
|
||||
var nowrap = "";
|
||||
if (column.nowrap) {
|
||||
nowrap = 'style="white-space:nowrap;"';
|
||||
}
|
||||
|
||||
// get column settings
|
||||
var column_settings = item.column_config[column.label];
|
||||
|
||||
// load attributes
|
||||
var link = column_settings.link;
|
||||
var value = column_settings.value;
|
||||
var target = column_settings.target;
|
||||
|
||||
// unescape value
|
||||
if (jQuery.type(value) === "string") {
|
||||
value = value.replace(/\/\//g, "/");
|
||||
}
|
||||
|
||||
// Attach popup menu?
|
||||
var id = "";
|
||||
var cls = "";
|
||||
if (column.attach_popup) {
|
||||
id = `grid-${item.encode_id}-popup`;
|
||||
cls = "menubutton";
|
||||
if (link !== "") {
|
||||
cls += " split";
|
||||
}
|
||||
cls += " popup";
|
||||
}
|
||||
|
||||
// Check for row wrapping
|
||||
tmpl += `<td ${nowrap}>`;
|
||||
|
||||
// Link
|
||||
if (link) {
|
||||
if (options.operations.length !== 0) {
|
||||
tmpl += `<div id="${id}" class="${cls}" style="float: left;">`;
|
||||
}
|
||||
tmpl += `<a class="menubutton-label use-target" target="${target}" href="${link}" onclick="return false;">${value}</a>`;
|
||||
if (options.operations.length !== 0) {
|
||||
tmpl += "</div>";
|
||||
}
|
||||
} else {
|
||||
tmpl += `<div id="${id}" class="${cls}"><label id="${column.label_id_prefix}${
|
||||
item.encode_id
|
||||
}" for="${item.encode_id}">${value || ""}</label></div>`;
|
||||
}
|
||||
tmpl += "</td>";
|
||||
}
|
||||
}
|
||||
tmpl += "</tr>";
|
||||
}
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
footer: function(options) {
|
||||
// create template string
|
||||
var tmpl = "";
|
||||
|
||||
// paging
|
||||
if (options.use_paging && options.num_pages > 1) {
|
||||
// get configuration
|
||||
var num_page_links = options.num_page_links;
|
||||
var cur_page_num = options.cur_page_num;
|
||||
var num_pages = options.num_pages;
|
||||
|
||||
// First pass on min page.
|
||||
var page_link_range = num_page_links / 2;
|
||||
var min_page = cur_page_num - page_link_range;
|
||||
var min_offset = 0;
|
||||
if (min_page <= 0) {
|
||||
// Min page is too low.
|
||||
min_page = 1;
|
||||
min_offset = page_link_range - (cur_page_num - min_page);
|
||||
}
|
||||
|
||||
// Set max page.
|
||||
var max_range = page_link_range + min_offset;
|
||||
var max_page = cur_page_num + max_range;
|
||||
var max_offset;
|
||||
if (max_page <= num_pages) {
|
||||
// Max page is fine.
|
||||
max_offset = 0;
|
||||
} else {
|
||||
// Max page is too high.
|
||||
max_page = num_pages;
|
||||
// +1 to account for the +1 in the loop below.
|
||||
max_offset = max_range - (max_page + 1 - cur_page_num);
|
||||
}
|
||||
|
||||
// Second and final pass on min page to add any unused
|
||||
// offset from max to min.
|
||||
if (max_offset !== 0) {
|
||||
min_page -= max_offset;
|
||||
if (min_page < 1) {
|
||||
min_page = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// template header
|
||||
tmpl += '<tr id="page-links-row">';
|
||||
if (options.show_item_checkboxes) {
|
||||
tmpl += "<td></td>";
|
||||
}
|
||||
tmpl += '<td colspan="100">' + '<span id="page-link-container">' + "Page:";
|
||||
|
||||
if (min_page > 1) {
|
||||
tmpl +=
|
||||
'<span class="page-link" id="page-link-1"><a href="javascript:void(0);" page_num="1" onclick="return false;">1</a></span> ...';
|
||||
}
|
||||
|
||||
// create page urls
|
||||
for (var page_index = min_page; page_index < max_page + 1; page_index++) {
|
||||
if (page_index == options.cur_page_num) {
|
||||
tmpl += `<span class="page-link inactive-link" id="page-link-${page_index}">${page_index}</span>`;
|
||||
} else {
|
||||
tmpl += `<span class="page-link" id="page-link-${page_index}"><a href="javascript:void(0);" onclick="return false;" page_num="${page_index}">${page_index}</a></span>`;
|
||||
}
|
||||
}
|
||||
|
||||
// show last page
|
||||
if (max_page < num_pages) {
|
||||
tmpl += `...<span class="page-link" id="page-link-${num_pages}"><a href="javascript:void(0);" onclick="return false;" page_num="${num_pages}">${num_pages}</a></span>`;
|
||||
}
|
||||
tmpl += "</span>";
|
||||
|
||||
// Show all link
|
||||
tmpl += `
|
||||
<span class="page-link" id="show-all-link-span"> | <a href="javascript:void(0);" onclick="return false;" page_num="all">Show All</a></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
// Grid operations for multiple items.
|
||||
if (options.show_item_checkboxes) {
|
||||
// start template
|
||||
tmpl += `
|
||||
<tr>
|
||||
<input type="hidden" id="operation" name="operation" value="">
|
||||
<td></td>
|
||||
<td colspan="100">
|
||||
For <span class="grid-selected-count"></span> selected items:
|
||||
`;
|
||||
|
||||
// configure buttons for operations
|
||||
for (let operation of options.operations) {
|
||||
if (operation.allow_multiple) {
|
||||
tmpl += `<input type="button" value="${
|
||||
operation.label
|
||||
}" class="operation-button action-button"> `;
|
||||
}
|
||||
}
|
||||
|
||||
// finalize template
|
||||
tmpl += "</td>" + "</tr>";
|
||||
}
|
||||
|
||||
// count global operations
|
||||
var found_global = false;
|
||||
for (let operation of options.operations) {
|
||||
if (operation.global_operation) {
|
||||
found_global = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// add global operations
|
||||
if (found_global) {
|
||||
tmpl += "<tr>" + '<td colspan="100">';
|
||||
for (let operation of options.operations) {
|
||||
if (operation.global_operation) {
|
||||
tmpl += `<a class="action-button" href="${operation.global_operation}">${operation.label}</a>`;
|
||||
}
|
||||
}
|
||||
tmpl += "</td>" + "</tr>";
|
||||
}
|
||||
|
||||
// add legend
|
||||
if (options.legend) {
|
||||
tmpl += `<tr><td colspan="100">${options.legend}</td></tr>`;
|
||||
}
|
||||
|
||||
// return
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
message: function(options) {
|
||||
var status = options.status;
|
||||
if (["success", "ok"].indexOf(status) != -1) {
|
||||
status = "done";
|
||||
}
|
||||
return `<p><div class="${status}message transient-message">${_.escape(
|
||||
options.message
|
||||
)}</div><div style="clear: both"></div></p>`;
|
||||
},
|
||||
|
||||
// template
|
||||
grid_filters: function(options) {
|
||||
// get filters
|
||||
var default_filter_dict = options.default_filter_dict;
|
||||
var filters = options.filters;
|
||||
|
||||
// show advanced search if flag set or if there are filters for advanced search fields
|
||||
var advanced_search_display = "none";
|
||||
if (options.advanced_search) {
|
||||
advanced_search_display = "block";
|
||||
}
|
||||
|
||||
// identify columns with advanced filtering
|
||||
var show_advanced_search_link = false;
|
||||
for (let column of options.columns) {
|
||||
if (column.filterable == "advanced") {
|
||||
var column_key = column.key;
|
||||
var f_key = filters[column_key];
|
||||
var d_key = default_filter_dict[column_key];
|
||||
if (f_key && d_key && f_key != d_key) {
|
||||
advanced_search_display = "block";
|
||||
}
|
||||
show_advanced_search_link = true;
|
||||
}
|
||||
}
|
||||
|
||||
// hide standard search if advanced is shown
|
||||
var standard_search_display = "block";
|
||||
if (advanced_search_display == "block") {
|
||||
standard_search_display = "none";
|
||||
}
|
||||
|
||||
//
|
||||
// standard search
|
||||
//
|
||||
var tmpl = `<div id="standard-search" style="display: ${standard_search_display};"><table><tr><td style="padding: 0;"><table>`;
|
||||
|
||||
// add standard filters
|
||||
for (let column of options.columns) {
|
||||
if (column.filterable == "standard") {
|
||||
tmpl += this.grid_column_filter(options, column);
|
||||
}
|
||||
}
|
||||
|
||||
// finalize standard search
|
||||
tmpl += "</table>" + "</td>" + "</tr>" + "<tr>" + "<td>";
|
||||
|
||||
// show advanced search link in standard display
|
||||
if (show_advanced_search_link) {
|
||||
tmpl += '<a href="" class="advanced-search-toggle">Advanced Search</a>';
|
||||
}
|
||||
|
||||
// finalize standard search display
|
||||
tmpl += "</td>" + "</tr>" + "</table>" + "</div>";
|
||||
|
||||
//
|
||||
// advanced search
|
||||
//
|
||||
tmpl += `<div id="advanced-search" style="display: ${advanced_search_display}; margin-top: 5px; border: 1px solid #ccc;"><table><tr><td style="text-align: left" colspan="100"><a href="" class="advanced-search-toggle">Close Advanced Search</a></td></tr>`;
|
||||
|
||||
// add advanced filters
|
||||
for (let column of options.columns) {
|
||||
if (column.filterable == "advanced") {
|
||||
tmpl += this.grid_column_filter(options, column);
|
||||
}
|
||||
}
|
||||
|
||||
// finalize advanced search template
|
||||
tmpl += "</table>" + "</div>";
|
||||
|
||||
// return template
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template
|
||||
grid_column_filter: function(options, column) {
|
||||
// collect parameters
|
||||
var filters = options.filters;
|
||||
var column_label = column.label;
|
||||
var column_key = column.key;
|
||||
if (column.filterable == "advanced") {
|
||||
column_label = column_label.toLowerCase();
|
||||
}
|
||||
|
||||
// start
|
||||
var tmpl = "<tr>";
|
||||
|
||||
if (column.filterable == "advanced") {
|
||||
tmpl += `<td align="left" style="padding-left: 10px">${column_label}:</td>`;
|
||||
}
|
||||
tmpl += '<td style="padding-bottom: 1px;">';
|
||||
if (column.is_text) {
|
||||
tmpl += `<form class="text-filter-form" column_key="${column_key}" action="${options.url}" method="get" >`;
|
||||
// Carry forward filtering criteria with hidden inputs.
|
||||
for (let column of options.columns) {
|
||||
var filter_value = filters[column.key];
|
||||
if (filter_value) {
|
||||
if (filter_value != "All") {
|
||||
if (column.is_text) {
|
||||
filter_value = JSON.stringify(filter_value);
|
||||
}
|
||||
tmpl += `<input type="hidden" id="${column.key}" name="f-${
|
||||
column.key
|
||||
}" value="${filter_value}"/>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Print current filtering criteria and links to delete.
|
||||
tmpl += `<span id="${column_key}-filtering-criteria">`;
|
||||
|
||||
// add filters
|
||||
var column_filter = filters[column_key];
|
||||
if (column_filter) {
|
||||
// identify type
|
||||
var type = jQuery.type(column_filter);
|
||||
|
||||
// single filter value
|
||||
if (type == "string") {
|
||||
if (column_filter != "All") {
|
||||
// append template
|
||||
tmpl += this.filter_element(column_key, column_filter);
|
||||
}
|
||||
}
|
||||
|
||||
// multiple filter values
|
||||
if (type == "array") {
|
||||
for (let i in column_filter) {
|
||||
// copy filters and remove entry
|
||||
var params = column_filter;
|
||||
params = params.slice(i);
|
||||
|
||||
// append template
|
||||
tmpl += this.filter_element(column_key, column_filter[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close span
|
||||
tmpl += "</span>";
|
||||
|
||||
// Set value, size of search input field. Minimum size is 20 characters.
|
||||
var value = "";
|
||||
var size = 20;
|
||||
if (column.filterable == "standard") {
|
||||
value = column.label.toLowerCase();
|
||||
if (value.length < 20) {
|
||||
size = value.length;
|
||||
}
|
||||
// +4 to account for space after placeholder
|
||||
size = size + 4;
|
||||
}
|
||||
|
||||
// print input field for column
|
||||
tmpl += `
|
||||
<span class="search-box">
|
||||
<input class="search-box-input" id="input-${column_key}-filter" name="f-${column_key}" type="text" placeholder="${value}" size="${size}"/>
|
||||
<button type="submit" style="background: transparent; border: none; padding: 4px; margin: 0px;">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</form>`;
|
||||
} else {
|
||||
// filter criteria
|
||||
tmpl += `<span id="${column_key}-filtering-criteria">`;
|
||||
|
||||
// add category filters
|
||||
var seperator = false;
|
||||
for (var cf_label in options.categorical_filters[column_key]) {
|
||||
// get category filter
|
||||
var cf = options.categorical_filters[column_key][cf_label];
|
||||
|
||||
// each filter will have only a single argument, so get that single argument
|
||||
var cf_key = "";
|
||||
var cf_arg = "";
|
||||
for (var key in cf) {
|
||||
cf_key = key;
|
||||
cf_arg = cf[key];
|
||||
}
|
||||
|
||||
// add seperator
|
||||
if (seperator) {
|
||||
tmpl += " | ";
|
||||
}
|
||||
seperator = true;
|
||||
|
||||
// add category
|
||||
var filter = filters[column_key];
|
||||
if (filter && cf[column_key] && filter == cf_arg) {
|
||||
tmpl += `<span class="categorical-filter ${column_key}-filter current-filter">${cf_label}</span>`;
|
||||
} else {
|
||||
tmpl += `<span class="categorical-filter ${column_key}-filter"><a href="javascript:void(0);" filter_key="${cf_key}" filter_val="${cf_arg}">${cf_label}</a></span>`;
|
||||
}
|
||||
}
|
||||
tmpl += "</span>";
|
||||
}
|
||||
tmpl += "</td>" + "</tr>";
|
||||
|
||||
// return template
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
// template for filter items
|
||||
filter_element: function(filter_key, filter_value) {
|
||||
filter_value = Utils.sanitize(filter_value);
|
||||
return `<span class="text-filter-val">${filter_value}<a href="javascript:void(0);" filter_key="${filter_key}" filter_val="${filter_value}"><i class="fa fa-times" style="padding-left: 5px; padding-bottom: 6px;"/></a></span>`;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,677 @@
|
||||
// This is necessary so that, when nested arrays are used in ajax/post/get methods, square brackets ('[]') are
|
||||
// not appended to the identifier of a nested array.
|
||||
jQuery.ajaxSettings.traditional = true;
|
||||
|
||||
// dependencies
|
||||
import Utils from "utils/utils";
|
||||
import GridModel from "legacy/grid/grid-model";
|
||||
import Templates from "legacy/grid/grid-template";
|
||||
import PopupMenu from "mvc/ui/popup-menu";
|
||||
// grid view
|
||||
export default Backbone.View.extend({
|
||||
// model
|
||||
grid: null,
|
||||
|
||||
// Initialize
|
||||
initialize: function(grid_config) {
|
||||
this.grid = new GridModel();
|
||||
this.dict_format = grid_config.dict_format;
|
||||
this.title = grid_config.title;
|
||||
var self = this;
|
||||
window.add_tag_to_grid_filter = (tag_name, tag_value) => {
|
||||
// Put tag name and value together.
|
||||
var tag = tag_name + (tag_value !== undefined && tag_value !== "" ? `:${tag_value}` : "");
|
||||
var advanced_search = $("#advanced-search").is(":visible");
|
||||
if (!advanced_search) {
|
||||
$("#standard-search").slideToggle("fast");
|
||||
$("#advanced-search").slideToggle("fast");
|
||||
}
|
||||
self.add_filter_condition("tags", tag);
|
||||
};
|
||||
|
||||
// set element
|
||||
if (this.dict_format) {
|
||||
this.setElement("<div/>");
|
||||
if (grid_config.url_base && !grid_config.items) {
|
||||
var url_data = grid_config.url_data || {};
|
||||
_.each(grid_config.filters, (v, k) => {
|
||||
url_data[`f-${k}`] = v;
|
||||
});
|
||||
$.ajax({
|
||||
url: `${grid_config.url_base}?${$.param(url_data)}`,
|
||||
success: function(response) {
|
||||
response.embedded = grid_config.embedded;
|
||||
response.filters = grid_config.filters || {};
|
||||
self.init_grid(response);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.init_grid(grid_config);
|
||||
}
|
||||
} else {
|
||||
this.setElement("#grid-container");
|
||||
this.init_grid(grid_config);
|
||||
}
|
||||
|
||||
// fix padding
|
||||
if (grid_config.use_panels) {
|
||||
$("#center").css({
|
||||
padding: "10px",
|
||||
overflow: "auto"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// refresh frames
|
||||
handle_refresh: function(refresh_frames) {
|
||||
if (refresh_frames) {
|
||||
if ($.inArray("history", refresh_frames) > -1) {
|
||||
if (window.top.Galaxy && window.top.Galaxy.currHistoryPanel) {
|
||||
window.top.Galaxy.currHistoryPanel.loadCurrentHistory();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Initialize
|
||||
init_grid: function(grid_config) {
|
||||
this.grid.set(grid_config);
|
||||
|
||||
// get options
|
||||
var options = this.grid.attributes;
|
||||
|
||||
if (this.allow_title_display && options.title) {
|
||||
Utils.setWindowTitle(options.title);
|
||||
}
|
||||
// handle refresh requests
|
||||
this.handle_refresh(options.refresh_frames);
|
||||
|
||||
// strip protocol and domain
|
||||
var url = this.grid.get("url_base");
|
||||
url = url.replace(/^.*\/\/[^\/]+/, "");
|
||||
this.grid.set("url_base", url);
|
||||
|
||||
// append main template
|
||||
this.$el.html(Templates.grid(options));
|
||||
|
||||
// update div contents
|
||||
this.$el.find("#grid-table-header").html(Templates.header(options));
|
||||
this.$el.find("#grid-table-body").html(Templates.body(options));
|
||||
this.$el.find("#grid-table-footer").html(Templates.footer(options));
|
||||
|
||||
// update message
|
||||
if (options.message) {
|
||||
this.$el.find("#grid-message").html(Templates.message(options));
|
||||
var self = this;
|
||||
if (options.use_hide_message) {
|
||||
setTimeout(() => {
|
||||
self.$el.find("#grid-message").html("");
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// configure elements
|
||||
this.init_grid_elements();
|
||||
this.init_grid_controls();
|
||||
|
||||
// attach global event handler
|
||||
// TODO: redundant (the onload/standard page handlers do this) - but needed because these are constructed after page ready
|
||||
if (window.init_refresh_on_change) {
|
||||
window.init_refresh_on_change();
|
||||
}
|
||||
},
|
||||
|
||||
// Initialize grid controls
|
||||
init_grid_controls: function() {
|
||||
// link
|
||||
var self = this;
|
||||
|
||||
// Initialize grid operation button.
|
||||
this.$el.find(".operation-button").each(function() {
|
||||
$(this).off();
|
||||
$(this).click(function() {
|
||||
self.submit_operation(this);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize text filters to select text on click and use normal font when user is typing.
|
||||
this.$el.find("input[type=text]").each(function() {
|
||||
$(this).off();
|
||||
$(this)
|
||||
.click(function() {
|
||||
$(this).select();
|
||||
})
|
||||
.keyup(function() {
|
||||
$(this).css("font-style", "normal");
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize sort links.
|
||||
this.$el.find(".sort-link").each(function() {
|
||||
$(this).off();
|
||||
$(this).click(function() {
|
||||
self.set_sort_condition($(this).attr("sort_key"));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize text filters.
|
||||
this.$el.find(".text-filter-form").each(function() {
|
||||
$(this).off();
|
||||
$(this).submit(function() {
|
||||
var column_key = $(this).attr("column_key");
|
||||
var text_input_obj = $(`#input-${column_key}-filter`);
|
||||
var text_input = text_input_obj.val();
|
||||
text_input_obj.val("");
|
||||
self.add_filter_condition(column_key, text_input);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize categorical filters.
|
||||
this.$el.find(".text-filter-val > a").each(function() {
|
||||
$(this).off();
|
||||
$(this).click(function() {
|
||||
// Remove visible element.
|
||||
$(this)
|
||||
.parent()
|
||||
.remove();
|
||||
|
||||
// Remove filter condition.
|
||||
self.remove_filter_condition($(this).attr("filter_key"), $(this).attr("filter_val"));
|
||||
|
||||
// Return
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize categorical filters.
|
||||
this.$el.find(".categorical-filter > a").each(function() {
|
||||
$(this).off();
|
||||
$(this).click(function() {
|
||||
self.set_categorical_filter($(this).attr("filter_key"), $(this).attr("filter_val"));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize standard, advanced search toggles.
|
||||
this.$el.find(".advanced-search-toggle").each(function() {
|
||||
$(this).off();
|
||||
$(this).click(() => {
|
||||
self.$el.find("#standard-search").slideToggle("fast");
|
||||
self.$el.find("#advanced-search").slideToggle("fast");
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// Add event to check all box
|
||||
this.$el.find("#check_all").off();
|
||||
this.$el.find("#check_all").on("click", () => {
|
||||
self.check_all_items();
|
||||
});
|
||||
},
|
||||
|
||||
// Initialize grid elements.
|
||||
init_grid_elements: function() {
|
||||
// Initialize grid selection checkboxes.
|
||||
this.$el.find(".grid").each(function() {
|
||||
var checkboxes = $(this).find("input.grid-row-select-checkbox");
|
||||
var check_count = $(this).find("span.grid-selected-count");
|
||||
var update_checked = () => {
|
||||
check_count.text($(checkboxes).filter(":checked").length);
|
||||
};
|
||||
|
||||
$(checkboxes).each(function() {
|
||||
$(this).change(update_checked);
|
||||
});
|
||||
update_checked();
|
||||
});
|
||||
|
||||
// Initialize ratings.
|
||||
if (this.$el.find(".community_rating_star").length !== 0) this.$el.find(".community_rating_star").rating({});
|
||||
|
||||
// get options
|
||||
var options = this.grid.attributes;
|
||||
var self = this;
|
||||
|
||||
//
|
||||
// add page click events
|
||||
//
|
||||
this.$el.find(".page-link > a").each(function() {
|
||||
$(this).click(function() {
|
||||
self.set_page($(this).attr("page_num"));
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
// add inbound/outbound events
|
||||
//
|
||||
this.$el.find(".use-target").each(function() {
|
||||
$(this).click(function() {
|
||||
self.execute({
|
||||
href: $(this).attr("href"),
|
||||
target: $(this).attr("target")
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
// empty grid?
|
||||
var items_length = options.items.length;
|
||||
if (items_length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add operation popup menus
|
||||
_.each(options.items, (item, index) => {
|
||||
var button = self.$(`#grid-${item.encode_id}-popup`).off();
|
||||
var popup = new PopupMenu(button);
|
||||
_.each(options.operations, operation => {
|
||||
self._add_operation(popup, operation, item);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/** Add an operation to the items menu */
|
||||
_add_operation: function(popup, operation, item) {
|
||||
var self = this;
|
||||
var settings = item.operation_config[operation.label];
|
||||
if (settings.allowed && operation.allow_popup) {
|
||||
popup.addItem({
|
||||
html: operation.label,
|
||||
href: settings.url_args,
|
||||
target: settings.target,
|
||||
confirmation_text: operation.confirm,
|
||||
func: function(e) {
|
||||
e.preventDefault();
|
||||
var label = $(e.target).html();
|
||||
if (operation.onclick) {
|
||||
operation.onclick(item.encode_id);
|
||||
} else {
|
||||
self.execute(this.findItemByHtml(label));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// Add a condition to the grid filter; this adds the condition and refreshes the grid.
|
||||
add_filter_condition: function(name, value) {
|
||||
// Do nothing is value is empty.
|
||||
if (value === "") {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add condition to grid.
|
||||
this.grid.add_filter(name, value, true);
|
||||
|
||||
// Add button that displays filter and provides a button to delete it.
|
||||
var t = $(Templates.filter_element(name, value));
|
||||
var self = this;
|
||||
t.click(function() {
|
||||
// Remove visible element.
|
||||
$(this).remove();
|
||||
|
||||
// Remove filter condition.
|
||||
self.remove_filter_condition(name, value);
|
||||
});
|
||||
|
||||
// append to container
|
||||
var container = this.$el.find(`#${name}-filtering-criteria`);
|
||||
container.append(t);
|
||||
|
||||
// execute
|
||||
this.go_page_one();
|
||||
this.execute();
|
||||
},
|
||||
|
||||
// Remove a condition to the grid filter; this adds the condition and refreshes the grid.
|
||||
remove_filter_condition: function(name, value) {
|
||||
// Remove filter condition.
|
||||
this.grid.remove_filter(name, value);
|
||||
|
||||
// Execute
|
||||
this.go_page_one();
|
||||
this.execute();
|
||||
},
|
||||
|
||||
// Set sort condition for grid.
|
||||
set_sort_condition: function(col_key) {
|
||||
// Set new sort condition. New sort is col_key if sorting new column; if reversing sort on
|
||||
// currently sorted column, sort is reversed.
|
||||
var cur_sort = this.grid.get("sort_key");
|
||||
var new_sort = col_key;
|
||||
if (cur_sort.indexOf(col_key) !== -1) {
|
||||
// Reverse sort.
|
||||
if (cur_sort.substring(0, 1) !== "-") {
|
||||
new_sort = `-${col_key}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove sort arrows elements.
|
||||
this.$el.find(".sort-arrow").remove();
|
||||
|
||||
// Add sort arrow element to new sort column.
|
||||
var sort_arrow = new_sort.substring(0, 1) == "-" ? "↑" : "↓";
|
||||
var t = $(`<span>${sort_arrow}</span>`).addClass("sort-arrow");
|
||||
|
||||
// Add to header
|
||||
this.$el.find(`#${col_key}-header`).append(t);
|
||||
|
||||
// Update grid.
|
||||
this.grid.set("sort_key", new_sort);
|
||||
this.go_page_one();
|
||||
this.execute();
|
||||
},
|
||||
|
||||
// Set new value for categorical filter.
|
||||
set_categorical_filter: function(name, new_value) {
|
||||
// Update filter hyperlinks to reflect new filter value.
|
||||
var category_filter = this.grid.get("categorical_filters")[name];
|
||||
|
||||
var cur_value = this.grid.get("filters")[name];
|
||||
var self = this;
|
||||
this.$el.find(`.${name}-filter`).each(function() {
|
||||
var text = $.trim($(this).text());
|
||||
var filter = category_filter[text];
|
||||
var filter_value = filter[name];
|
||||
if (filter_value == new_value) {
|
||||
// Remove filter link since grid will be using this filter. It is assumed that
|
||||
// this element has a single child, a hyperlink/anchor with text.
|
||||
$(this).empty();
|
||||
$(this).addClass("current-filter");
|
||||
$(this).append(text);
|
||||
} else if (filter_value == cur_value) {
|
||||
// Add hyperlink for this filter since grid will no longer be using this filter. It is assumed that
|
||||
// this element has a single child, a hyperlink/anchor.
|
||||
$(this).empty();
|
||||
var t = $(`<a href="#">${text}</a>`);
|
||||
t.click(() => {
|
||||
self.set_categorical_filter(name, filter_value);
|
||||
});
|
||||
$(this).removeClass("current-filter");
|
||||
$(this).append(t);
|
||||
}
|
||||
});
|
||||
|
||||
// Update grid.
|
||||
this.grid.add_filter(name, new_value);
|
||||
this.go_page_one();
|
||||
this.execute();
|
||||
},
|
||||
|
||||
// Set page to view.
|
||||
set_page: function(new_page) {
|
||||
// Update page hyperlink to reflect new page.
|
||||
var self = this;
|
||||
this.$el.find(".page-link").each(function() {
|
||||
var id = $(this).attr("id");
|
||||
|
||||
var // Id has form 'page-link-<page_num>
|
||||
page_num = parseInt(id.split("-")[2], 10);
|
||||
|
||||
var cur_page = self.grid.get("cur_page");
|
||||
var text;
|
||||
if (page_num === new_page) {
|
||||
// Remove link to page since grid will be on this page. It is assumed that
|
||||
// this element has a single child, a hyperlink/anchor with text.
|
||||
text = $(this)
|
||||
.children()
|
||||
.text();
|
||||
$(this).empty();
|
||||
$(this).addClass("inactive-link");
|
||||
$(this).text(text);
|
||||
} else if (page_num === cur_page) {
|
||||
// Add hyperlink to this page since grid will no longer be on this page. It is assumed that
|
||||
// this element has a single child, a hyperlink/anchor.
|
||||
text = $(this).text();
|
||||
$(this).empty();
|
||||
$(this).removeClass("inactive-link");
|
||||
var t = $(`<a href="#">${text}</a>`);
|
||||
t.click(() => {
|
||||
self.set_page(page_num);
|
||||
});
|
||||
$(this).append(t);
|
||||
}
|
||||
});
|
||||
|
||||
if (new_page === "all") {
|
||||
this.grid.set("cur_page", new_page);
|
||||
} else {
|
||||
this.grid.set("cur_page", parseInt(new_page, 10));
|
||||
}
|
||||
this.execute();
|
||||
},
|
||||
|
||||
// confirmation/submission of operation request
|
||||
submit_operation: function(operation_button, confirmation_text) {
|
||||
// identify operation
|
||||
var operation_name = $(operation_button).val();
|
||||
|
||||
// verify any item is selected
|
||||
var number_of_checked_ids = this.$el.find('input[name="id"]:checked').length;
|
||||
if (number_of_checked_ids < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check to see if there's grid confirmation text for this operation
|
||||
var operation = _.findWhere(this.grid.attributes.operations, {
|
||||
label: operation_name
|
||||
});
|
||||
if (operation && !confirmation_text) {
|
||||
confirmation_text = operation.confirm || "";
|
||||
}
|
||||
|
||||
// collect ids
|
||||
var item_ids = [];
|
||||
this.$el.find("input[name=id]:checked").each(function() {
|
||||
item_ids.push($(this).val());
|
||||
});
|
||||
|
||||
// execute operation
|
||||
var options = {
|
||||
operation: operation_name,
|
||||
id: item_ids,
|
||||
confirmation_text: confirmation_text
|
||||
};
|
||||
if (operation.target == "top" || operation.target == "center") {
|
||||
options = _.extend(options, {
|
||||
href: operation.href,
|
||||
target: operation.target
|
||||
});
|
||||
}
|
||||
this.execute(options);
|
||||
return true;
|
||||
},
|
||||
|
||||
check_all_items: function() {
|
||||
var check = this.$(".grid-row-select-checkbox");
|
||||
var state = this.$("#check_all").prop("checked");
|
||||
_.each(check, c => {
|
||||
$(c).prop("checked", state);
|
||||
});
|
||||
this.init_grid_elements();
|
||||
},
|
||||
|
||||
// Go back to page one; this is useful when a filter is applied.
|
||||
go_page_one: function() {
|
||||
// Need to go back to page 1 if not showing all.
|
||||
var cur_page = this.grid.get("cur_page");
|
||||
if (cur_page !== null && cur_page !== undefined && cur_page !== "all") {
|
||||
this.grid.set("cur_page", 1);
|
||||
}
|
||||
},
|
||||
|
||||
//
|
||||
// execute operations and hyperlink requests
|
||||
//
|
||||
execute: function(options) {
|
||||
// get url
|
||||
var id = null;
|
||||
var href = null;
|
||||
var operation = null;
|
||||
var confirmation_text = null;
|
||||
var target = null;
|
||||
|
||||
// check for options
|
||||
if (options) {
|
||||
// get options
|
||||
href = options.href;
|
||||
operation = options.operation;
|
||||
id = options.id;
|
||||
confirmation_text = options.confirmation_text;
|
||||
target = options.target;
|
||||
|
||||
// check if input contains the operation tag
|
||||
if (href !== undefined && href.indexOf("operation=") != -1) {
|
||||
// Get operation, id in hyperlink's href.
|
||||
var href_parts = href.split("?");
|
||||
if (href_parts.length > 1) {
|
||||
var href_parms_str = href_parts[1];
|
||||
var href_parms = href_parms_str.split("&");
|
||||
for (var index = 0; index < href_parms.length; index++) {
|
||||
if (href_parms[index].indexOf("operation") != -1) {
|
||||
// Found operation parm; get operation value.
|
||||
operation = href_parms[index].split("=")[1];
|
||||
operation = operation.replace(/\+/g, " ");
|
||||
} else if (href_parms[index].indexOf("id") != -1) {
|
||||
// Found id parm; get id value.
|
||||
id = href_parms[index].split("=")[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for operation details
|
||||
if (operation && id) {
|
||||
// show confirmation box
|
||||
if (
|
||||
confirmation_text &&
|
||||
confirmation_text !== "" &&
|
||||
confirmation_text != "None" &&
|
||||
confirmation_text != "null"
|
||||
)
|
||||
if (!confirm(confirmation_text)) return false;
|
||||
|
||||
// use small characters for operation?!
|
||||
operation = operation.toLowerCase();
|
||||
|
||||
// Update grid.
|
||||
this.grid.set({
|
||||
operation: operation,
|
||||
item_ids: id
|
||||
});
|
||||
|
||||
// Do operation. If operation cannot be performed asynchronously, redirect to location.
|
||||
if (target == "top") {
|
||||
window.top.location = `${href}?${$.param(this.grid.get_url_data())}`;
|
||||
} else if (target == "center") {
|
||||
$("#galaxy_main").attr("src", `${href}?${$.param(this.grid.get_url_data())}`);
|
||||
} else if (this.grid.can_async_op(operation) || this.dict_format) {
|
||||
this.update_grid();
|
||||
} else {
|
||||
this.go_to(target, href);
|
||||
}
|
||||
|
||||
// done
|
||||
return false;
|
||||
}
|
||||
|
||||
// refresh grid
|
||||
if (href) {
|
||||
this.go_to(target, href);
|
||||
return false;
|
||||
}
|
||||
|
||||
// refresh grid
|
||||
if (this.grid.get("async") || this.dict_format) {
|
||||
this.update_grid();
|
||||
} else {
|
||||
this.go_to(target, href);
|
||||
}
|
||||
|
||||
// done
|
||||
return false;
|
||||
},
|
||||
|
||||
// go to url
|
||||
go_to: function(target, href) {
|
||||
// get aysnc status
|
||||
var async = this.grid.get("async");
|
||||
this.grid.set("async", false);
|
||||
|
||||
// get slide status
|
||||
var advanced_search = this.$el.find("#advanced-search").is(":visible");
|
||||
this.grid.set("advanced_search", advanced_search);
|
||||
|
||||
// get default url
|
||||
if (!href) {
|
||||
href = `${this.grid.get("url_base")}?${$.param(this.grid.get_url_data())}`;
|
||||
}
|
||||
|
||||
// clear grid of transient request attributes.
|
||||
this.grid.set({
|
||||
operation: undefined,
|
||||
item_ids: undefined,
|
||||
async: async
|
||||
});
|
||||
switch (target) {
|
||||
case "center":
|
||||
$("#galaxy_main").attr("src", href);
|
||||
break;
|
||||
case "top":
|
||||
window.top.location = href;
|
||||
break;
|
||||
default:
|
||||
window.location = href;
|
||||
}
|
||||
},
|
||||
|
||||
// Update grid.
|
||||
update_grid: function() {
|
||||
// If there's an operation, do POST; otherwise, do GET.
|
||||
var method = this.grid.get("operation") ? "POST" : "GET";
|
||||
|
||||
// Show overlay to indicate loading and prevent user actions.
|
||||
this.$el.find(".loading-elt-overlay").show();
|
||||
var self = this;
|
||||
$.ajax({
|
||||
type: method,
|
||||
url: self.grid.get("url_base"),
|
||||
data: self.grid.get_url_data(),
|
||||
error: function() {
|
||||
alert("Grid refresh failed");
|
||||
},
|
||||
success: function(response_text) {
|
||||
// backup
|
||||
var embedded = self.grid.get("embedded");
|
||||
var insert = self.grid.get("insert");
|
||||
var advanced_search = self.$el.find("#advanced-search").is(":visible");
|
||||
|
||||
// request new configuration
|
||||
var json = self.dict_format ? response_text : $.parseJSON(response_text);
|
||||
|
||||
// update
|
||||
json.embedded = embedded;
|
||||
json.insert = insert;
|
||||
json.advanced_search = advanced_search;
|
||||
|
||||
// Initialize new grid config
|
||||
self.init_grid(json);
|
||||
|
||||
// Hide loading overlay.
|
||||
self.$el.find(".loading-elt-overlay").hide();
|
||||
},
|
||||
complete: function() {
|
||||
// Clear grid of transient request attributes.
|
||||
self.grid.set({
|
||||
operation: undefined,
|
||||
item_ids: undefined
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -17,13 +17,6 @@ export default Backbone.Model.extend({
|
||||
item_ids: undefined
|
||||
},
|
||||
|
||||
/**
|
||||
* Return true if operation can be done asynchronously.
|
||||
*/
|
||||
can_async_op: function(op) {
|
||||
return _.indexOf(this.attributes.async_ops, op) !== -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Add filtering criterion.
|
||||
*/
|
||||
|
||||
@@ -10,7 +10,6 @@ var View = Backbone.View.extend({
|
||||
$.ajax({
|
||||
url: `${Galaxy.root + this.item}/${this.model.get("action_id")}?${$.param(Galaxy.params)}`,
|
||||
success: function(response) {
|
||||
response["dict_format"] = true;
|
||||
self.model.set(response);
|
||||
self.render();
|
||||
}
|
||||
|
||||
@@ -112,14 +112,12 @@ export default {
|
||||
body: function(options) {
|
||||
// initialize
|
||||
var tmpl = "";
|
||||
var num_rows_rendered = 0;
|
||||
var items_length = options.items.length;
|
||||
|
||||
// empty grid?
|
||||
if (items_length === 0) {
|
||||
// No results.
|
||||
tmpl += '<tr><td colspan="100"><em>No Items</em></td></tr>';
|
||||
num_rows_rendered = 1;
|
||||
}
|
||||
|
||||
// create rows
|
||||
@@ -193,7 +191,6 @@ export default {
|
||||
}
|
||||
}
|
||||
tmpl += "</tr>";
|
||||
num_rows_rendered++;
|
||||
}
|
||||
return tmpl;
|
||||
},
|
||||
|
||||
@@ -15,7 +15,6 @@ export default Backbone.View.extend({
|
||||
// Initialize
|
||||
initialize: function(grid_config) {
|
||||
this.grid = new GridModel();
|
||||
this.dict_format = grid_config.dict_format;
|
||||
this.title = grid_config.title;
|
||||
var self = this;
|
||||
window.add_tag_to_grid_filter = (tag_name, tag_value) => {
|
||||
@@ -30,26 +29,21 @@ export default Backbone.View.extend({
|
||||
};
|
||||
|
||||
// set element
|
||||
if (this.dict_format) {
|
||||
this.setElement("<div/>");
|
||||
if (grid_config.url_base && !grid_config.items) {
|
||||
var url_data = grid_config.url_data || {};
|
||||
_.each(grid_config.filters, (v, k) => {
|
||||
url_data[`f-${k}`] = v;
|
||||
});
|
||||
$.ajax({
|
||||
url: `${grid_config.url_base}?${$.param(url_data)}`,
|
||||
success: function(response) {
|
||||
response.embedded = grid_config.embedded;
|
||||
response.filters = grid_config.filters || {};
|
||||
self.init_grid(response);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.init_grid(grid_config);
|
||||
}
|
||||
this.setElement("<div/>");
|
||||
if (grid_config.url_base && !grid_config.items) {
|
||||
var url_data = grid_config.url_data || {};
|
||||
_.each(grid_config.filters, (v, k) => {
|
||||
url_data[`f-${k}`] = v;
|
||||
});
|
||||
$.ajax({
|
||||
url: `${grid_config.url_base}?${$.param(url_data)}`,
|
||||
success: function(response) {
|
||||
response.embedded = grid_config.embedded;
|
||||
response.filters = grid_config.filters || {};
|
||||
self.init_grid(response);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.setElement("#grid-container");
|
||||
this.init_grid(grid_config);
|
||||
}
|
||||
|
||||
@@ -570,10 +564,8 @@ export default Backbone.View.extend({
|
||||
window.top.location = `${href}?${$.param(this.grid.get_url_data())}`;
|
||||
} else if (target == "center") {
|
||||
$("#galaxy_main").attr("src", `${href}?${$.param(this.grid.get_url_data())}`);
|
||||
} else if (this.grid.can_async_op(operation) || this.dict_format) {
|
||||
this.update_grid();
|
||||
} else {
|
||||
this.go_to(target, href);
|
||||
this.update_grid();
|
||||
}
|
||||
|
||||
// done
|
||||
@@ -587,11 +579,7 @@ export default Backbone.View.extend({
|
||||
}
|
||||
|
||||
// refresh grid
|
||||
if (this.grid.get("async") || this.dict_format) {
|
||||
this.update_grid();
|
||||
} else {
|
||||
this.go_to(target, href);
|
||||
}
|
||||
this.update_grid();
|
||||
|
||||
// done
|
||||
return false;
|
||||
@@ -599,10 +587,6 @@ export default Backbone.View.extend({
|
||||
|
||||
// go to url
|
||||
go_to: function(target, href) {
|
||||
// get aysnc status
|
||||
var async = this.grid.get("async");
|
||||
this.grid.set("async", false);
|
||||
|
||||
// get slide status
|
||||
var advanced_search = this.$el.find("#advanced-search").is(":visible");
|
||||
this.grid.set("advanced_search", advanced_search);
|
||||
@@ -615,8 +599,7 @@ export default Backbone.View.extend({
|
||||
// clear grid of transient request attributes.
|
||||
this.grid.set({
|
||||
operation: undefined,
|
||||
item_ids: undefined,
|
||||
async: async
|
||||
item_ids: undefined
|
||||
});
|
||||
switch (target) {
|
||||
case "center":
|
||||
@@ -652,7 +635,7 @@ export default Backbone.View.extend({
|
||||
var advanced_search = self.$el.find("#advanced-search").is(":visible");
|
||||
|
||||
// request new configuration
|
||||
var json = self.dict_format ? response_text : $.parseJSON(response_text);
|
||||
var json = response_text;
|
||||
|
||||
// update
|
||||
json.embedded = embedded;
|
||||
|
||||
@@ -60,7 +60,6 @@ var View = Backbone.View.extend({
|
||||
Utils.get({
|
||||
url: `${Galaxy.root}history/${options.action_id}?${$.param(Galaxy.params)}`,
|
||||
success: function(response) {
|
||||
response.dict_format = true;
|
||||
self.model.set(response);
|
||||
self.render();
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ var ToolShedRepositoryView = Backbone.View.extend({
|
||||
"<% _.each(shed_tool_confs.options, function(conf) { %>",
|
||||
'<option value="<%= conf.value %>"><%= conf.label %></option>',
|
||||
"<% }); %>",
|
||||
'</select>',
|
||||
"</select>",
|
||||
'<div class="toolParamHelp" style="clear: both;">Select the file whose <b>tool_path</b> setting you want used for installing repositories.</div>',
|
||||
"</div>",
|
||||
"</div>"
|
||||
|
||||
@@ -62,7 +62,7 @@ var Model = Backbone.Model.extend({
|
||||
description: _l("Associate OpenIDs with your account."),
|
||||
icon: "fa-openid",
|
||||
onclick: function() {
|
||||
window.location.href = `${Galaxy.root}user/openid_manage?cntrller=user&use_panels=True`;
|
||||
window.location.href = `${Galaxy.root}openids/list`;
|
||||
}
|
||||
},
|
||||
custom_builds: {
|
||||
|
||||
@@ -459,7 +459,6 @@ var TracksterView = Backbone.View.extend({
|
||||
view_in_saved: function(dataset_params) {
|
||||
var tracks_grid = new GridView({
|
||||
url_base: `${Galaxy.root}visualization/list_tracks`,
|
||||
dict_format: true,
|
||||
embedded: true
|
||||
});
|
||||
Galaxy.modal.show({
|
||||
|
||||
@@ -46,14 +46,12 @@ var select_datasets = (filters, success_fn) => {
|
||||
var history_grid = new GridView({
|
||||
url_base: `${Galaxy.root}visualization/list_history_datasets`,
|
||||
filters: filters,
|
||||
dict_format: true,
|
||||
embedded: true
|
||||
});
|
||||
|
||||
// library dataset selection tab
|
||||
var library_grid = new GridView({
|
||||
url_base: `${Galaxy.root}visualization/list_library_datasets`,
|
||||
dict_format: true,
|
||||
embedded: true
|
||||
});
|
||||
|
||||
|
||||
@@ -1289,21 +1289,6 @@ class UsesFormDefinitionsMixin:
|
||||
else:
|
||||
return [fdc.latest_form for fdc in fdc_list if fdc.latest_form.type == form_type]
|
||||
|
||||
def field_param_values_ok(self, widget_name, widget_type, **kwd):
|
||||
# Make sure required fields have contents, etc
|
||||
params = util.Params(kwd)
|
||||
if widget_type == 'AddressField':
|
||||
if not util.restore_text(params.get('%s_short_desc' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_name' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_institution' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_address' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_city' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_state' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_postal_code' % widget_name, '')) \
|
||||
or not util.restore_text(params.get('%s_country' % widget_name, '')):
|
||||
return False
|
||||
return True
|
||||
|
||||
def save_widget_field(self, trans, field_obj, widget_name, **kwd):
|
||||
# Save a form_builder field object
|
||||
params = util.Params(kwd)
|
||||
|
||||
@@ -10,7 +10,6 @@ from galaxy.model.item_attrs import RuntimeException, UsesAnnotations, UsesItemR
|
||||
from galaxy.util import restore_text, sanitize_text, unicodify
|
||||
from galaxy.util.odict import odict
|
||||
from galaxy.web.framework import decorators, url_for
|
||||
from galaxy.web.framework.helpers import iff
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -21,12 +20,8 @@ class Grid(object):
|
||||
Specifies the content and format of a grid (data table).
|
||||
"""
|
||||
title = ""
|
||||
exposed = True
|
||||
model_class = None
|
||||
show_item_checkboxes = False
|
||||
template = "grid_base.mako"
|
||||
async_template = "grid_base_async.mako"
|
||||
use_async = False
|
||||
use_hide_message = True
|
||||
global_actions = []
|
||||
columns = []
|
||||
@@ -35,14 +30,12 @@ class Grid(object):
|
||||
# Any columns that are filterable (either standard or advanced) should have a default value set in the default filter.
|
||||
default_filter = {}
|
||||
default_sort_key = None
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
num_rows_per_page = 25
|
||||
num_page_links = 10
|
||||
# Set preference names.
|
||||
cur_filter_pref_name = ".filter"
|
||||
cur_sort_key_pref_name = ".sort_key"
|
||||
pass_through_operations = {}
|
||||
legend = None
|
||||
info_text = None
|
||||
|
||||
@@ -65,7 +58,6 @@ class Grid(object):
|
||||
# FIXME: pretty sure this is only here to pass along, can likely be eliminated
|
||||
status = kwargs.get('status', None)
|
||||
message = kwargs.get('message', None)
|
||||
dict_format = kwargs.get('dict_format', False)
|
||||
# Build a base filter and sort key that is the combination of the saved state and defaults.
|
||||
# Saved state takes preference over defaults.
|
||||
base_filter = {}
|
||||
@@ -73,14 +65,6 @@ class Grid(object):
|
||||
# default_filter is a dictionary that provides a default set of filters based on the grid's columns.
|
||||
base_filter = self.default_filter.copy()
|
||||
base_sort_key = self.default_sort_key
|
||||
if self.preserve_state:
|
||||
pref_name = text_type(self.__class__.__name__ + self.cur_filter_pref_name)
|
||||
if pref_name in trans.get_user().preferences:
|
||||
saved_filter = loads(trans.get_user().preferences[pref_name])
|
||||
base_filter.update(saved_filter)
|
||||
pref_name = text_type(self.__class__.__name__ + self.cur_sort_key_pref_name)
|
||||
if pref_name in trans.get_user().preferences:
|
||||
base_sort_key = loads(trans.get_user().preferences[pref_name])
|
||||
# Build initial query
|
||||
query = self.build_initial_query(trans, **kwargs)
|
||||
query = self.apply_query_filter(trans, query, **kwargs)
|
||||
@@ -228,26 +212,11 @@ class Grid(object):
|
||||
# There are some places in grid templates where it's useful for a grid
|
||||
# to have its current filter.
|
||||
self.cur_filter_dict = cur_filter_dict
|
||||
# Preserve grid state: save current filter and sort key.
|
||||
if self.preserve_state:
|
||||
pref_name = text_type(self.__class__.__name__ + self.cur_filter_pref_name)
|
||||
trans.get_user().preferences[pref_name] = text_type(dumps(cur_filter_dict))
|
||||
if sort_key:
|
||||
pref_name = text_type(self.__class__.__name__ + self.cur_sort_key_pref_name)
|
||||
trans.get_user().preferences[pref_name] = text_type(dumps(sort_key))
|
||||
trans.sa_session.flush()
|
||||
|
||||
# Log grid view.
|
||||
context = text_type(self.__class__.__name__)
|
||||
params = cur_filter_dict.copy()
|
||||
params['sort'] = sort_key
|
||||
params['async'] = ('async' in kwargs)
|
||||
|
||||
# TODO:??
|
||||
# commenting this out; when this fn calls session.add( action ) and session.flush the query from this fn
|
||||
# is effectively 'wiped' out. Nate believes it has something to do with our use of session( autocommit=True )
|
||||
# in mapping.py. If you change that to False, the log_action doesn't affect the query
|
||||
# Below, I'm rendering the template first (that uses query), then calling log_action, then returning the page
|
||||
# trans.log_action( trans.get_user(), text_type( "grid.view" ), context, params )
|
||||
|
||||
# Render grid.
|
||||
def url(*args, **kwargs):
|
||||
@@ -280,43 +249,14 @@ class Grid(object):
|
||||
|
||||
self.use_panels = (kwargs.get('use_panels', False) in [True, 'True', 'true'])
|
||||
self.advanced_search = (kwargs.get('advanced_search', False) in [True, 'True', 'true'])
|
||||
async_request = ((self.use_async) and (kwargs.get('async', False) in [True, 'True', 'true']))
|
||||
# Currently, filling the template returns a str object; this requires decoding the string into a
|
||||
# unicode object within mako templates. What probably should be done is to return the template as
|
||||
# utf-8 unicode; however, this would require encoding the object as utf-8 before returning the grid
|
||||
# results via a controller method, which is require substantial changes. Hence, for now, return grid
|
||||
# as str.
|
||||
if not dict_format:
|
||||
page = trans.fill_template(iff(async_request, self.async_template, self.template),
|
||||
grid=self,
|
||||
query=query,
|
||||
cur_page_num=page_num,
|
||||
num_pages=num_pages,
|
||||
num_page_links=self.num_page_links,
|
||||
default_filter_dict=self.default_filter,
|
||||
cur_filter_dict=cur_filter_dict,
|
||||
sort_key=sort_key,
|
||||
current_item=current_item,
|
||||
ids=kwargs.get('id', []),
|
||||
url=url,
|
||||
status=status,
|
||||
message=message,
|
||||
info_text=self.info_text,
|
||||
use_panels=self.use_panels,
|
||||
use_hide_message=self.use_hide_message,
|
||||
advanced_search=self.advanced_search,
|
||||
show_item_checkboxes=(self.show_item_checkboxes or
|
||||
kwargs.get('show_item_checkboxes', '') in ['True', 'true']),
|
||||
# Pass back kwargs so that grid template can set and use args without
|
||||
# grid explicitly having to pass them.
|
||||
kwargs=kwargs)
|
||||
trans.log_action(trans.get_user(), text_type("grid.view"), context, params)
|
||||
return page
|
||||
|
||||
grid_config = {
|
||||
'title' : self.title,
|
||||
'url_base' : trans.request.path_url,
|
||||
'async' : self.use_async,
|
||||
'async_ops' : [],
|
||||
'categorical_filters' : {},
|
||||
'filters' : cur_filter_dict,
|
||||
|
||||
@@ -106,6 +106,7 @@ def app_factory(global_conf, load_app_kwds={}, **kwargs):
|
||||
webapp.add_client_route('/tours/{tour_id}')
|
||||
webapp.add_client_route('/user')
|
||||
webapp.add_client_route('/user/{form_id}')
|
||||
webapp.add_client_route('/openids/list')
|
||||
webapp.add_client_route('/visualizations/list_published')
|
||||
webapp.add_client_route('/visualizations/list')
|
||||
webapp.add_client_route('/visualizations/edit')
|
||||
|
||||
@@ -154,7 +154,6 @@ class UserListGrid(grids.Grid):
|
||||
grids.GridColumnFilter("All", args=dict(deleted='All'))
|
||||
]
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
def get_current_item(self, trans, **kwargs):
|
||||
@@ -255,7 +254,6 @@ class RoleListGrid(grids.Grid):
|
||||
grids.GridColumnFilter("All", args=dict(deleted='All'))
|
||||
]
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
def apply_query_filter(self, trans, query, **kwargs):
|
||||
@@ -335,7 +333,6 @@ class GroupListGrid(grids.Grid):
|
||||
grids.GridColumnFilter("All", args=dict(deleted='All'))
|
||||
]
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
|
||||
@@ -447,7 +444,6 @@ class QuotaListGrid(grids.Grid):
|
||||
grids.GridColumnFilter("All", args=dict(deleted='All'))
|
||||
]
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
|
||||
@@ -499,7 +495,6 @@ class ToolVersionListGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = {}
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
@@ -559,7 +554,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
|
||||
if message and status:
|
||||
kwd['message'] = util.sanitize_text(message)
|
||||
kwd['status'] = status
|
||||
kwd['dict_format'] = True
|
||||
return self.user_list_grid(trans, **kwd)
|
||||
|
||||
@web.expose_api
|
||||
@@ -592,7 +586,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
|
||||
if message:
|
||||
kwargs['message'] = util.sanitize_text(message)
|
||||
kwargs['status'] = status or 'done'
|
||||
kwargs['dict_format'] = True
|
||||
return self.quota_list_grid(trans, **kwargs)
|
||||
|
||||
@web.expose_api
|
||||
@@ -902,7 +895,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
|
||||
@web.expose_api
|
||||
@web.require_admin
|
||||
def tool_versions_list(self, trans, **kwd):
|
||||
kwd['dict_format'] = True
|
||||
return self.tool_version_list_grid(trans, **kwd)
|
||||
|
||||
@web.expose
|
||||
@@ -923,7 +915,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
|
||||
message, status = self._undelete_role(trans, ids)
|
||||
elif operation == 'purge':
|
||||
message, status = self._purge_role(trans, ids)
|
||||
kwargs['dict_format'] = True
|
||||
if message and status:
|
||||
kwargs['message'] = util.sanitize_text(message)
|
||||
kwargs['status'] = status
|
||||
@@ -1168,7 +1159,6 @@ class AdminGalaxy(controller.JSAppLauncher, AdminActions, UsesQuotaMixin, QuotaP
|
||||
message, status = self._undelete_group(trans, ids)
|
||||
elif operation == 'purge':
|
||||
message, status = self._purge_group(trans, ids)
|
||||
kwargs['dict_format'] = True
|
||||
if message and status:
|
||||
kwargs['message'] = util.sanitize_text(message)
|
||||
kwargs['status'] = status
|
||||
|
||||
@@ -88,7 +88,6 @@ class AdminToolshed(AdminGalaxy):
|
||||
if message and status:
|
||||
kwd['message'] = util.sanitize_text(message)
|
||||
kwd['status'] = 'success' if status in ['ok', 'done', 'success'] else 'error'
|
||||
kwd['dict_format'] = True
|
||||
return self.installed_repository_grid(trans, **kwd)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -87,8 +87,6 @@ class HistoryDatasetAssociationListGrid(grids.Grid):
|
||||
]
|
||||
standard_filters = []
|
||||
default_filter = dict(name="All", deleted="False", tags="All")
|
||||
preserve_state = False
|
||||
use_async = True
|
||||
use_paging = True
|
||||
num_rows_per_page = 50
|
||||
|
||||
@@ -572,7 +570,6 @@ class DatasetInterface(BaseUIController, UsesAnnotations, UsesItemRatings, UsesE
|
||||
kwargs['refresh_frames'] = ['history']
|
||||
|
||||
# Render the list view
|
||||
kwargs['dict_format'] = True
|
||||
return self.stored_list_grid(trans, status=status, message=message, **kwargs)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -39,7 +39,6 @@ class FormsGrid(grids.Grid):
|
||||
model_class = model.FormDefinitionCurrent
|
||||
default_sort_key = "-update_time"
|
||||
num_rows_per_page = 50
|
||||
preserve_state = True
|
||||
use_paging = True
|
||||
default_filter = dict(deleted="False")
|
||||
columns = [
|
||||
@@ -99,7 +98,6 @@ class Forms(BaseUIController):
|
||||
if message and status:
|
||||
kwd['message'] = util.sanitize_text(message)
|
||||
kwd['status'] = status
|
||||
kwd['dict_format'] = True
|
||||
return self.forms_grid(trans, **kwd)
|
||||
|
||||
@web.expose_api
|
||||
|
||||
@@ -130,8 +130,6 @@ class HistoryListGrid(grids.Grid):
|
||||
]
|
||||
default_filter = dict(name="All", deleted="False", tags="All", sharing="All")
|
||||
num_rows_per_page = 15
|
||||
preserve_state = False
|
||||
use_async = True
|
||||
use_paging = True
|
||||
info_text = "Histories that have been deleted for more than a time period specified by the Galaxy administrator(s) may be permanently deleted."
|
||||
|
||||
@@ -194,7 +192,6 @@ class HistoryAllPublishedGrid(grids.Grid):
|
||||
default_filter = dict(public_url="All", username="All", tags="All")
|
||||
use_paging = True
|
||||
num_rows_per_page = 50
|
||||
use_async = True
|
||||
columns = [
|
||||
NameURLColumn("Name", key="name", filterable="advanced"),
|
||||
grids.OwnerAnnotationColumn("Annotation", key="annotation", model_annotation_association_class=model.HistoryAnnotationAssociation, filterable="advanced"),
|
||||
@@ -246,7 +243,6 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
@web.expose
|
||||
@web.json
|
||||
def list_published(self, trans, **kwargs):
|
||||
kwargs['dict_format'] = True
|
||||
return self.published_list_grid(trans, **kwargs)
|
||||
|
||||
@web.expose_api
|
||||
@@ -316,7 +312,6 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
|
||||
trans.sa_session.flush()
|
||||
# Render the list view
|
||||
kwargs['dict_format'] = True
|
||||
if message and status:
|
||||
kwargs['message'] = sanitize_text(message)
|
||||
kwargs['status'] = status
|
||||
@@ -454,7 +449,6 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
message = "Unshared %d shared histories" % len(ids)
|
||||
status = 'done'
|
||||
# Render the list view
|
||||
kwargs['dict_format'] = True
|
||||
return self.shared_list_grid(trans, status=status, message=message, **kwargs)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -62,7 +62,6 @@ class PageListGrid(grids.Grid):
|
||||
class PageAllPublishedGrid(grids.Grid):
|
||||
# Grid definition
|
||||
use_panels = True
|
||||
use_async = True
|
||||
title = "Published Pages"
|
||||
model_class = model.Page
|
||||
default_sort_key = "update_time"
|
||||
@@ -104,7 +103,6 @@ class ItemSelectionGrid(grids.Grid):
|
||||
show_item_checkboxes = True
|
||||
default_filter = {"deleted": "False", "sharing": "All"}
|
||||
default_sort_key = "-update_time"
|
||||
use_async = True
|
||||
use_paging = True
|
||||
num_rows_per_page = 10
|
||||
|
||||
@@ -322,7 +320,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
session.flush()
|
||||
|
||||
# Build grid dictionary.
|
||||
kwargs['dict_format'] = True
|
||||
grid = self._page_list(trans, *args, **kwargs)
|
||||
grid['shared_by_others'] = self._get_shared(trans)
|
||||
return grid
|
||||
@@ -330,7 +327,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.expose
|
||||
@web.json
|
||||
def list_published(self, trans, *args, **kwargs):
|
||||
kwargs['dict_format'] = True
|
||||
grid = self._all_published_list(trans, *args, **kwargs)
|
||||
grid['shared_by_others'] = self._get_shared(trans)
|
||||
return grid
|
||||
@@ -700,7 +696,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.require_login("select a history from saved histories")
|
||||
def list_histories_for_selection(self, trans, **kwargs):
|
||||
""" Returns HTML that enables a user to select one or more histories. """
|
||||
kwargs['dict_format'] = True
|
||||
return self._history_selection_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -708,7 +703,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.require_login("select a workflow from saved workflows")
|
||||
def list_workflows_for_selection(self, trans, **kwargs):
|
||||
""" Returns HTML that enables a user to select one or more workflows. """
|
||||
kwargs['dict_format'] = True
|
||||
return self._workflow_selection_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -716,7 +710,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.require_login("select a visualization from saved visualizations")
|
||||
def list_visualizations_for_selection(self, trans, **kwargs):
|
||||
""" Returns HTML that enables a user to select one or more visualizations. """
|
||||
kwargs['dict_format'] = True
|
||||
return self._visualization_selection_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -724,7 +717,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.require_login("select a page from saved pages")
|
||||
def list_pages_for_selection(self, trans, **kwargs):
|
||||
""" Returns HTML that enables a user to select one or more pages. """
|
||||
kwargs['dict_format'] = True
|
||||
return self._page_selection_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -732,7 +724,6 @@ class PageController(BaseUIController, SharableMixin,
|
||||
@web.require_login("select a dataset from saved datasets")
|
||||
def list_datasets_for_selection(self, trans, **kwargs):
|
||||
""" Returns HTML that enables a user to select one or more datasets. """
|
||||
kwargs['dict_format'] = True
|
||||
return self._datasets_selection_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -57,7 +57,7 @@ class RootController(controller.JSAppLauncher, UsesAnnotations):
|
||||
'toolbox' : app.toolbox.to_dict(trans, in_panel=False),
|
||||
'toolbox_in_panel' : app.toolbox.to_dict(trans),
|
||||
'message_box_visible' : app.config.message_box_visible,
|
||||
'show_inactivity_warning' : app.config.user_activation_on and trans.user and not trans.user.active,
|
||||
'show_inactivity_warning' : app.config.user_activation_on and trans.user and not trans.user.active
|
||||
}
|
||||
|
||||
# TODO: move to user
|
||||
|
||||
@@ -62,16 +62,17 @@ can also copy and paste it into your browser.
|
||||
|
||||
|
||||
class UserOpenIDGrid(grids.Grid):
|
||||
use_panels = False
|
||||
title = "OpenIDs linked to your account"
|
||||
model_class = model.UserOpenID
|
||||
template = '/user/openid_manage.mako'
|
||||
default_filter = {"openid": "All"}
|
||||
default_sort_key = "-create_time"
|
||||
columns = [
|
||||
grids.TextColumn("OpenID URL", key="openid", link=(lambda x: dict(action='openid_auth', login_button="Login", openid_url=x.openid if not x.provider else '', openid_provider=x.provider, auto_associate=True))),
|
||||
grids.GridColumn("Created", key="create_time", format=time_ago),
|
||||
]
|
||||
global_actions = [
|
||||
grids.GridAction("Add new account", url_args=dict(action="create_openid"), target="center")
|
||||
]
|
||||
operations = [
|
||||
grids.GridOperation("Delete", async_compatible=True),
|
||||
]
|
||||
@@ -138,8 +139,10 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
return trans.show_error_message('OpenID authentication is not enabled in this instance of Galaxy')
|
||||
auto_associate = util.string_as_bool(kwd.get('auto_associate', False))
|
||||
action = 'login'
|
||||
controller = 'user'
|
||||
if trans.user:
|
||||
action = 'openid_manage'
|
||||
action = 'openids'
|
||||
controller = 'list'
|
||||
if trans.app.config.support_url is not None:
|
||||
contact = '<a href="%s">support</a>' % trans.app.config.support_url
|
||||
else:
|
||||
@@ -153,7 +156,7 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
openid_provider = kwd.get('openid_provider', None)
|
||||
if info.status == trans.app.openid_manager.FAILURE and display_identifier:
|
||||
message = "Login via OpenID failed. The technical reason for this follows, please include this message in your email if you need to %s to resolve this problem: %s" % (contact, info.message)
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
return trans.response.send_redirect(url_for(controller=controller,
|
||||
action=action,
|
||||
use_panels=True,
|
||||
redirect=redirect,
|
||||
@@ -208,8 +211,8 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
message = '%s<br>Click <a href="%s"><strong>here</strong></a> to return to the page you were previously viewing.' % (message, escape(self.__get_redirect_url(redirect)))
|
||||
if redirect and status != "error":
|
||||
return trans.response.send_redirect(self.__get_redirect_url(redirect))
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
return trans.response.send_redirect(url_for(controller='openids',
|
||||
action='list',
|
||||
use_panels=True,
|
||||
redirect=redirect,
|
||||
message=message,
|
||||
@@ -300,18 +303,14 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
for openid in openid_objs:
|
||||
message = '%s<li><a href="%s" target="_blank">%s</a></li>' % (message, url_for(controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True), openid.name)
|
||||
message = "%s</ul>" % (message)
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
use_panels=use_panels,
|
||||
redirect=redirect,
|
||||
return trans.response.send_redirect(url_for(controller='openids',
|
||||
action='list',
|
||||
message=message,
|
||||
status='info'))
|
||||
if redirect:
|
||||
return trans.response.send_redirect(redirect)
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
use_panels=use_panels,
|
||||
redirect=redirect,
|
||||
return trans.response.send_redirect(url_for(controller='openids',
|
||||
action='list',
|
||||
message=message,
|
||||
status='info'))
|
||||
if kwd.get('create_user_button', False):
|
||||
@@ -352,18 +351,14 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
for openid in openid_objs:
|
||||
message = '%s<li><a href="%s" target="_blank">%s</a></li>' % (message, url_for(controller='user', action='openid_auth', openid_provider=openid.id, redirect=redirect, auto_associate=True), openid.name)
|
||||
message = "%s</ul>" % (message)
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
use_panels=True,
|
||||
redirect=redirect,
|
||||
return trans.response.send_redirect(url_for(controller='openids',
|
||||
action='list',
|
||||
message=message,
|
||||
status='info'))
|
||||
if redirect:
|
||||
return trans.response.send_redirect(redirect)
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
use_panels=use_panels,
|
||||
redirect=redirect,
|
||||
return trans.response.send_redirect(url_for(controller='openids',
|
||||
action='list',
|
||||
message=message,
|
||||
status='info'))
|
||||
else:
|
||||
@@ -386,63 +381,53 @@ class User(BaseUIController, UsesFormDefinitionsMixin, CreatesUsersMixin, Create
|
||||
openids=openids)
|
||||
|
||||
@web.expose
|
||||
@web.require_login('manage OpenIDs')
|
||||
def openid_disassociate(self, trans, **kwd):
|
||||
'''Disassociates a user with an OpenID'''
|
||||
if not trans.app.config.enable_openid:
|
||||
return trans.show_error_message('OpenID authentication is not enabled in this instance of Galaxy')
|
||||
params = util.Params(kwd)
|
||||
ids = params.get('id', None)
|
||||
message = params.get('message', None)
|
||||
status = params.get('status', None)
|
||||
use_panels = params.get('use_panels', False)
|
||||
user_openids = []
|
||||
if not ids:
|
||||
message = 'You must select at least one OpenID to disassociate from your Galaxy account.'
|
||||
status = 'error'
|
||||
else:
|
||||
ids = util.listify(params.id)
|
||||
for id in ids:
|
||||
id = trans.security.decode_id(id)
|
||||
user_openid = trans.sa_session.query(trans.app.model.UserOpenID).get(int(id))
|
||||
if not user_openid or (trans.user.id != user_openid.user_id):
|
||||
message = 'The selected OpenID(s) are not associated with your Galaxy account.'
|
||||
status = 'error'
|
||||
user_openids = []
|
||||
break
|
||||
user_openids.append(user_openid)
|
||||
if user_openids:
|
||||
deleted_urls = []
|
||||
for user_openid in user_openids:
|
||||
trans.sa_session.delete(user_openid)
|
||||
deleted_urls.append(user_openid.openid)
|
||||
trans.sa_session.flush()
|
||||
for deleted_url in deleted_urls:
|
||||
trans.log_event("User disassociated OpenID: %s" % deleted_url)
|
||||
message = '%s OpenIDs were disassociated from your Galaxy account.' % len(ids)
|
||||
status = 'done'
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_manage',
|
||||
use_panels=use_panels,
|
||||
message=message,
|
||||
status=status))
|
||||
@web.require_login('create OpenIDs')
|
||||
def create_openid(self, trans, **kwd):
|
||||
return trans.fill_template('/user/openid_manage.mako',
|
||||
openid_providers=trans.app.openid_providers,
|
||||
redirect=kwd.get('redirect', url_for(controller='openids', action='list')).strip())
|
||||
|
||||
@web.expose
|
||||
@web.expose_api
|
||||
@web.require_login('manage OpenIDs')
|
||||
def openid_manage(self, trans, **kwd):
|
||||
'''Manage OpenIDs for user'''
|
||||
def openids_list(self, trans, **kwd):
|
||||
'''List of availabel OpenIDs for user'''
|
||||
message = kwd.get('message', '')
|
||||
status = kwd.get('status', '')
|
||||
if not trans.app.config.enable_openid:
|
||||
return trans.show_error_message('OpenID authentication is not enabled in this instance of Galaxy')
|
||||
use_panels = kwd.get('use_panels', False)
|
||||
message = 'OpenID authentication is not enabled in this instance of Galaxy.'
|
||||
status = 'error'
|
||||
if 'operation' in kwd:
|
||||
operation = kwd['operation'].lower()
|
||||
if operation == "delete":
|
||||
return trans.response.send_redirect(url_for(controller='user',
|
||||
action='openid_disassociate',
|
||||
use_panels=use_panels,
|
||||
id=kwd['id']))
|
||||
kwd['redirect'] = kwd.get('redirect', url_for(controller='user', action='openid_manage', use_panels=True)).strip()
|
||||
kwd['openid_providers'] = trans.app.openid_providers
|
||||
ids = util.listify(kwd.get('id'))
|
||||
if operation == 'delete':
|
||||
if not ids:
|
||||
message = 'You must select at least one OpenID to disassociate from your Galaxy account.'
|
||||
status = 'error'
|
||||
else:
|
||||
user_openids = []
|
||||
for id in ids:
|
||||
id = trans.security.decode_id(id)
|
||||
user_openid = trans.sa_session.query(trans.app.model.UserOpenID).get(int(id))
|
||||
if not user_openid or (trans.user.id != user_openid.user_id):
|
||||
message = 'The selected OpenID(s) are not associated with your Galaxy account.'
|
||||
status = 'error'
|
||||
user_openids = []
|
||||
break
|
||||
user_openids.append(user_openid)
|
||||
if user_openids:
|
||||
deleted_urls = []
|
||||
for user_openid in user_openids:
|
||||
trans.sa_session.delete(user_openid)
|
||||
deleted_urls.append(user_openid.openid)
|
||||
trans.sa_session.flush()
|
||||
for deleted_url in deleted_urls:
|
||||
trans.log_event('User disassociated OpenID: %s' % deleted_url)
|
||||
message = '%s OpenIDs were disassociated from your Galaxy account.' % len(ids)
|
||||
status = 'done'
|
||||
if message and status:
|
||||
kwd['message'] = util.sanitize_text(message)
|
||||
kwd['status'] = status
|
||||
kwd['dict_format'] = True
|
||||
return self.user_openid_grid(trans, **kwd)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -118,7 +118,6 @@ class TracksterSelectionGrid(grids.Grid):
|
||||
title = "Insert into visualization"
|
||||
model_class = model.Visualization
|
||||
default_sort_key = "-update_time"
|
||||
use_async = True
|
||||
use_paging = False
|
||||
show_item_checkboxes = True
|
||||
columns = [
|
||||
@@ -193,7 +192,6 @@ class VisualizationListGrid(grids.Grid):
|
||||
class VisualizationAllPublishedGrid(grids.Grid):
|
||||
# Grid definition
|
||||
use_panels = True
|
||||
use_async = True
|
||||
title = "Published Visualizations"
|
||||
model_class = model.Visualization
|
||||
default_sort_key = "update_time"
|
||||
@@ -242,7 +240,6 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
@web.require_login("see all available libraries")
|
||||
def list_libraries(self, trans, **kwargs):
|
||||
"""List all libraries that can be used for selecting datasets."""
|
||||
kwargs['dict_format'] = True
|
||||
return self._libraries_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -251,7 +248,6 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
def list_history_datasets(self, trans, **kwargs):
|
||||
"""List a history's datasets that can be added to a visualization."""
|
||||
kwargs['show_item_checkboxes'] = 'True'
|
||||
kwargs['dict_format'] = True
|
||||
return self._history_datasets_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@@ -260,19 +256,16 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
def list_library_datasets(self, trans, **kwargs):
|
||||
"""List a library's datasets that can be added to a visualization."""
|
||||
kwargs['show_item_checkboxes'] = 'True'
|
||||
kwargs['dict_format'] = True
|
||||
return self._library_datasets_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@web.json
|
||||
def list_tracks(self, trans, **kwargs):
|
||||
kwargs['dict_format'] = True
|
||||
return self._tracks_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
@web.json
|
||||
def list_published(self, trans, *args, **kwargs):
|
||||
kwargs['dict_format'] = True
|
||||
grid = self._published_list_grid(trans, **kwargs)
|
||||
grid['shared_by_others'] = self._get_shared(trans)
|
||||
return grid
|
||||
@@ -294,7 +287,6 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
self.copy(trans, **kwargs)
|
||||
session.flush()
|
||||
kwargs['embedded'] = True
|
||||
kwargs['dict_format'] = True
|
||||
if message and status:
|
||||
kwargs['message'] = sanitize_text(message)
|
||||
kwargs['status'] = status
|
||||
|
||||
@@ -102,7 +102,6 @@ class StoredWorkflowAllPublishedGrid(grids.Grid):
|
||||
model_class = model.StoredWorkflow
|
||||
default_sort_key = "update_time"
|
||||
default_filter = dict(public_url="All", username="All", tags="All")
|
||||
use_async = True
|
||||
columns = [
|
||||
grids.PublicURLColumn("Name", key="name", filterable="advanced", attach_popup=True),
|
||||
grids.OwnerAnnotationColumn("Annotation",
|
||||
@@ -202,7 +201,6 @@ class WorkflowController(BaseUIController, SharableMixin, UsesStoredWorkflowMixi
|
||||
@web.expose
|
||||
@web.json
|
||||
def list_published(self, trans, **kwargs):
|
||||
kwargs['dict_format'] = True
|
||||
return self.published_list_grid(trans, **kwargs)
|
||||
|
||||
@web.expose
|
||||
|
||||
@@ -17,8 +17,8 @@ from sqlalchemy import and_, not_, or_
|
||||
|
||||
from galaxy import model, util
|
||||
from galaxy.web.base.controller import BaseUIController, web
|
||||
from galaxy.web.framework.helpers import grids
|
||||
from galaxy.webapps.reports.controllers.query import ReportQueryBuilder
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -179,7 +179,6 @@ class SpecifiedDateListGrid(grids.Grid):
|
||||
use_async = False
|
||||
model_class = model.Job
|
||||
title = "Jobs"
|
||||
template = '/webapps/reports/grid.mako'
|
||||
default_sort_key = "id"
|
||||
columns = [
|
||||
JobIdColumn("Id",
|
||||
@@ -223,7 +222,6 @@ class SpecifiedDateListGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = {'specified_date': 'All'}
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
|
||||
@@ -18,12 +18,12 @@ from sqlalchemy import and_
|
||||
|
||||
from galaxy import model, util
|
||||
from galaxy.web.base.controller import BaseUIController, web
|
||||
from galaxy.web.framework.helpers import grids
|
||||
from galaxy.webapps.reports.controllers.jobs import (
|
||||
get_spark_time,
|
||||
sorter
|
||||
)
|
||||
from galaxy.webapps.reports.controllers.query import ReportQueryBuilder
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -81,7 +81,6 @@ class SpecifiedDateListGrid(grids.Grid):
|
||||
use_async = False
|
||||
model_class = model.StoredWorkflow
|
||||
title = "Workflows"
|
||||
template = '/webapps/reports/grid.mako'
|
||||
default_sort_key = "name"
|
||||
columns = [
|
||||
WorkflowNameColumn("Name",
|
||||
@@ -113,7 +112,6 @@ class SpecifiedDateListGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = {'specified_date': 'All'}
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = True
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
|
||||
@@ -0,0 +1,854 @@
|
||||
import logging
|
||||
import math
|
||||
from json import dumps, loads
|
||||
|
||||
from markupsafe import escape
|
||||
from six import string_types, text_type
|
||||
from sqlalchemy.sql.expression import and_, false, func, null, or_, true
|
||||
|
||||
from galaxy.model.item_attrs import RuntimeException, UsesAnnotations, UsesItemRatings
|
||||
from galaxy.util import sanitize_text, unicodify
|
||||
from galaxy.util.odict import odict
|
||||
from galaxy.web.framework import decorators, url_for
|
||||
from galaxy.web.framework.helpers import iff
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Grid(object):
|
||||
"""
|
||||
Specifies the content and format of a grid (data table).
|
||||
"""
|
||||
title = ""
|
||||
model_class = None
|
||||
show_item_checkboxes = False
|
||||
template = "legacy/grid_base.mako"
|
||||
async_template = "legacy/grid_base_async.mako"
|
||||
use_async = False
|
||||
use_hide_message = True
|
||||
global_actions = []
|
||||
columns = []
|
||||
operations = []
|
||||
standard_filters = []
|
||||
# Any columns that are filterable (either standard or advanced) should have a default value set in the default filter.
|
||||
default_filter = {}
|
||||
default_sort_key = None
|
||||
use_paging = False
|
||||
num_rows_per_page = 25
|
||||
num_page_links = 10
|
||||
# Set preference names.
|
||||
cur_filter_pref_name = ".filter"
|
||||
cur_sort_key_pref_name = ".sort_key"
|
||||
legend = None
|
||||
info_text = None
|
||||
|
||||
def __init__(self):
|
||||
# Determine if any multiple row operations are defined
|
||||
self.has_multiple_item_operations = False
|
||||
for operation in self.operations:
|
||||
if operation.allow_multiple:
|
||||
self.has_multiple_item_operations = True
|
||||
break
|
||||
|
||||
# If a column does not have a model class, set the column's model class
|
||||
# to be the grid's model class.
|
||||
for column in self.columns:
|
||||
if not column.model_class:
|
||||
column.model_class = self.model_class
|
||||
|
||||
def __call__(self, trans, **kwargs):
|
||||
# Get basics.
|
||||
# FIXME: pretty sure this is only here to pass along, can likely be eliminated
|
||||
status = kwargs.get('status', None)
|
||||
message = kwargs.get('message', None)
|
||||
# Build a base filter and sort key that is the combination of the saved state and defaults.
|
||||
# Saved state takes preference over defaults.
|
||||
base_filter = {}
|
||||
if self.default_filter:
|
||||
# default_filter is a dictionary that provides a default set of filters based on the grid's columns.
|
||||
base_filter = self.default_filter.copy()
|
||||
base_sort_key = self.default_sort_key
|
||||
# Build initial query
|
||||
query = self.build_initial_query(trans, **kwargs)
|
||||
query = self.apply_query_filter(trans, query, **kwargs)
|
||||
# Maintain sort state in generated urls
|
||||
extra_url_args = {}
|
||||
# Determine whether use_default_filter flag is set.
|
||||
use_default_filter_str = kwargs.get('use_default_filter')
|
||||
use_default_filter = False
|
||||
if use_default_filter_str:
|
||||
use_default_filter = (use_default_filter_str.lower() == 'true')
|
||||
# Process filtering arguments to (a) build a query that represents the filter and (b) build a
|
||||
# dictionary that denotes the current filter.
|
||||
cur_filter_dict = {}
|
||||
for column in self.columns:
|
||||
if column.key:
|
||||
# Get the filter criterion for the column. Precedence is (a) if using default filter, only look there; otherwise,
|
||||
# (b) look in kwargs; and (c) look in base filter.
|
||||
column_filter = None
|
||||
if use_default_filter:
|
||||
if self.default_filter:
|
||||
column_filter = self.default_filter.get(column.key)
|
||||
elif "f-" + column.model_class.__name__ + ".%s" % column.key in kwargs:
|
||||
# Queries that include table joins cannot guarantee unique column names. This problem is
|
||||
# handled by setting the column_filter value to <TableName>.<ColumnName>.
|
||||
column_filter = kwargs.get("f-" + column.model_class.__name__ + ".%s" % column.key)
|
||||
elif "f-" + column.key in kwargs:
|
||||
column_filter = kwargs.get("f-" + column.key)
|
||||
elif column.key in base_filter:
|
||||
column_filter = base_filter.get(column.key)
|
||||
|
||||
# Method (1) combines a mix of strings and lists of strings into a single string and (2) attempts to de-jsonify all strings.
|
||||
def loads_recurse(item):
|
||||
decoded_list = []
|
||||
if isinstance(item, string_types):
|
||||
try:
|
||||
# Not clear what we're decoding, so recurse to ensure that we catch everything.
|
||||
decoded_item = loads(item)
|
||||
if isinstance(decoded_item, list):
|
||||
decoded_list = loads_recurse(decoded_item)
|
||||
else:
|
||||
decoded_list = [text_type(decoded_item)]
|
||||
except ValueError:
|
||||
decoded_list = [text_type(item)]
|
||||
elif isinstance(item, list):
|
||||
for element in item:
|
||||
a_list = loads_recurse(element)
|
||||
decoded_list = decoded_list + a_list
|
||||
return decoded_list
|
||||
# If column filter found, apply it.
|
||||
if column_filter is not None:
|
||||
# TextColumns may have a mix of json and strings.
|
||||
if isinstance(column, TextColumn):
|
||||
column_filter = loads_recurse(column_filter)
|
||||
if len(column_filter) == 1:
|
||||
column_filter = column_filter[0]
|
||||
# Interpret ',' as a separator for multiple terms.
|
||||
if isinstance(column_filter, string_types) and column_filter.find(',') != -1:
|
||||
column_filter = column_filter.split(',')
|
||||
|
||||
# Check if filter is empty
|
||||
if isinstance(column_filter, list):
|
||||
# Remove empty strings from filter list
|
||||
column_filter = [x for x in column_filter if x != '']
|
||||
if len(column_filter) == 0:
|
||||
continue
|
||||
elif isinstance(column_filter, string_types):
|
||||
# If filter criterion is empty, do nothing.
|
||||
if column_filter == '':
|
||||
continue
|
||||
|
||||
# Update query.
|
||||
query = column.filter(trans, trans.user, query, column_filter)
|
||||
# Upate current filter dict.
|
||||
# Column filters are rendered in various places, sanitize them all here.
|
||||
cur_filter_dict[column.key] = sanitize_text(column_filter)
|
||||
# Carry filter along to newly generated urls; make sure filter is a string so
|
||||
# that we can encode to UTF-8 and thus handle user input to filters.
|
||||
if isinstance(column_filter, list):
|
||||
# Filter is a list; process each item.
|
||||
column_filter = [text_type(_).encode('utf-8') if not isinstance(_, string_types) else _ for _ in column_filter]
|
||||
extra_url_args["f-" + column.key] = dumps(column_filter)
|
||||
else:
|
||||
# Process singleton filter.
|
||||
if not isinstance(column_filter, string_types):
|
||||
column_filter = text_type(column_filter)
|
||||
extra_url_args["f-" + column.key] = column_filter.encode("utf-8")
|
||||
# Process sort arguments.
|
||||
sort_key = None
|
||||
if 'sort' in kwargs:
|
||||
sort_key = kwargs['sort']
|
||||
elif base_sort_key:
|
||||
sort_key = base_sort_key
|
||||
if sort_key:
|
||||
ascending = not(sort_key.startswith("-"))
|
||||
# Queries that include table joins cannot guarantee unique column names. This problem is
|
||||
# handled by setting the column_filter value to <TableName>.<ColumnName>.
|
||||
table_name = None
|
||||
if sort_key.find('.') > -1:
|
||||
a_list = sort_key.split('.')
|
||||
if ascending:
|
||||
table_name = a_list[0]
|
||||
else:
|
||||
table_name = a_list[0][1:]
|
||||
column_name = a_list[1]
|
||||
elif ascending:
|
||||
column_name = sort_key
|
||||
else:
|
||||
column_name = sort_key[1:]
|
||||
# Sort key is a column key.
|
||||
for column in self.columns:
|
||||
if column.key and column.key.find('.') > -1:
|
||||
column_key = column.key.split('.')[1]
|
||||
else:
|
||||
column_key = column.key
|
||||
if (table_name is None or table_name == column.model_class.__name__) and column_key == column_name:
|
||||
query = column.sort(trans, query, ascending, column_name=column_name)
|
||||
break
|
||||
extra_url_args['sort'] = sort_key
|
||||
# There might be a current row
|
||||
current_item = self.get_current_item(trans, **kwargs)
|
||||
# Process page number.
|
||||
if self.use_paging:
|
||||
if 'page' in kwargs:
|
||||
if kwargs['page'] == 'all':
|
||||
page_num = 0
|
||||
else:
|
||||
page_num = int(kwargs['page'])
|
||||
else:
|
||||
page_num = 1
|
||||
if page_num == 0:
|
||||
# Show all rows in page.
|
||||
total_num_rows = query.count()
|
||||
page_num = 1
|
||||
num_pages = 1
|
||||
else:
|
||||
# Show a limited number of rows. Before modifying query, get the total number of rows that query
|
||||
# returns so that the total number of pages can be computed.
|
||||
total_num_rows = query.count()
|
||||
query = query.limit(self.num_rows_per_page).offset((page_num - 1) * self.num_rows_per_page)
|
||||
num_pages = int(math.ceil(float(total_num_rows) / self.num_rows_per_page))
|
||||
else:
|
||||
# Defaults.
|
||||
page_num = 1
|
||||
num_pages = 1
|
||||
# There are some places in grid templates where it's useful for a grid
|
||||
# to have its current filter.
|
||||
self.cur_filter_dict = cur_filter_dict
|
||||
|
||||
# Log grid view.
|
||||
context = text_type(self.__class__.__name__)
|
||||
params = cur_filter_dict.copy()
|
||||
params['sort'] = sort_key
|
||||
params['async'] = ('async' in kwargs)
|
||||
|
||||
# TODO:??
|
||||
# commenting this out; when this fn calls session.add( action ) and session.flush the query from this fn
|
||||
# is effectively 'wiped' out. Nate believes it has something to do with our use of session( autocommit=True )
|
||||
# in mapping.py. If you change that to False, the log_action doesn't affect the query
|
||||
# Below, I'm rendering the template first (that uses query), then calling log_action, then returning the page
|
||||
# trans.log_action( trans.get_user(), text_type( "grid.view" ), context, params )
|
||||
|
||||
# Render grid.
|
||||
def url(*args, **kwargs):
|
||||
route_name = kwargs.pop('__route_name__', None)
|
||||
# Only include sort/filter arguments if not linking to another
|
||||
# page. This is a bit of a hack.
|
||||
if 'action' in kwargs:
|
||||
new_kwargs = dict()
|
||||
else:
|
||||
new_kwargs = dict(extra_url_args)
|
||||
# Extend new_kwargs with first argument if found
|
||||
if len(args) > 0:
|
||||
new_kwargs.update(args[0])
|
||||
new_kwargs.update(kwargs)
|
||||
# We need to encode item ids
|
||||
if 'id' in new_kwargs:
|
||||
id = new_kwargs['id']
|
||||
if isinstance(id, list):
|
||||
new_kwargs['id'] = [trans.security.encode_id(i) for i in id]
|
||||
else:
|
||||
new_kwargs['id'] = trans.security.encode_id(id)
|
||||
# The url_for invocation *must* include a controller and action.
|
||||
if 'controller' not in new_kwargs:
|
||||
new_kwargs['controller'] = trans.controller
|
||||
if 'action' not in new_kwargs:
|
||||
new_kwargs['action'] = trans.action
|
||||
if route_name:
|
||||
return url_for(route_name, **new_kwargs)
|
||||
return url_for(**new_kwargs)
|
||||
|
||||
self.use_panels = (kwargs.get('use_panels', False) in [True, 'True', 'true'])
|
||||
self.advanced_search = (kwargs.get('advanced_search', False) in [True, 'True', 'true'])
|
||||
async_request = ((self.use_async) and (kwargs.get('async', False) in [True, 'True', 'true']))
|
||||
# Currently, filling the template returns a str object; this requires decoding the string into a
|
||||
# unicode object within mako templates. What probably should be done is to return the template as
|
||||
# utf-8 unicode; however, this would require encoding the object as utf-8 before returning the grid
|
||||
# results via a controller method, which is require substantial changes. Hence, for now, return grid
|
||||
# as str.
|
||||
page = trans.fill_template(iff(async_request, self.async_template, self.template),
|
||||
grid=self,
|
||||
query=query,
|
||||
cur_page_num=page_num,
|
||||
num_pages=num_pages,
|
||||
num_page_links=self.num_page_links,
|
||||
default_filter_dict=self.default_filter,
|
||||
cur_filter_dict=cur_filter_dict,
|
||||
sort_key=sort_key,
|
||||
current_item=current_item,
|
||||
ids=kwargs.get('id', []),
|
||||
url=url,
|
||||
status=status,
|
||||
message=message,
|
||||
info_text=self.info_text,
|
||||
use_panels=self.use_panels,
|
||||
use_hide_message=self.use_hide_message,
|
||||
advanced_search=self.advanced_search,
|
||||
show_item_checkboxes=(self.show_item_checkboxes or
|
||||
kwargs.get('show_item_checkboxes', '') in ['True', 'true']),
|
||||
# Pass back kwargs so that grid template can set and use args without
|
||||
# grid explicitly having to pass them.
|
||||
kwargs=kwargs)
|
||||
trans.log_action(trans.get_user(), text_type("grid.view"), context, params)
|
||||
return page
|
||||
|
||||
def get_ids(self, **kwargs):
|
||||
id = []
|
||||
if 'id' in kwargs:
|
||||
id = kwargs['id']
|
||||
# Coerce ids to list
|
||||
if not isinstance(id, list):
|
||||
id = id.split(",")
|
||||
# Ensure ids are integers
|
||||
try:
|
||||
id = list(map(int, id))
|
||||
except Exception:
|
||||
decorators.error("Invalid id")
|
||||
return id
|
||||
|
||||
# ---- Override these ----------------------------------------------------
|
||||
def handle_operation(self, trans, operation, ids, **kwargs):
|
||||
pass
|
||||
|
||||
def get_current_item(self, trans, **kwargs):
|
||||
return None
|
||||
|
||||
def build_initial_query(self, trans, **kwargs):
|
||||
return trans.sa_session.query(self.model_class)
|
||||
|
||||
def apply_query_filter(self, trans, query, **kwargs):
|
||||
# Applies a database filter that holds for all items in the grid.
|
||||
# (gvk) Is this method necessary? Why not simply build the entire query,
|
||||
# including applying filters in the build_initial_query() method?
|
||||
return query
|
||||
|
||||
|
||||
class GridColumn(object):
|
||||
def __init__(self, label, key=None, model_class=None, method=None, format=None,
|
||||
link=None, attach_popup=False, visible=True, nowrap=False,
|
||||
# Valid values for filterable are ['standard', 'advanced', None]
|
||||
filterable=None, sortable=True, label_id_prefix=None, target=None):
|
||||
"""Create a grid column."""
|
||||
self.label = label
|
||||
self.key = key
|
||||
self.model_class = model_class
|
||||
self.method = method
|
||||
self.format = format
|
||||
self.link = link
|
||||
self.target = target
|
||||
self.nowrap = nowrap
|
||||
self.attach_popup = attach_popup
|
||||
self.visible = visible
|
||||
self.filterable = filterable
|
||||
# Column must have a key to be sortable.
|
||||
self.sortable = (self.key is not None and sortable)
|
||||
self.label_id_prefix = label_id_prefix or ''
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
if self.method:
|
||||
value = getattr(grid, self.method)(trans, item)
|
||||
elif self.key:
|
||||
value = getattr(item, self.key)
|
||||
else:
|
||||
value = None
|
||||
if self.format:
|
||||
value = self.format(value)
|
||||
return escape(unicodify(value))
|
||||
|
||||
def get_link(self, trans, grid, item):
|
||||
if self.link and self.link(item):
|
||||
return self.link(item)
|
||||
return None
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
""" Modify query to reflect the column filter. """
|
||||
if column_filter == "All":
|
||||
pass
|
||||
if column_filter == "True":
|
||||
query = query.filter_by(**{self.key: True})
|
||||
elif column_filter == "False":
|
||||
query = query.filter_by(**{self.key: False})
|
||||
return query
|
||||
|
||||
def get_accepted_filters(self):
|
||||
""" Returns a list of accepted filters for this column. """
|
||||
accepted_filters_vals = ["False", "True", "All"]
|
||||
accepted_filters = []
|
||||
for val in accepted_filters_vals:
|
||||
args = {self.key: val}
|
||||
accepted_filters.append(GridColumnFilter(val, args))
|
||||
return accepted_filters
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
"""Sort query using this column."""
|
||||
if column_name is None:
|
||||
column_name = self.key
|
||||
if ascending:
|
||||
query = query.order_by(self.model_class.table.c.get(column_name).asc())
|
||||
else:
|
||||
query = query.order_by(self.model_class.table.c.get(column_name).desc())
|
||||
return query
|
||||
|
||||
|
||||
class ReverseSortColumn(GridColumn):
|
||||
""" Column that reverses sorting; this is useful when the natural sort is descending. """
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
return GridColumn.sort(self, trans, query, (not ascending), column_name=column_name)
|
||||
|
||||
|
||||
class TextColumn(GridColumn):
|
||||
""" Generic column that employs freetext and, hence, supports freetext, case-independent filtering. """
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
""" Modify query to filter using free text, case independence. """
|
||||
if column_filter == "All":
|
||||
pass
|
||||
elif column_filter:
|
||||
query = query.filter(self.get_filter(trans, user, column_filter))
|
||||
return query
|
||||
|
||||
def get_filter(self, trans, user, column_filter):
|
||||
""" Returns a SQLAlchemy criterion derived from column_filter. """
|
||||
if isinstance(column_filter, string_types):
|
||||
return self.get_single_filter(user, column_filter)
|
||||
elif isinstance(column_filter, list):
|
||||
clause_list = []
|
||||
for filter in column_filter:
|
||||
clause_list.append(self.get_single_filter(user, filter))
|
||||
return and_(*clause_list)
|
||||
|
||||
def get_single_filter(self, user, a_filter):
|
||||
"""
|
||||
Returns a SQLAlchemy criterion derived for a single filter. Single filter
|
||||
is the most basic filter--usually a string--and cannot be a list.
|
||||
"""
|
||||
# Queries that include table joins cannot guarantee that table column names will be
|
||||
# unique, so check to see if a_filter is of type <TableName>.<ColumnName>.
|
||||
if self.key.find('.') > -1:
|
||||
a_key = self.key.split('.')[1]
|
||||
else:
|
||||
a_key = self.key
|
||||
model_class_key_field = getattr(self.model_class, a_key)
|
||||
return func.lower(model_class_key_field).like("%" + a_filter.lower() + "%")
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
"""Sort column using case-insensitive alphabetical sorting."""
|
||||
if column_name is None:
|
||||
column_name = self.key
|
||||
if ascending:
|
||||
query = query.order_by(func.lower(self.model_class.table.c.get(column_name)).asc())
|
||||
else:
|
||||
query = query.order_by(func.lower(self.model_class.table.c.get(column_name)).desc())
|
||||
return query
|
||||
|
||||
|
||||
class DateTimeColumn(TextColumn):
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
"""Sort query using this column."""
|
||||
return GridColumn.sort(self, trans, query, ascending, column_name=column_name)
|
||||
|
||||
|
||||
class BooleanColumn(TextColumn):
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
"""Sort query using this column."""
|
||||
return GridColumn.sort(self, trans, query, ascending, column_name=column_name)
|
||||
|
||||
def get_single_filter(self, user, a_filter):
|
||||
if self.key.find('.') > -1:
|
||||
a_key = self.key.split('.')[1]
|
||||
else:
|
||||
a_key = self.key
|
||||
model_class_key_field = getattr(self.model_class, a_key)
|
||||
return model_class_key_field == a_filter
|
||||
|
||||
|
||||
class IntegerColumn(TextColumn):
|
||||
"""
|
||||
Integer column that employs freetext, but checks that the text is an integer,
|
||||
so support filtering on integer values.
|
||||
|
||||
IMPORTANT NOTE: grids that use this column type should not include the column
|
||||
in the cols_to_filter list of MulticolFilterColumn ( i.e., searching on this
|
||||
column type should not be performed in the grid's standard search - it won't
|
||||
throw exceptions, but it also will not find what you're looking for ). Grids
|
||||
that search on this column should use 'filterable="advanced"' so that searching
|
||||
is only performed in the advanced search component, restricting the search to
|
||||
the specific column.
|
||||
|
||||
This is useful for searching on object ids or other integer columns. See the
|
||||
JobIdColumn column in the SpecifiedDateListGrid class in the jobs controller of
|
||||
the reports webapp for an example.
|
||||
"""
|
||||
|
||||
def get_single_filter(self, user, a_filter):
|
||||
model_class_key_field = getattr(self.model_class, self.key)
|
||||
assert int(a_filter), "The search entry must be an integer"
|
||||
return model_class_key_field == int(a_filter)
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
"""Sort query using this column."""
|
||||
return GridColumn.sort(self, trans, query, ascending, column_name=column_name)
|
||||
|
||||
|
||||
class CommunityRatingColumn(GridColumn, UsesItemRatings):
|
||||
""" Column that displays community ratings for an item. """
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
ave_item_rating, num_ratings = self.get_ave_item_rating_data(trans.sa_session, item, webapp_model=trans.model)
|
||||
return trans.fill_template("tool_shed_rating.mako",
|
||||
ave_item_rating=ave_item_rating,
|
||||
num_ratings=num_ratings,
|
||||
item_id=trans.security.encode_id(item.id))
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
def get_foreign_key(source_class, target_class):
|
||||
""" Returns foreign key in source class that references target class. """
|
||||
target_fk = None
|
||||
for fk in source_class.table.foreign_keys:
|
||||
if fk.references(target_class.table):
|
||||
target_fk = fk
|
||||
break
|
||||
if not target_fk:
|
||||
raise RuntimeException("No foreign key found between objects: %s, %s" % source_class.table, target_class.table)
|
||||
return target_fk
|
||||
# Get the columns that connect item's table and item's rating association table.
|
||||
item_rating_assoc_class = getattr(trans.model, '%sRatingAssociation' % self.model_class.__name__)
|
||||
foreign_key = get_foreign_key(item_rating_assoc_class, self.model_class)
|
||||
fk_col = foreign_key.parent
|
||||
referent_col = foreign_key.get_referent(self.model_class.table)
|
||||
# Do sorting using a subquery.
|
||||
# Subquery to get average rating for each item.
|
||||
ave_rating_subquery = trans.sa_session.query(fk_col,
|
||||
func.avg(item_rating_assoc_class.table.c.rating).label('avg_rating')) \
|
||||
.group_by(fk_col).subquery()
|
||||
# Integrate subquery into main query.
|
||||
query = query.outerjoin((ave_rating_subquery, referent_col == ave_rating_subquery.columns[fk_col.name]))
|
||||
# Sort using subquery results; use coalesce to avoid null values.
|
||||
if not ascending: # TODO: for now, reverse sorting b/c first sort is ascending, and that should be the natural sort.
|
||||
query = query.order_by(func.coalesce(ave_rating_subquery.c.avg_rating, 0).asc())
|
||||
else:
|
||||
query = query.order_by(func.coalesce(ave_rating_subquery.c.avg_rating, 0).desc())
|
||||
return query
|
||||
|
||||
|
||||
class OwnerAnnotationColumn(TextColumn, UsesAnnotations):
|
||||
""" Column that displays and filters item owner's annotations. """
|
||||
|
||||
def __init__(self, col_name, key, model_class=None, model_annotation_association_class=None, filterable=None):
|
||||
GridColumn.__init__(self, col_name, key=key, model_class=model_class, filterable=filterable)
|
||||
self.sortable = False
|
||||
self.model_annotation_association_class = model_annotation_association_class
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
""" Returns first 150 characters of annotation. """
|
||||
annotation = self.get_item_annotation_str(trans.sa_session, item.user, item)
|
||||
if annotation:
|
||||
ann_snippet = annotation[:155]
|
||||
if len(annotation) > 155:
|
||||
ann_snippet = ann_snippet[:ann_snippet.rfind(' ')]
|
||||
ann_snippet += "..."
|
||||
else:
|
||||
ann_snippet = ""
|
||||
return escape(ann_snippet)
|
||||
|
||||
def get_single_filter(self, user, a_filter):
|
||||
""" Filter by annotation and annotation owner. """
|
||||
return self.model_class.annotations.any(
|
||||
and_(func.lower(self.model_annotation_association_class.annotation).like("%" + a_filter.lower() + "%"),
|
||||
# TODO: not sure why, to filter by owner's annotations, we have to do this rather than
|
||||
# 'self.model_class.user==self.model_annotation_association_class.user'
|
||||
self.model_annotation_association_class.table.c.user_id == self.model_class.table.c.user_id))
|
||||
|
||||
|
||||
class CommunityTagsColumn(TextColumn):
|
||||
""" Column that supports community tags. """
|
||||
|
||||
def __init__(self, col_name, key, model_class=None, model_tag_association_class=None, filterable=None, grid_name=None):
|
||||
GridColumn.__init__(self, col_name, key=key, model_class=model_class, nowrap=True, filterable=filterable, sortable=False)
|
||||
self.model_tag_association_class = model_tag_association_class
|
||||
# Column-specific attributes.
|
||||
self.grid_name = grid_name
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
return trans.fill_template("/tagging_common.mako", tag_type="community", trans=trans, user=trans.get_user(), tagged_item=item, elt_context=self.grid_name,
|
||||
in_form=True, input_size="20", tag_click_fn="add_tag_to_grid_filter", use_toggle_link=True)
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
|
||||
if column_filter == "All":
|
||||
pass
|
||||
elif column_filter:
|
||||
query = query.filter(self.get_filter(trans, user, column_filter))
|
||||
return query
|
||||
|
||||
def get_filter(self, trans, user, column_filter):
|
||||
# Parse filter to extract multiple tags.
|
||||
if isinstance(column_filter, list):
|
||||
# Collapse list of tags into a single string; this is redundant but effective. TODO: fix this by iterating over tags.
|
||||
column_filter = ",".join(column_filter)
|
||||
raw_tags = trans.app.tag_handler.parse_tags(column_filter.encode("utf-8"))
|
||||
clause_list = []
|
||||
for name, value in raw_tags:
|
||||
if name:
|
||||
# Filter by all tags.
|
||||
clause_list.append(self.model_class.tags.any(func.lower(self.model_tag_association_class.user_tname).like("%" + name.lower() + "%")))
|
||||
if value:
|
||||
# Filter by all values.
|
||||
clause_list.append(self.model_class.tags.any(func.lower(self.model_tag_association_class.user_value).like("%" + value.lower() + "%")))
|
||||
return and_(*clause_list)
|
||||
|
||||
|
||||
class IndividualTagsColumn(CommunityTagsColumn):
|
||||
""" Column that supports individual tags. """
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
return trans.fill_template("/tagging_common.mako",
|
||||
tag_type="individual",
|
||||
user=trans.user,
|
||||
tagged_item=item,
|
||||
elt_context=self.grid_name,
|
||||
in_form=True,
|
||||
input_size="20",
|
||||
tag_click_fn="add_tag_to_grid_filter",
|
||||
use_toggle_link=True)
|
||||
|
||||
def get_filter(self, trans, user, column_filter):
|
||||
# Parse filter to extract multiple tags.
|
||||
if isinstance(column_filter, list):
|
||||
# Collapse list of tags into a single string; this is redundant but effective. TODO: fix this by iterating over tags.
|
||||
column_filter = ",".join(column_filter)
|
||||
raw_tags = trans.app.tag_handler.parse_tags(column_filter.encode("utf-8"))
|
||||
clause_list = []
|
||||
for name, value in raw_tags:
|
||||
if name:
|
||||
# Filter by individual's tag names.
|
||||
clause_list.append(self.model_class.tags.any(and_(func.lower(self.model_tag_association_class.user_tname).like("%" + name.lower() + "%"), self.model_tag_association_class.user == user)))
|
||||
if value:
|
||||
# Filter by individual's tag values.
|
||||
clause_list.append(self.model_class.tags.any(and_(func.lower(self.model_tag_association_class.user_value).like("%" + value.lower() + "%"), self.model_tag_association_class.user == user)))
|
||||
return and_(*clause_list)
|
||||
|
||||
|
||||
class MulticolFilterColumn(TextColumn):
|
||||
""" Column that performs multicolumn filtering. """
|
||||
|
||||
def __init__(self, col_name, cols_to_filter, key, visible, filterable="default"):
|
||||
GridColumn.__init__(self, col_name, key=key, visible=visible, filterable=filterable)
|
||||
self.cols_to_filter = cols_to_filter
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
""" Modify query to filter model_class by tag. Multiple filters are ANDed. """
|
||||
if column_filter == "All":
|
||||
return query
|
||||
if isinstance(column_filter, list):
|
||||
clause_list = []
|
||||
for filter in column_filter:
|
||||
part_clause_list = []
|
||||
for column in self.cols_to_filter:
|
||||
part_clause_list.append(column.get_filter(trans, user, filter))
|
||||
clause_list.append(or_(*part_clause_list))
|
||||
complete_filter = and_(*clause_list)
|
||||
else:
|
||||
clause_list = []
|
||||
for column in self.cols_to_filter:
|
||||
clause_list.append(column.get_filter(trans, user, column_filter))
|
||||
complete_filter = or_(*clause_list)
|
||||
return query.filter(complete_filter)
|
||||
|
||||
|
||||
class OwnerColumn(TextColumn):
|
||||
""" Column that lists item's owner. """
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
return item.user.username
|
||||
|
||||
def sort(self, trans, query, ascending, column_name=None):
|
||||
""" Sort column using case-insensitive alphabetical sorting on item's username. """
|
||||
if ascending:
|
||||
query = query.order_by(func.lower(self.model_class.username).asc())
|
||||
else:
|
||||
query = query.order_by(func.lower(self.model_class.username).desc())
|
||||
return query
|
||||
|
||||
|
||||
class PublicURLColumn(TextColumn):
|
||||
""" Column displays item's public URL based on username and slug. """
|
||||
|
||||
def get_link(self, trans, grid, item):
|
||||
if item.user.username and item.slug:
|
||||
return dict(action='display_by_username_and_slug', username=item.user.username, slug=item.slug)
|
||||
elif not item.user.username:
|
||||
# TODO: provide link to set username.
|
||||
return None
|
||||
elif not item.user.slug:
|
||||
# TODO: provide link to set slug.
|
||||
return None
|
||||
|
||||
|
||||
class DeletedColumn(GridColumn):
|
||||
""" Column that tracks and filters for items with deleted attribute. """
|
||||
|
||||
def get_accepted_filters(self):
|
||||
""" Returns a list of accepted filters for this column. """
|
||||
accepted_filter_labels_and_vals = {"active" : "False", "deleted" : "True", "all": "All"}
|
||||
accepted_filters = []
|
||||
for label, val in accepted_filter_labels_and_vals.items():
|
||||
args = {self.key: val}
|
||||
accepted_filters.append(GridColumnFilter(label, args))
|
||||
return accepted_filters
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
"""Modify query to filter self.model_class by state."""
|
||||
if column_filter == "All":
|
||||
pass
|
||||
elif column_filter in ["True", "False"]:
|
||||
query = query.filter(self.model_class.deleted == (column_filter == "True"))
|
||||
return query
|
||||
|
||||
|
||||
class StateColumn(GridColumn):
|
||||
"""
|
||||
Column that tracks and filters for items with state attribute.
|
||||
|
||||
IMPORTANT NOTE: self.model_class must have a states Bunch or dict if
|
||||
this column type is used in the grid.
|
||||
"""
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
return item.state
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
"""Modify query to filter self.model_class by state."""
|
||||
if column_filter == "All":
|
||||
pass
|
||||
elif column_filter in [v for k, v in self.model_class.states.items()]:
|
||||
query = query.filter(self.model_class.state == column_filter)
|
||||
return query
|
||||
|
||||
def get_accepted_filters(self):
|
||||
"""Returns a list of accepted filters for this column."""
|
||||
all = GridColumnFilter('all', {self.key : 'All'})
|
||||
accepted_filters = [all]
|
||||
for k, v in self.model_class.states.items():
|
||||
args = {self.key: v}
|
||||
accepted_filters.append(GridColumnFilter(v, args))
|
||||
return accepted_filters
|
||||
|
||||
|
||||
class SharingStatusColumn(GridColumn):
|
||||
""" Grid column to indicate sharing status. """
|
||||
|
||||
def get_value(self, trans, grid, item):
|
||||
# Delete items cannot be shared.
|
||||
if item.deleted:
|
||||
return ""
|
||||
# Build a list of sharing for this item.
|
||||
sharing_statuses = []
|
||||
if item.users_shared_with:
|
||||
sharing_statuses.append("Shared")
|
||||
if item.importable:
|
||||
sharing_statuses.append("Accessible")
|
||||
if item.published:
|
||||
sharing_statuses.append("Published")
|
||||
return ", ".join(sharing_statuses)
|
||||
|
||||
def get_link(self, trans, grid, item):
|
||||
if not item.deleted and (item.users_shared_with or item.importable or item.published):
|
||||
return dict(operation="share or publish", id=item.id)
|
||||
return None
|
||||
|
||||
def filter(self, trans, user, query, column_filter):
|
||||
""" Modify query to filter histories by sharing status. """
|
||||
if column_filter == "All":
|
||||
pass
|
||||
elif column_filter:
|
||||
if column_filter == "private":
|
||||
query = query.filter(self.model_class.users_shared_with == null())
|
||||
query = query.filter(self.model_class.importable == false())
|
||||
elif column_filter == "shared":
|
||||
query = query.filter(self.model_class.users_shared_with != null())
|
||||
elif column_filter == "accessible":
|
||||
query = query.filter(self.model_class.importable == true())
|
||||
elif column_filter == "published":
|
||||
query = query.filter(self.model_class.published == true())
|
||||
return query
|
||||
|
||||
def get_accepted_filters(self):
|
||||
""" Returns a list of accepted filters for this column. """
|
||||
accepted_filter_labels_and_vals = odict()
|
||||
accepted_filter_labels_and_vals["private"] = "private"
|
||||
accepted_filter_labels_and_vals["shared"] = "shared"
|
||||
accepted_filter_labels_and_vals["accessible"] = "accessible"
|
||||
accepted_filter_labels_and_vals["published"] = "published"
|
||||
accepted_filter_labels_and_vals["all"] = "All"
|
||||
accepted_filters = []
|
||||
for label, val in accepted_filter_labels_and_vals.items():
|
||||
args = {self.key: val}
|
||||
accepted_filters.append(GridColumnFilter(label, args))
|
||||
return accepted_filters
|
||||
|
||||
|
||||
class GridOperation(object):
|
||||
def __init__(self, label, key=None, condition=None, allow_multiple=True, allow_popup=True,
|
||||
target=None, url_args=None, async_compatible=False, confirm=None,
|
||||
global_operation=None):
|
||||
self.label = label
|
||||
self.key = key
|
||||
self.allow_multiple = allow_multiple
|
||||
self.allow_popup = allow_popup
|
||||
self.condition = condition
|
||||
self.target = target
|
||||
self.url_args = url_args
|
||||
self.async_compatible = async_compatible
|
||||
# if 'confirm' is set, then ask before completing the operation
|
||||
self.confirm = confirm
|
||||
# specify a general operation that acts on the full grid
|
||||
# this should be a function returning a dictionary with parameters
|
||||
# to pass to the URL, similar to GridColumn links:
|
||||
# global_operation=(lambda: dict(operation="download")
|
||||
self.global_operation = global_operation
|
||||
|
||||
def get_url_args(self, item):
|
||||
if self.url_args:
|
||||
if hasattr(self.url_args, '__call__'):
|
||||
url_args = self.url_args(item)
|
||||
else:
|
||||
url_args = dict(self.url_args)
|
||||
url_args['id'] = item.id
|
||||
return url_args
|
||||
else:
|
||||
return dict(operation=self.label, id=item.id)
|
||||
|
||||
def allowed(self, item):
|
||||
if self.condition:
|
||||
return bool(self.condition(item))
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
class DisplayByUsernameAndSlugGridOperation(GridOperation):
|
||||
""" Operation to display an item by username and slug. """
|
||||
|
||||
def get_url_args(self, item):
|
||||
return {'action' : 'display_by_username_and_slug', 'username' : item.user.username, 'slug' : item.slug}
|
||||
|
||||
|
||||
class GridAction(object):
|
||||
def __init__(self, label=None, url_args=None, target=None):
|
||||
self.label = label
|
||||
self.url_args = url_args
|
||||
self.target = target
|
||||
|
||||
|
||||
class GridColumnFilter(object):
|
||||
def __init__(self, label, args=None):
|
||||
self.label = label
|
||||
self.args = args
|
||||
|
||||
def get_url_args(self):
|
||||
rval = {}
|
||||
for k, v in self.args.items():
|
||||
rval["f-" + k] = v
|
||||
return rval
|
||||
@@ -21,7 +21,7 @@ from galaxy import (
|
||||
from galaxy.tools.repositories import ValidationContext
|
||||
from galaxy.web.base.controller import BaseUIController
|
||||
from galaxy.web.form_builder import CheckboxField, SelectField
|
||||
from galaxy.web.framework.helpers import grids
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
from galaxy.webapps.tool_shed.util import ratings_util
|
||||
from tool_shed.capsule import capsule_manager
|
||||
from tool_shed.dependencies.repository import relation_builder
|
||||
|
||||
@@ -215,7 +215,6 @@ class InstalledRepositoryGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = dict(deleted="False")
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
|
||||
@@ -3,7 +3,8 @@ import logging
|
||||
from markupsafe import escape
|
||||
from sqlalchemy import and_
|
||||
|
||||
from galaxy.web.framework.helpers import grids, time_ago
|
||||
from galaxy.web.framework.helpers import time_ago
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
from galaxy.webapps.tool_shed import model
|
||||
from tool_shed.grids.repository_grids import CategoryGrid, RepositoryGrid
|
||||
from tool_shed.util import hg_util
|
||||
|
||||
@@ -7,7 +7,7 @@ from sqlalchemy import and_, false, or_, true
|
||||
import tool_shed.grids.util as grids_util
|
||||
import tool_shed.repository_types.util as rt_util
|
||||
import tool_shed.util.shed_util_common as suc
|
||||
from galaxy.web.framework.helpers import grids
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
from galaxy.webapps.tool_shed import model
|
||||
from tool_shed.util import hg_util, metadata_util, repository_util
|
||||
|
||||
@@ -62,7 +62,6 @@ class CategoryGrid(grids.Grid):
|
||||
operations = []
|
||||
standard_filters = []
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
|
||||
@@ -236,7 +235,6 @@ class RepositoryGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = dict(deleted="False")
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
@@ -358,7 +356,6 @@ class MatchedRepositoryGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = {}
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
@@ -457,7 +454,6 @@ class RepositoriesByUserGrid(RepositoryGrid):
|
||||
standard_filters = []
|
||||
default_filter = dict(deleted="False")
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
@@ -978,7 +974,6 @@ class RepositoryMetadataGrid(grids.Grid):
|
||||
standard_filters = []
|
||||
default_filter = dict(malicious="False")
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
@@ -1298,7 +1293,6 @@ class ValidCategoryGrid(CategoryGrid):
|
||||
operations = []
|
||||
standard_filters = []
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import logging
|
||||
from markupsafe import escape
|
||||
from sqlalchemy import and_, false, null, or_, true
|
||||
|
||||
from galaxy.web.framework.helpers import grids
|
||||
from galaxy.webapps.reports.framework import grids
|
||||
from galaxy.webapps.tool_shed import model
|
||||
from tool_shed.grids.repository_grids import RepositoryGrid
|
||||
from tool_shed.util import hg_util, metadata_util
|
||||
@@ -45,7 +45,6 @@ class ComponentGrid(grids.Grid):
|
||||
operations = []
|
||||
standard_filters = []
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
|
||||
@@ -349,7 +348,6 @@ class RepositoryReviewsByUserGrid(grids.Grid):
|
||||
]
|
||||
standard_filters = []
|
||||
num_rows_per_page = 50
|
||||
preserve_state = False
|
||||
use_paging = False
|
||||
|
||||
def build_initial_query(self, trans, **kwd):
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
define("legacy/grid/grid-model",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=Backbone.Model.extend({defaults:{url_base:"",async:!1,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:!1,advanced_search:!1,cur_page:1,num_pages:1,operation:void 0,item_ids:void 0},can_async_op:function(t){return-1!==_.indexOf(this.attributes.async_ops,t)},add_filter:function(t,e,i){if(i){var s,r=this.attributes.filters[t];if(null===r||void 0===r)s=e;else if("string"==typeof r)if("All"==r||r==e)s=e;else{var a=[];a[0]=r,a[1]=e,s=a}else-1===(s=r).indexOf(e)&&s.push(e);this.attributes.filters[t]=s}else this.attributes.filters[t]=e},remove_filter:function(t,e){var i=this.attributes.filters[t];if(null===i||void 0===i)return!1;if("string"==typeof i)this.attributes.filters[t]="";else{var s=_.indexOf(i,e);-1!==s&&(i[s]="")}},get_url_data:function(){var t={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes,advanced_search:this.attributes.advanced_search};this.attributes.operation&&(t.operation=this.attributes.operation),this.attributes.item_ids&&(t.id=this.attributes.item_ids);var e=this;return _.each(_.pairs(e.attributes.filters),function(e){t["f-"+e[0]]=e[1]}),t},get_url:function(t){return this.get("url_base")+"?"+$.param(this.get_url_data())+"&"+$.param(t)}})});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define("mvc/grid/grid-model",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=Backbone.Model.extend({defaults:{url_base:"",async:!1,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:!1,advanced_search:!1,cur_page:1,num_pages:1,operation:void 0,item_ids:void 0},can_async_op:function(t){return-1!==_.indexOf(this.attributes.async_ops,t)},add_filter:function(t,e,i){if(i){var s,r=this.attributes.filters[t];if(null===r||void 0===r)s=e;else if("string"==typeof r)if("All"==r||r==e)s=e;else{var a=[];a[0]=r,a[1]=e,s=a}else-1===(s=r).indexOf(e)&&s.push(e);this.attributes.filters[t]=s}else this.attributes.filters[t]=e},remove_filter:function(t,e){var i=this.attributes.filters[t];if(null===i||void 0===i)return!1;if("string"==typeof i)this.attributes.filters[t]="";else{var s=_.indexOf(i,e);-1!==s&&(i[s]="")}},get_url_data:function(){var t={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes,advanced_search:this.attributes.advanced_search};this.attributes.operation&&(t.operation=this.attributes.operation),this.attributes.item_ids&&(t.id=this.attributes.item_ids);var e=this;return _.each(_.pairs(e.attributes.filters),function(e){t["f-"+e[0]]=e[1]}),t},get_url:function(t){return this.get("url_base")+"?"+$.param(this.get_url_data())+"&"+$.param(t)}})});
|
||||
define("mvc/grid/grid-model",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=Backbone.Model.extend({defaults:{url_base:"",async:!1,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:!1,advanced_search:!1,cur_page:1,num_pages:1,operation:void 0,item_ids:void 0},add_filter:function(t,e,i){if(i){var s,r=this.attributes.filters[t];if(null===r||void 0===r)s=e;else if("string"==typeof r)if("All"==r||r==e)s=e;else{var a=[];a[0]=r,a[1]=e,s=a}else-1===(s=r).indexOf(e)&&s.push(e);this.attributes.filters[t]=s}else this.attributes.filters[t]=e},remove_filter:function(t,e){var i=this.attributes.filters[t];if(null===i||void 0===i)return!1;if("string"==typeof i)this.attributes.filters[t]="";else{var s=_.indexOf(i,e);-1!==s&&(i[s]="")}},get_url_data:function(){var t={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes,advanced_search:this.attributes.advanced_search};this.attributes.operation&&(t.operation=this.attributes.operation),this.attributes.item_ids&&(t.id=this.attributes.item_ids);var e=this;return _.each(_.pairs(e.attributes.filters),function(e){t["f-"+e[0]]=e[1]}),t},get_url:function(t){return this.get("url_base")+"?"+$.param(this.get_url_data())+"&"+$.param(t)}})});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/grid/grid-shared",["exports","mvc/grid/grid-view"],function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var a=function(e){return e&&e.__esModule?e:{default:e}}(t),i=Backbone.View.extend({initialize:function(e){var t=this;this.setElement($("<div/>")),this.model=new Backbone.Model(e),this.item=this.model.get("item"),this.title=this.model.get("plural"),$.ajax({url:Galaxy.root+this.item+"/"+this.model.get("action_id")+"?"+$.param(Galaxy.params),success:function(e){e.dict_format=!0,t.model.set(e),t.render()}})},render:function(){var e=new a.default(this.model.attributes);this.$el.empty().append(e.$el),this.$el.append(this._templateShared())},_templateShared:function(){var e=this,t=$("<div><h2>"+this.model.get("plural")+" shared with you by others</h2></div>"),a=this.model.attributes;if(a.shared_by_others&&a.shared_by_others.length>0){var i=$('<table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><th>Title</th><th>Owner</th></tr></table>');_.each(a.shared_by_others,function(t,a){var r=Galaxy.root+e.item+"/display_by_username_and_slug?username="+t.username+"&slug="+t.slug;i.append('<tr><td><a href="'+r+'">'+_.escape(t.title)+"</a></td><td>"+_.escape(t.username)+"</td></tr>")}),t.append(i)}else t.append("No "+this.model.get("plural").toLowerCase()+" have been shared with you.");return t}});e.default={View:i}});
|
||||
define("mvc/grid/grid-shared",["exports","mvc/grid/grid-view"],function(e,t){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var a=function(e){return e&&e.__esModule?e:{default:e}}(t),i=Backbone.View.extend({initialize:function(e){var t=this;this.setElement($("<div/>")),this.model=new Backbone.Model(e),this.item=this.model.get("item"),this.title=this.model.get("plural"),$.ajax({url:Galaxy.root+this.item+"/"+this.model.get("action_id")+"?"+$.param(Galaxy.params),success:function(e){t.model.set(e),t.render()}})},render:function(){var e=new a.default(this.model.attributes);this.$el.empty().append(e.$el),this.$el.append(this._templateShared())},_templateShared:function(){var e=this,t=$("<div><h2>"+this.model.get("plural")+" shared with you by others</h2></div>"),a=this.model.attributes;if(a.shared_by_others&&a.shared_by_others.length>0){var i=$('<table class="colored" border="0" cellspacing="0" cellpadding="0" width="100%"><tr class="header"><th>Title</th><th>Owner</th></tr></table>');_.each(a.shared_by_others,function(t,a){var r=Galaxy.root+e.item+"/display_by_username_and_slug?username="+t.username+"&slug="+t.slug;i.append('<tr><td><a href="'+r+'">'+_.escape(t.title)+"</a></td><td>"+_.escape(t.username)+"</td></tr>")}),t.append(i)}else t.append("No "+this.model.get("plural").toLowerCase()+" have been shared with you.");return t}});e.default={View:i}});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define("mvc/history/history-list",["exports","utils/localization","utils/utils","mvc/grid/grid-view","mvc/history/history-model","mvc/history/copy-dialog"],function(t,e,i,o,n,a){"use strict";function l(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});var r=l(e),d=l(i),c=l(o),s=l(n),u=l(a),f=c.default.extend({_showCopyDialog:function(t){var e=new s.default.History({id:t});e.fetch().fail(function(){alert("History could not be fetched. Please contact an administrator")}).done(function(){(0,u.default)(e,{}).done(function(){window.parent&&window.parent.Galaxy&&window.parent.Galaxy.currHistoryPanel&&window.parent.Galaxy.currHistoryPanel.loadCurrentHistory(),window.location.reload(!0)})})},_add_operation:function(t,e,i){var o=this,n=i.operation_config[e.label];"Copy"==e.label&&(e.onclick=function(t){o._showCopyDialog(t)}),n.allowed&&e.allow_popup&&t.addItem({html:e.label,href:n.url_args,target:n.target,confirmation_text:e.confirm,func:function(t){t.preventDefault();var n=$(t.target).html();e.onclick?e.onclick(i.encode_id):o.execute(this.findItemByHtml(n))}})}}),y=Backbone.View.extend({title:(0,r.default)("Histories"),initialize:function(t){var e=this;this.setElement($("<div/>")),this.model=new Backbone.Model,d.default.get({url:Galaxy.root+"history/"+t.action_id+"?"+$.param(Galaxy.params),success:function(t){t.dict_format=!0,e.model.set(t),e.render()}})},render:function(){var t=new f(this.model.attributes);this.$el.empty().append(t.$el)}});t.default={View:y}});
|
||||
define("mvc/history/history-list",["exports","utils/localization","utils/utils","mvc/grid/grid-view","mvc/history/history-model","mvc/history/copy-dialog"],function(t,e,i,o,n,a){"use strict";function l(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});var r=l(e),d=l(i),c=l(o),s=l(n),u=l(a),f=c.default.extend({_showCopyDialog:function(t){var e=new s.default.History({id:t});e.fetch().fail(function(){alert("History could not be fetched. Please contact an administrator")}).done(function(){(0,u.default)(e,{}).done(function(){window.parent&&window.parent.Galaxy&&window.parent.Galaxy.currHistoryPanel&&window.parent.Galaxy.currHistoryPanel.loadCurrentHistory(),window.location.reload(!0)})})},_add_operation:function(t,e,i){var o=this,n=i.operation_config[e.label];"Copy"==e.label&&(e.onclick=function(t){o._showCopyDialog(t)}),n.allowed&&e.allow_popup&&t.addItem({html:e.label,href:n.url_args,target:n.target,confirmation_text:e.confirm,func:function(t){t.preventDefault();var n=$(t.target).html();e.onclick?e.onclick(i.encode_id):o.execute(this.findItemByHtml(n))}})}}),y=Backbone.View.extend({title:(0,r.default)("Histories"),initialize:function(t){var e=this;this.setElement($("<div/>")),this.model=new Backbone.Model,d.default.get({url:Galaxy.root+"history/"+t.action_id+"?"+$.param(Galaxy.params),success:function(t){e.model.set(t),e.render()}})},render:function(){var t=new f(this.model.attributes);this.$el.empty().append(t.$el)}});t.default={View:y}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/user/user-preferences",["exports","utils/localization","mvc/form/form-view","mvc/ui/ui-misc","utils/query-string-parsing"],function(e,t,i,s,a){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var n=o(t),r=(o(i),o(s)),u=o(a),l=Backbone.Model.extend({initialize:function(e){(e=e||{}).user_id=e.user_id||Galaxy.user.id,this.set({user_id:e.user_id,information:{title:(0,n.default)("Manage information"),description:"Edit your email, addresses and custom parameters or change your username.",url:"api/users/"+e.user_id+"/information/inputs",icon:"fa-user",redirect:"user"},password:{title:(0,n.default)("Change password"),description:(0,n.default)("Allows you to change your login credentials."),icon:"fa-unlock-alt",url:"api/users/"+e.user_id+"/password/inputs",submit_title:"Save password",redirect:"user"},communication:{title:(0,n.default)("Change communication settings"),description:(0,n.default)("Enable or disable the communication feature to chat with other users."),url:"api/users/"+e.user_id+"/communication/inputs",icon:"fa-comments-o",redirect:"user"},permissions:{title:(0,n.default)("Set dataset permissions for new histories"),description:"Grant others default access to newly created histories. Changes made here will only affect histories created after these settings have been stored.",url:"api/users/"+e.user_id+"/permissions/inputs",icon:"fa-users",submit_title:"Save permissions",redirect:"user"},api_key:{title:(0,n.default)("Manage API key"),description:(0,n.default)("Access your current API key or create a new one."),url:"api/users/"+e.user_id+"/api_key/inputs",icon:"fa-key",submit_title:"Create a new key",submit_icon:"fa-check"},toolbox_filters:{title:(0,n.default)("Manage Toolbox filters"),description:(0,n.default)("Customize your Toolbox by displaying or omitting sets of Tools."),url:"api/users/"+e.user_id+"/toolbox_filters/inputs",icon:"fa-filter",submit_title:"Save filters",redirect:"user"},openids:{title:(0,n.default)("Manage OpenIDs"),description:(0,n.default)("Associate OpenIDs with your account."),icon:"fa-openid",onclick:function(){window.location.href=Galaxy.root+"user/openid_manage?cntrller=user&use_panels=True"}},custom_builds:{title:(0,n.default)("Manage custom builds"),description:(0,n.default)("Add or remove custom builds using history datasets."),icon:"fa-cubes",onclick:function(){window.location.href=Galaxy.root+"custom_builds"}},logout:{title:(0,n.default)("Sign out"),description:(0,n.default)("Click here to sign out of all sessions."),icon:"fa-sign-out",onclick:function(){Galaxy.modal.show({title:(0,n.default)("Sign out"),body:"Do you want to continue and sign out of all active sessions?",buttons:{Cancel:function(){Galaxy.modal.hide()},"Sign out":function(){window.location.href=Galaxy.root+"user/logout?session_csrf_token="+Galaxy.session_csrf_token}}})}}})}}),d=Backbone.View.extend({title:(0,n.default)("User Preferences"),initialize:function(){this.model=new l,this.setElement("<div/>"),this.render()},render:function(){var e=this,t=Galaxy.config;$.getJSON(Galaxy.root+"api/users/"+Galaxy.user.id,function(i){e.$preferences=$("<div/>").addClass("ui-panel").append($("<h2/>").append("User preferences")).append($("<p/>").append("You are logged in as <strong>"+_.escape(i.email)+"</strong>.")).append(e.$table=$("<table/>").addClass("ui-panel-table"));var s=u.default.get("message"),a=u.default.get("status");s&&a&&e.$preferences.prepend(new r.default.Message({message:s,status:a}).$el),t.use_remote_user||(e._addLink("information"),e._addLink("password")),t.enable_communication_server&&e._addLink("communication"),e._addLink("custom_builds"),e._addLink("permissions"),e._addLink("api_key"),t.has_user_tool_filters&&e._addLink("toolbox_filters"),t.enable_openid&&!t.use_remote_user&&e._addLink("openids"),Galaxy.session_csrf_token&&e._addLink("logout"),e.$preferences.append(e._templateFooter(i)),e.$el.empty().append(e.$preferences)})},_addLink:function(e){var t=this.model.get(e),i=$(this._templateLink(t)),s=i.find("a");t.onclick?s.on("click",function(){t.onclick()}):s.attr("href",Galaxy.root+"user/"+e),this.$table.append(i)},_templateLink:function(e){return'<tr><td><div class="ui-panel-icon fa '+e.icon+'"></td><td><a class="ui-panel-anchor" href="javascript:void(0)">'+e.title+'</a><div class="ui-form-info">'+e.description+"</div></td></tr>"},_templateFooter:function(e){return'<p class="ui-panel-footer">You are using <strong>'+e.nice_total_disk_usage+"</strong> of disk space in this Galaxy instance. "+(Galaxy.config.enable_quotas?"Your disk quota is: <strong>"+e.quota+"</strong>. ":"")+'Is your usage more than expected? See the <a href="https://galaxyproject.org/learn/managing-datasets/" target="_blank">documentation</a> for tips on how to find all of the data in your account.</p>'}});e.default={View:d,Model:l}});
|
||||
define("mvc/user/user-preferences",["exports","utils/localization","mvc/form/form-view","mvc/ui/ui-misc","utils/query-string-parsing"],function(e,t,i,s,o){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var n=a(t),r=(a(i),a(s)),u=a(o),l=Backbone.Model.extend({initialize:function(e){(e=e||{}).user_id=e.user_id||Galaxy.user.id,this.set({user_id:e.user_id,information:{title:(0,n.default)("Manage information"),description:"Edit your email, addresses and custom parameters or change your username.",url:"api/users/"+e.user_id+"/information/inputs",icon:"fa-user",redirect:"user"},password:{title:(0,n.default)("Change password"),description:(0,n.default)("Allows you to change your login credentials."),icon:"fa-unlock-alt",url:"api/users/"+e.user_id+"/password/inputs",submit_title:"Save password",redirect:"user"},communication:{title:(0,n.default)("Change communication settings"),description:(0,n.default)("Enable or disable the communication feature to chat with other users."),url:"api/users/"+e.user_id+"/communication/inputs",icon:"fa-comments-o",redirect:"user"},permissions:{title:(0,n.default)("Set dataset permissions for new histories"),description:"Grant others default access to newly created histories. Changes made here will only affect histories created after these settings have been stored.",url:"api/users/"+e.user_id+"/permissions/inputs",icon:"fa-users",submit_title:"Save permissions",redirect:"user"},api_key:{title:(0,n.default)("Manage API key"),description:(0,n.default)("Access your current API key or create a new one."),url:"api/users/"+e.user_id+"/api_key/inputs",icon:"fa-key",submit_title:"Create a new key",submit_icon:"fa-check"},toolbox_filters:{title:(0,n.default)("Manage Toolbox filters"),description:(0,n.default)("Customize your Toolbox by displaying or omitting sets of Tools."),url:"api/users/"+e.user_id+"/toolbox_filters/inputs",icon:"fa-filter",submit_title:"Save filters",redirect:"user"},openids:{title:(0,n.default)("Manage OpenIDs"),description:(0,n.default)("Associate OpenIDs with your account."),icon:"fa-openid",onclick:function(){window.location.href=Galaxy.root+"openids/list"}},custom_builds:{title:(0,n.default)("Manage custom builds"),description:(0,n.default)("Add or remove custom builds using history datasets."),icon:"fa-cubes",onclick:function(){window.location.href=Galaxy.root+"custom_builds"}},logout:{title:(0,n.default)("Sign out"),description:(0,n.default)("Click here to sign out of all sessions."),icon:"fa-sign-out",onclick:function(){Galaxy.modal.show({title:(0,n.default)("Sign out"),body:"Do you want to continue and sign out of all active sessions?",buttons:{Cancel:function(){Galaxy.modal.hide()},"Sign out":function(){window.location.href=Galaxy.root+"user/logout?session_csrf_token="+Galaxy.session_csrf_token}}})}}})}}),d=Backbone.View.extend({title:(0,n.default)("User Preferences"),initialize:function(){this.model=new l,this.setElement("<div/>"),this.render()},render:function(){var e=this,t=Galaxy.config;$.getJSON(Galaxy.root+"api/users/"+Galaxy.user.id,function(i){e.$preferences=$("<div/>").addClass("ui-panel").append($("<h2/>").append("User preferences")).append($("<p/>").append("You are logged in as <strong>"+_.escape(i.email)+"</strong>.")).append(e.$table=$("<table/>").addClass("ui-panel-table"));var s=u.default.get("message"),o=u.default.get("status");s&&o&&e.$preferences.prepend(new r.default.Message({message:s,status:o}).$el),t.use_remote_user||(e._addLink("information"),e._addLink("password")),t.enable_communication_server&&e._addLink("communication"),e._addLink("custom_builds"),e._addLink("permissions"),e._addLink("api_key"),t.has_user_tool_filters&&e._addLink("toolbox_filters"),t.enable_openid&&!t.use_remote_user&&e._addLink("openids"),Galaxy.session_csrf_token&&e._addLink("logout"),e.$preferences.append(e._templateFooter(i)),e.$el.empty().append(e.$preferences)})},_addLink:function(e){var t=this.model.get(e),i=$(this._templateLink(t)),s=i.find("a");t.onclick?s.on("click",function(){t.onclick()}):s.attr("href",Galaxy.root+"user/"+e),this.$table.append(i)},_templateLink:function(e){return'<tr><td><div class="ui-panel-icon fa '+e.icon+'"></td><td><a class="ui-panel-anchor" href="javascript:void(0)">'+e.title+'</a><div class="ui-form-info">'+e.description+"</div></td></tr>"},_templateFooter:function(e){return'<p class="ui-panel-footer">You are using <strong>'+e.nice_total_disk_usage+"</strong> of disk space in this Galaxy instance. "+(Galaxy.config.enable_quotas?"Your disk quota is: <strong>"+e.quota+"</strong>. ":"")+'Is your usage more than expected? See the <a href="https://galaxyproject.org/learn/managing-datasets/" target="_blank">documentation</a> for tips on how to find all of the data in your account.</p>'}});e.default={View:d,Model:l}});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +0,0 @@
|
||||
<%namespace name="grid_base" file="./grid_base.mako" import="*" />
|
||||
|
||||
${init()}
|
||||
${h.dumps( grid_base.get_grid_config() )}
|
||||
@@ -1,5 +1,5 @@
|
||||
<%!
|
||||
from galaxy.web.framework.helpers.grids import TextColumn
|
||||
from galaxy.webapps.reports.framework.grids import TextColumn
|
||||
|
||||
def inherit(context):
|
||||
kwargs = context.get( 'kwargs', {} )
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
## load javascript
|
||||
<script type="text/javascript">
|
||||
require(['mvc/grid/grid-view'], function(GridView) {
|
||||
require(['legacy/grid/grid-view'], function(GridView) {
|
||||
$(function() {
|
||||
var gridView = new GridView.default( ${ h.dumps( self.get_grid_config( embedded=embedded, insert=insert ) ) } );
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
<%namespace name="grid_base" file="/legacy/grid_base.mako" import="*" />
|
||||
|
||||
${init()}
|
||||
${h.dumps( grid_base.get_grid_config() )}
|
||||
@@ -1,18 +0,0 @@
|
||||
<%inherit file="/webapps/galaxy/base_panels.mako"/>
|
||||
|
||||
<%def name="init()">
|
||||
<%
|
||||
self.has_left_panel=False
|
||||
self.has_right_panel=False
|
||||
self.active_view=active_view
|
||||
self.message_box_visible=False
|
||||
%>
|
||||
</%def>
|
||||
|
||||
<%def name="center_panel()">
|
||||
<div style="overflow: auto; height: 100%;">
|
||||
<div style="padding: 10px">
|
||||
${grid}
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
@@ -16,7 +16,7 @@
|
||||
<li><a href="${h.url_for( controller='user', action='api_keys', cntrller=cntrller )}">${_('Manage your API keys')}</a></li>
|
||||
<li><a href="${h.url_for( controller='user', action='toolbox_filters', cntrller=cntrller )}">${_('Manage your ToolBox filters')}</a></li>
|
||||
%if trans.app.config.enable_openid and not trans.app.config.use_remote_user:
|
||||
<li><a href="${h.url_for( controller='user', action='openid_manage', cntrller=cntrller )}">${_('Manage OpenIDs')}</a> linked to your account</li>
|
||||
<li><a href="${h.url_for( controller='openids', action='list' )}">${_('Manage OpenIDs')}</a> linked to your account</li>
|
||||
%endif
|
||||
<li><a href="${h.url_for( controller='user', action='logout', logout_all=True )}" target="_top">${_('Logout')}</a> ${_('of all user sessions')}</li>
|
||||
%else:
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
## Template generates a grid that enables user to select items.
|
||||
<%inherit file="../grid_base.mako" />
|
||||
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace file="login.mako" import="render_openid_form" />
|
||||
|
||||
<%def name="load()">
|
||||
<%def name="body()">
|
||||
<h2>Associate more OpenIDs</h2>
|
||||
${render_openid_form( kwargs['redirect'], True, kwargs['openid_providers'] )}
|
||||
<br/><br/>
|
||||
${parent.load()}
|
||||
</%def>
|
||||
${render_openid_form( redirect, True, openid_providers )}
|
||||
</%def>
|
||||
@@ -1 +0,0 @@
|
||||
<%inherit file="/grid_base.mako"/>
|
||||
@@ -5,7 +5,7 @@
|
||||
${parent.javascripts()}
|
||||
|
||||
<script type="text/javascript">
|
||||
require(['reports_webapp/run_stats'], function(run_stats){
|
||||
require(['reports/run_stats'], function(run_stats){
|
||||
run_stats.create_chart(${jf_hr_data}, "jf_hr_chart", "hours", "Jobs Finished per Hour");
|
||||
run_stats.create_chart(${jf_dy_data}, "jf_dy_chart", "days", "Jobs Finished per Day");
|
||||
run_stats.create_chart(${jc_hr_data}, "jc_hr_chart", "hours", "Jobs Created per Hour");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace name="grid_base" file="/grid_base.mako" import="*" />
|
||||
<%namespace name="grid_base" file="/legacy/grid_base.mako" import="*" />
|
||||
<%namespace name="grid_common" file="../common/grid_common.mako" import="*" />
|
||||
|
||||
<%def name="insert()">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%inherit file="/base.mako"/>
|
||||
<%namespace name="grid_base" file="/grid_base.mako" import="*" />
|
||||
<%namespace name="grid_base" file="/legacy/grid_base.mako" import="*" />
|
||||
<%namespace name="grid_common" file="../common/grid_common.mako" import="*" />
|
||||
|
||||
<%def name="insert()">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%!
|
||||
from galaxy.web.framework.helpers.grids import TextColumn, StateColumn, GridColumnFilter
|
||||
from galaxy.webapps.reports.framework.grids import TextColumn, StateColumn, GridColumnFilter
|
||||
from galaxy.web.framework.helpers import iff
|
||||
%>
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
<%inherit file="/grid_base.mako"/>
|
||||
<%inherit file="/legacy/grid_base.mako"/>
|
||||
|
||||
Reference in New Issue
Block a user