Merge pull request #5212 from guerler/remove_gridhelper_001

Remove html producing grid helpers
This commit is contained in:
Dannon Baker
2017-12-14 19:24:36 -05:00
committed by GitHub
67 changed files with 2333 additions and 338 deletions
+7 -14
View File
@@ -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
})
);
},
+11 -4
View File
@@ -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`
})
);
},
-2
View File
@@ -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">&nbsp;`;
}
}
// 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) == "-" ? "&uarr;" : "&darr;";
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;
},
+18 -35
View File
@@ -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: {
-1
View File
@@ -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
});
-15
View File
@@ -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)
+1 -61
View File
@@ -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,
+1
View File
@@ -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
+59 -74
View File
@@ -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):
+2 -1
View File
@@ -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
+1 -7
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-4
View File
@@ -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 ) ) } );
});
+4
View File
@@ -0,0 +1,4 @@
<%namespace name="grid_base" file="/legacy/grid_base.mako" import="*" />
${init()}
${h.dumps( grid_base.get_grid_config() )}
-18
View File
@@ -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>
+1 -1
View File
@@ -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:
+4 -9
View File
@@ -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
View File
@@ -1 +0,0 @@
<%inherit file="/grid_base.mako"/>
+1 -1
View File
@@ -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"/>