Merge remote-tracking branch 'upstream/dev' into workflow_list_fixes

This commit is contained in:
Dannon Baker
2017-12-21 17:59:16 -05:00
104 changed files with 1925 additions and 1906 deletions
+9 -22
View File
@@ -1,26 +1,13 @@
module.exports = function(grunt) {
"use strict";
var GALAXY_PATHS = {
dist : '../static/scripts',
maps : '../static/maps',
// this symlink allows us to serve uncompressed scripts in DEV_PATH for use with sourcemaps
srcSymlink : '../static/src',
},
TOOLSHED_PATHS = {
dist : '../static/toolshed/scripts',
maps : '../static/toolshed/maps',
srcSymlink : '../static/toolshed/src',
};
grunt.config.set( 'app', 'galaxy' );
grunt.config.set( 'paths', GALAXY_PATHS );
if( grunt.option( 'app' ) === 'toolshed' ){
grunt.config.set( 'app', grunt.option( 'app' ) );
grunt.config.set( 'paths', TOOLSHED_PATHS );
}
dist: "../static/scripts",
maps: "../static/maps",
// this symlink allows us to serve uncompressed scripts in DEV_PATH for use with sourcemaps
srcSymlink: "../static/src"
};
grunt.config.set("app", "galaxy");
grunt.config.set("paths", GALAXY_PATHS);
// see the sub directory grunt-tasks/ for individual task definitions
grunt.loadTasks( 'grunt-tasks' );
grunt.registerTask( 'default', [ 'uglify' ] );
grunt.loadTasks("grunt-tasks");
grunt.registerTask("default", ["style"]);
};
-10
View File
@@ -66,13 +66,3 @@ As mentioned above, 'make client' will also rebuild styles. If you *only* want
to run the style task, use the following command from the `client` directory:
yarn run style
The Toolshed Client Build
=========================
The toolshed client is not tightly integrated with the rest of the build
system. To build the toolshed client, execute the following command from the
`client` directory.
yarn run build-toolshed
+150 -2
View File
@@ -1,11 +1,37 @@
import _l from "utils/localization";
import GalaxyApp from "galaxy";
import WorkflowView from "mvc/workflow/workflow-view";
import Trackster from "viz/trackster";
import Circster from "viz/circster";
import Phyloviz from "viz/phyloviz";
import Sweepster from "viz/sweepster";
import GalaxyLibrary from "galaxy.library";
import AdminToolshed from "admin.toolshed";
import Masthead from "layout/masthead";
import user from "mvc/user/user-model";
import Modal from "mvc/ui/ui-modal";
import pagesEditorOnload from "galaxy.pages";
import Data from "mvc/dataset/data";
import History from "mvc/history/history-model";
import StructureView from "mvc/history/history-structure-view";
import HistoryContents from "mvc/history/history-contents";
import MultiPanel from "mvc/history/multi-panel";
import HistoryView from "mvc/history/history-view";
import HistoryViewEdit from "mvc/history/history-view-edit";
import HistoryViewAnnotated from "mvc/history/history-view-annotated";
import HistoryCopyDialog from "mvc/history/copy-dialog";
import HDAListItemEdit from "mvc/history/hda-li-edit";
import HDAModel from "mvc/history/hda-model";
import addLogging from "utils/add-logging";
import LegacyGridView from "legacy/grid/grid-view";
import * as run_stats from "reports/run_stats";
import ToolshedGroups from "toolshed/toolshed.groups";
if (window.Galaxy && window.Galaxy.debug === undefined) {
//TODO: (kind of a temporary hack?) Must have Galaxy.logging for some of the imports
//here; remove when imports are all fixed.
addLogging(window.Galaxy, "GalaxyApp");
}
export function mastheadEntry(options) {
if (!Galaxy.user) {
@@ -34,17 +60,139 @@ export function workflowEntry(options) {
new WorkflowView(options);
}
function libraryEntry(options) {
export function libraryEntry(options) {
new GalaxyLibrary.GalaxyApp(options);
}
export function historyEntry(options) {
$("#toggle-deleted").modeButton({
initialMode: options.initialModeDeleted,
modes: [
{ mode: "showing_deleted", html: _l("Exclude deleted") },
{ mode: "not_showing_deleted", html: _l("Include deleted") }
]
});
$("#toggle-hidden").modeButton({
initialMode: options.initialModeHidden,
modes: [
{ mode: "showing_hidden", html: _l("Exclude hidden") },
{ mode: "not_showing_hidden", html: _l("Include hidden") }
]
});
$("#switch").click(function() {
//##HACK:ity hack hack
//##TODO: remove when out of iframe
var hview =
Galaxy.currHistoryPanel || (window.top.Galaxy && window.top.Galaxy.currHistoryPanel)
? window.top.Galaxy.currHistoryPanel
: null;
if (hview) {
hview.switchToHistory("${ history[ 'id' ] }");
} else {
window.location = "${ switch_to_url }";
}
});
// use_panels effects where the the center_panel() is rendered:
// w/o it renders to the body, w/ it renders to #center - we need to adjust a few things for scrolling to work
if (options.hasMasthead) {
$("#center").addClass("flex-vertical-container");
}
let viewClass = options.userIsOwner ? HistoryViewEdit.HistoryViewEdit : HistoryView.HistoryView;
let historyModel = new History.History(options.historyJSON);
// attach the copy dialog to the import button now that we have a history
$("#import").click(function() {
HistoryCopyDialog(historyModel, {
useImport: true,
// use default datasets option to match the toggle-deleted button
allDatasets: $("#toggle-deleted").modeButton("getMode").mode === "showing_deleted"
}).done(function() {
if (window === window.parent) {
window.location = Galaxy.root;
} else if (Galaxy.currHistoryPanel) {
Galaxy.currHistoryPanel.loadCurrentHistory();
}
});
});
let historyView = new viewClass({
el: $("#history-" + options.historyJSON.id),
className: viewClass.prototype.className + " wide",
$scrollContainer: options.hasMasthead
? function() {
return this.$el.parent();
}
: undefined,
model: historyModel,
show_deleted: options.showDeletedJson,
show_hidden: options.showHiddenJson,
purgeAllowed: options.allow_user_dataset_purge
});
historyView.trigger("loading");
historyModel
.fetchContents({ silent: true })
.fail(function() {
alert("Galaxy history failed to load");
})
.done(function() {
historyView.trigger("loading-done");
historyView.render();
});
$("#toggle-deleted").on("click", function() {
historyView.toggleShowDeleted();
});
$("#toggle-hidden").on("click", function() {
historyView.toggleShowHidden();
});
}
export function multiHistoryEntry(options) {
let histories = new History.HistoryCollection([], {
includeDeleted: options.includingDeleted,
order: options.order,
limitOnFirstFetch: options.limit,
limitPerFetch: options.limit,
currentHistoryId: options.current_history_id
});
let multipanel = new MultiPanel.MultiPanelColumns({
el: $("#center").get(0),
histories: histories
});
histories.fetchFirst({ silent: true }).done(function() {
multipanel.createColumns();
multipanel.render(0);
});
}
export const bundleEntries = {
library: libraryEntry,
masthead: mastheadEntry,
workflow: workflowEntry,
trackster: tracksterEntry,
circster: circsterEntry,
adminToolshed: adminToolshedEntry
adminToolshed: adminToolshedEntry,
pages: pagesEditorOnload,
phyloviz: Phyloviz.PhylovizView,
createTabularDatasetChunkedView: Data.createTabularDatasetChunkedView,
multiHistory: multiHistoryEntry,
history: historyEntry,
History: History.History,
HistoryContents: HistoryContents.HistoryContents,
SweepsterVisualization: Sweepster.SweepsterVisualization,
SweepsterVisualizationView: Sweepster.SweepsterVisualizationView,
HistoryCopyDialog,
HistoryViewAnnotated,
Trackster,
StructureView,
HDAListItemEdit,
HDAModel,
GalaxyApp,
LegacyGridView,
run_stats,
ToolshedGroups
};
window.bundleEntries = bundleEntries;
+3
View File
@@ -256,6 +256,9 @@ GalaxyApp.prototype.toString = function toString() {
return `GalaxyApp(${userEmail})`;
};
// This is not great. Rework to be a singleton-style Galaxy app accessible/created by import
window.Galaxy = window.Galaxy || new GalaxyApp();
// ============================================================================
export default {
GalaxyApp: GalaxyApp
+1 -1
View File
@@ -176,7 +176,7 @@ var GalaxyLibrary = Backbone.View.extend({
mod_toastr.info("You must select at least one dataset to download");
Galaxy.libraries.library_router.navigate(`folders/${folder_id}`, { trigger: true, replace: true });
} else {
Galaxy.libraries.folderToolbarView.download(folder_id, format);
Galaxy.libraries.folderToolbarView.download(format);
Galaxy.libraries.library_router.navigate(`folders/${folder_id}`, { trigger: false, replace: true });
}
});
+3 -1
View File
@@ -5,6 +5,8 @@ import "libs/jquery/jquery.wymeditor";
import "libs/jquery/jquery.autocomplete";
import GridView from "mvc/grid/grid-view";
var WYMeditor = window.WYMeditor;
var CONTROLS = {
// Item types.
ITEM_HISTORY: "item_history",
@@ -487,7 +489,7 @@ WYMeditor.editor.prototype.dialog = function(dialogType, dialogFeatures, bodyHtm
}
};
export default function editor_onload() {
export default function pagesEditorOnload() {
// Generic error handling
$(document).ajaxError((e, x) => {
// console.log( e, x );
+2 -4
View File
@@ -17,10 +17,8 @@ var Router = Backbone.Router.extend({
data.__identifer = Math.random()
.toString(36)
.substr(2);
if (!$.isEmptyObject(data)) {
url += url.indexOf("?") == -1 ? "?" : "&";
url += $.param(data, true);
}
url += url.indexOf("?") == -1 ? "?" : "&";
url += $.param(data, true);
Galaxy.params = data;
this.navigate(url, { trigger: true });
},
@@ -4754,3 +4754,5 @@ WYMeditor.WymClassSafari.prototype.getTagForStyle = function(style) {
if(/super/.test(style)) return 'sup';
return false;
};
window.WYMeditor = WYMeditor;
@@ -278,8 +278,8 @@ var ListCollectionCreator = Backbone.View.extend(BASE_MVC.LoggableMixin)
/** describe what is wrong with a particular element if anything */
_isElementInvalid: function(element) {
if (element.history_content_type !== "dataset") {
return _l("is not a dataset");
if (element.history_content_type === "dataset_collection") {
return _l("is a collection, this is not allowed");
}
var validState = element.state === STATES.OK || _.contains(STATES.NOT_READY_STATES, element.state);
if (!validState) {
@@ -1796,7 +1796,8 @@ var pairedCollectionCreatorModal = function _pairedCollectionCreatorModal(datase
oncreate: function(creator, response) {
Galaxy.modal.hide();
deferred.resolve(response);
}
},
title: _l("Create a collection of paired datasets")
});
if (!window.Galaxy || !Galaxy.modal) {
@@ -1805,7 +1806,7 @@ var pairedCollectionCreatorModal = function _pairedCollectionCreatorModal(datase
creator = new PairedCollectionCreator(options);
Galaxy.modal.show({
title: _l("Create a collection of paired datasets"),
title: options.title,
body: creator.$el,
width: "80%",
height: "800px",
+1 -3
View File
@@ -1,8 +1,6 @@
import _l from "utils/localization";
// Additional dependencies: jQuery, underscore.
import Modal from "mvc/ui/ui-modal";
import Frames from "mvc/ui/ui-frames";
import mod_icon_btn from "mvc/ui/icon-button";
// Additional dependencies: jQuery, underscore.
/**
* Dataset metedata.
*/
+29 -37
View File
@@ -286,47 +286,39 @@ var DatasetListItemView = _super.extend(
return this._renderMetaFileDownloadButton();
}
return $(
[
'<a class="download-btn icon-btn" ',
'href="',
this.model.urls.download,
`" title="${_l("Download")}" download>`,
'<span class="fa fa-floppy-o"></span>',
"</a>"
].join("")
);
return $(`
<a class="download-btn icon-btn" href="${this.model.urls.download}" title="${_l("Download")}">
<span class="fa fa-floppy-o"></span>
</a>`);
},
/** Render the download button which opens a dropdown with links to download assoc. meta files (indeces, etc.) */
/** Render the download button which opens a dropdown with links to download assoc. meta files (indices, etc.) */
_renderMetaFileDownloadButton: function() {
var urls = this.model.urls;
return $(
[
'<div class="metafile-dropdown dropdown">',
'<a class="download-btn icon-btn" href="javascript:void(0)" data-toggle="dropdown"',
` title="${_l("Download")}">`,
'<span class="fa fa-floppy-o"></span>',
"</a>",
'<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">',
`<li><a href="${urls.download}" download>`,
_l("Download dataset"),
"</a></li>",
_.map(this.model.get("meta_files"), meta_file =>
[
'<li><a href="',
urls.meta_download + meta_file.file_type,
'">',
_l("Download"),
" ",
meta_file.file_type,
"</a></li>"
].join("")
).join("\n"),
"</ul>",
"</div>"
].join("\n")
);
return $(`
<div class="metafile-dropdown dropdown">
<a class="download-btn icon-btn" href="${urls.download}" data-toggle="dropdown" title="${_l(
"Download"
)}">
<span class="fa fa-floppy-o"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li>
<a href="${urls.download}">
${_l("Download dataset")}
</a>
</li>
${_.map(
this.model.get("meta_files"),
meta_file =>
`<li>
<a href="${urls.meta_download + meta_file.file_type}">
${_l("Download")} ${meta_file.file_type}
</a>
</li>`
)}
</ul>
</div>`);
},
_renderNametags: function() {
@@ -1,15 +1,14 @@
function _labelIfName(tag) {
if (tag.indexOf("name:") == 0) {
return `<span class="label label-info">${_.escape(tag.slice(5))}</span>`;
} else {
return "";
}
function _templateNametag(tag) {
return `<span class="label label-info">${_.escape(tag.slice(5))}</span>`;
}
function nametagTemplate(historyItem) {
return `<span class="nametags">${_.sortBy(_.uniq(historyItem.tags))
.map(_labelIfName)
.join("")}</span>`;
let uniqueNametags = _.filter(_.uniq(historyItem.tags), t => t.indexOf("name:") === 0);
let nametagsDisplay = _.sortBy(uniqueNametags).map(_templateNametag);
return `
<div class="nametags" title="${uniqueNametags.length} nametags">
${nametagsDisplay.join("")}
</div>`;
}
export default {
File diff suppressed because it is too large Load Diff
+10 -11
View File
@@ -39,17 +39,16 @@ export var View = Backbone.View.extend({
if (!this.visible) {
this.visible = true;
this.$el.fadeIn("fast");
if (this.options.closing_events) {
var self = this;
$(document).on("keyup.ui-modal", e => {
if (e.keyCode == 27) {
self.hide(true);
}
});
this.$backdrop.on("click", () => {
self.hide(true);
});
}
}
if (this.options.closing_events) {
$(document).on("keyup.ui-modal", e => {
if (e.keyCode == 27) {
this.hide(true);
}
});
this.$backdrop.on("click", () => {
this.hide(true);
});
}
},
@@ -5,7 +5,6 @@ import Utils from "utils/utils";
import Buttons from "mvc/ui/ui-buttons";
var View = Backbone.View.extend({
initialize: function(options) {
var self = this;
this.data = [];
this.data2 = [];
this.model =
@@ -28,7 +27,9 @@ var View = Backbone.View.extend({
pagesize: 20
}).set(options);
this.on("change", () => {
self.model.get("onchange") && self.model.get("onchange")(self.value());
if (this.model.get("onchange")) {
this.model.get("onchange")(this.value());
}
});
this.listenTo(this.model, "change:data", this._changeData, this);
this.listenTo(this.model, "change:disabled", this._changeDisabled, this);
@@ -40,8 +41,11 @@ var View = Backbone.View.extend({
},
render: function() {
var self = this;
this.model.get("searchable") ? this._renderSearchable() : this._renderClassic();
if (this.model.get("searchable")) {
this._renderSearchable();
} else {
this._renderClassic();
}
this.$el.addClass(this.model.get("cls")).attr("id", this.model.get("id"));
this.$select
.empty()
@@ -49,8 +53,8 @@ var View = Backbone.View.extend({
.attr("id", `${this.model.get("id")}_select`)
.prop("multiple", this.model.get("multiple"))
.on("change", () => {
self.value(self._getValue());
self.trigger("change");
this.value(this._getValue());
this.trigger("change");
});
this._changeData();
this._changeWait();
@@ -60,7 +64,6 @@ var View = Backbone.View.extend({
/** Renders the classic selection field */
_renderClassic: function() {
var self = this;
this.$el
.addClass(this.model.get("multiple") ? "ui-select-multiple" : "ui-select")
.append((this.$select = $("<select/>")))
@@ -76,12 +79,12 @@ var View = Backbone.View.extend({
.off("mousedown")
.on("mousedown", event => {
var currentY = event.pageY;
var currentHeight = self.$select.height();
self.minHeight = self.minHeight || currentHeight;
var currentHeight = this.$select.height();
this.minHeight = this.minHeight || currentHeight;
$("#dd-helper")
.show()
.on("mousemove", event => {
self.$select.height(Math.max(currentHeight + (event.pageY - currentY), self.minHeight));
this.$select.height(Math.max(currentHeight + (event.pageY - currentY), this.minHeight));
})
.on("mouseup mouseleave", () => {
$("#dd-helper")
@@ -98,25 +101,27 @@ var View = Backbone.View.extend({
/** Renders the default select2 field */
_renderSearchable: function() {
var self = this;
this.$el.append((this.$select = $("<div/>"))).append((this.$dropdown = $("<div/>")));
this.$dropdown.hide();
if (!this.model.get("multiple")) {
this.$dropdown.show().on("click", () => {
self.$select.select2 && self.$select.select2("open");
if (this.$select.select2) {
this.$select.select2("open");
}
});
}
this.all_button = null;
if (this.model.get("multiple") && !this.model.get("individual") && !this.model.get("readonly")) {
this.all_button = new Buttons.ButtonCheck({
onclick: function() {
onclick: () => {
var new_value = [];
self.all_button.value() !== 0 &&
_.each(self.model.get("data"), option => {
if (this.all_button.value() !== 0) {
_.each(this.model.get("data"), option => {
new_value.push(option.value);
});
self.value(new_value);
self.trigger("change");
}
this.value(new_value);
this.trigger("change");
}
});
this.$el.prepend(this.all_button.$el);
@@ -127,7 +132,7 @@ var View = Backbone.View.extend({
_match: function(term, text) {
return (
!term ||
term == "" ||
term === "" ||
String(text)
.toUpperCase()
.indexOf(term.toUpperCase()) >= 0
@@ -136,18 +141,17 @@ var View = Backbone.View.extend({
/** Updates the selection options */
_changeData: function() {
var self = this;
this.data = [];
if (!this.model.get("multiple") && this.model.get("optional")) {
this.data.push({
value: "__null__",
label: self.model.get("empty_text")
label: this.model.get("empty_text")
});
}
_.each(this.model.get("data"), option => {
self.data.push(option);
this.data.push(option);
});
if (this.length() == 0) {
if (this.length() === 0) {
this.data.push({
value: "__null__",
label: this.model.get("error_text")
@@ -156,61 +160,71 @@ var View = Backbone.View.extend({
if (this.model.get("searchable")) {
this.data2 = [];
_.each(this.data, (option, index) => {
self.data2.push({
this.data2.push({
order: index,
id: option.value,
text: option.label,
tags: option.tags
});
});
this.$select.data("select2") && this.$select.select2("destroy");
if (this.$select.data("select2")) {
this.$select.select2("destroy");
}
this.matched_tags = {};
this.$select.select2({
data: self.data2,
data: this.data2,
closeOnSelect: !this.model.get("multiple"),
multiple: this.model.get("multiple"),
query: function(q) {
self.matched_tags = {};
var pagesize = self.model.get("pagesize");
var results = _.filter(self.data2, e => {
query: q => {
this.matched_tags = {};
var pagesize = this.model.get("pagesize");
var results = _.filter(this.data2, e => {
var found = false;
_.each(e.tags, tag => {
if (self._match(q.term, tag)) {
found = self.matched_tags[tag] = true;
if (this._match(q.term, tag)) {
found = this.matched_tags[tag] = true;
}
});
return found || self._match(q.term, e.text);
return found || this._match(q.term, e.text);
});
q.callback({
results: results.slice((q.page - 1) * pagesize, q.page * pagesize),
more: results.length >= q.page * pagesize
});
},
formatResult: function(result) {
return `${_.escape(result.text)}<div class="ui-tags">${_.reduce(
result.tags,
(memo, tag) => {
if (self.matched_tags[tag]) {
formatResult: result => {
let extraTagWarning = "";
let filteredTags = _.filter(result.tags, t => this.matched_tags.hasOwnProperty(t));
if (filteredTags.length > 5) {
extraTagWarning = `&nbsp;<div class="label label-warning">${filteredTags.length -
5} more tags</div>`;
}
return `
${_.escape(result.text)}
<div class="ui-tags">
${_.reduce(
filteredTags.slice(0, 5),
(memo, tag) => {
return `${memo}&nbsp;<div class="label label-info">${_.escape(tag)}</div>`;
}
return memo;
},
""
)}</div>`;
},
""
)}
${extraTagWarning}
</div>`;
}
});
this.$(".select2-container .select2-search input").off("blur");
} else {
this.$select.find("option").remove();
_.each(this.data, option => {
self.$select.append(
this.$select.append(
$("<option/>")
.attr("value", option.value)
.html(_.escape(option.label))
);
});
}
this.model.set("disabled", this.model.get("readonly") || this.length() == 0);
this.model.set("disabled", this.model.get("readonly") || this.length() === 0);
this._changeValue();
},
@@ -252,7 +266,9 @@ var View = Backbone.View.extend({
/** Return/Set current selection */
value: function(new_value) {
new_value !== undefined && this.model.set("value", new_value);
if (new_value !== undefined) {
this.model.set("value", new_value);
}
return this._getValue();
},
@@ -311,9 +327,13 @@ var View = Backbone.View.extend({
/** Update all available options at once */
add: function(options, sorter) {
_.each(this.model.get("data"), v => {
v.keep && !_.findWhere(options, { value: v.value }) && options.push(v);
if (v.keep && !_.findWhere(options, { value: v.value })) {
options.push(v);
}
});
sorter && options && options.sort(sorter);
if (sorter && options) {
options.sort(sorter);
}
this.model.set("data", options);
},
@@ -334,7 +354,6 @@ var View = Backbone.View.extend({
/** Set value to dom */
_setValue: function(new_value) {
var self = this;
if (new_value === null || new_value === undefined) {
new_value = "__null__";
}
@@ -351,8 +370,10 @@ var View = Backbone.View.extend({
if ($.isArray(new_value)) {
var val = [];
_.each(new_value, v => {
var d = _.findWhere(self.data2, { id: v });
d && val.push(d);
var d = _.findWhere(this.data2, { id: v });
if (d) {
val.push(d);
}
});
new_value = val;
} else {
@@ -1,8 +1,7 @@
// dependencies
import Utils from "utils/utils";
import Ui from "mvc/ui/ui-misc";
import Table from "mvc/ui/ui-table";
import List from "mvc/ui/ui-list";
// collection of libraries
var Libraries = Backbone.Collection.extend({
url: `${Galaxy.root}api/libraries?deleted=false`
@@ -85,7 +84,9 @@ var View = Backbone.View.extend({
// add change event. fires on trigger
this.on("change", () => {
options.onchange && options.onchange(self.value());
if (options.onchange) {
options.onchange(self.value());
}
});
// create elements
+171 -96
View File
@@ -1,169 +1,244 @@
/** zh localization */
/* by steven shen */
define({
// ----------------------------------------------------------------------------- masthead
"Analyze Data": "数据分析",
Workflow: "流程",
"Shared Data": "共享的数据",
"Data Libraries": "数据库",
Histories: "已发布的历史",
Workflows: "已发布的流程",
Visualizations: "已发布的可视化",
Pages: "已发布的页面",
Visualization: "可视化",
"New Track Browser": "创建 Track Browser",
"Saved Visualizations": "已保存的保存",
"Interactive Environments": "交互式环境",
Admin: "管理员",
Help: "帮助",
Support: "支持",
Search: "搜索",
"Mailing Lists": "邮件列表",
Videos: "视频",
Wiki: false,
"How to Cite Galaxy": "引用",
"Interactive Tours": "使用引导",
User: "用户",
Login: "登陆",
Register: "注册",
"Login or Register": "登陆或注册",
"Logged in as": "您已登陆为",
Preferences: "用户偏好性",
"Custom Builds": "自定义构建集",
Logout: "退出",
"Saved Histories": "保存历史",
"Saved Datasets": "保存数据集",
"Saved Pages": "保存页面",
//Tooltip
"Account and saved data": "账号及数据保存",
"Account registration or login": "注册与登录",
"Support, contact, and community": "支持,联系,社区",
"Administer this Galaxy": "管理您的Galaxy",
"Visualize datasets": "数据集可视化",
"Access published resources": "访问发布的资源",
"Chain tools into workflows": "将工具链接到工作流程中",
"Analysis home view": "数据分析主页",
// ---------------------------------------------------------------------------- histories
// ---- history/options-menu
"History Lists": "历史列表",
// Saved histories is defined above.
"Saved Histories": "保存历史",
"Histories Shared with Me": "分享给您历史",
"Current History": "当前历史",
"Create New": "创建新的历史",
"Copy History": "复制历史",
"Share or Publish": "分享或发布历史",
"Show Structure": "展示结构",
"Extract Workflow": "提取为工作流",
// Delete is defined elsewhere, but is also in this menu.
Delete: "删除",
"Delete Permanently": "永久删除",
"Dataset Actions": "数据操作",
"Copy Datasets": "复制数据集",
"Dataset Security": "数据安全",
"Resume Paused Jobs": "恢复已暂停的任务",
"Collapse Expanded Datasets": false,
"Unhide Hidden Datasets": "取消隐藏的数据集",
"Delete Hidden Datasets": "删除隐藏的数据集",
"Purge Deleted Datasets": "清空已删除的数据集",
Downloads: "下载",
"Export Tool Citations": "导出工具文献引用",
"Export History to File": "导出历史到文件",
"Other Actions": "其他操作",
"Import from File": "从文件导入",
Webhooks: false,
// ---- history-model
// ---- history-view
"This history is empty": "历史已空",
"No matching datasets found": "未找到匹配的数据集",
//"An error occurred while getting updates from the server" :
//false,
//"Please contact a Galaxy administrator if the problem persists" :
//false,
"An error occurred while getting updates from the server": "从服务器更新出现错误",
"Please contact a Galaxy administrator if the problem persists": "如果问题仍然存在,请联系Galaxy管理员",
//TODO:
//"An error was encountered while <% where %>" :
//false,
"Search datasets": "搜索数据集",
"You are currently viewing a deleted history!": "正在查看已删除的历史",
"You are over your disk quota": "您已超过磁盘配额",
//"Tool execution is on hold until your disk usage drops below your allocated quota" :
//false,
All: "皆",
"An error was encountered while <% where %>": "出现错误,当执行以下操作时: <% where %>",
"search datasets": "搜索数据集",
"You are currently viewing a deleted history!": "您正在查看已删除的历史记录",
"You are over your disk quota": "您超出了您的磁盘配额",
"Tool execution is on hold until your disk usage drops below your allocated quota":
"工具执行处于暂停状态,直到您的磁盘使用量低于您分配的配额",
All: "所有的",
None: "一个也没有",
"For all selected": "为每个选定",
// ---- history-view-edit
//"Edit history tags" :
//false,
//"Edit history Annotation" :
//false,
"Edit history tags": "编辑历史标签",
"Edit history Annotation": "编辑历史备注",
"Click to rename history": "单击要重命名的历史",
// multi operations
"Operations on multiple datasets": "编辑多个数据集",
//"Hide datasets" :
//false,
//"Unhide datasets" :
//false,
//"Delete datasets" :
//false,
//"Undelete datasets" :
//false,
"Hide datasets": "隐藏数据集",
"Unhide datasets": "显示数据集",
"Delete datasets": "删除数据集",
"Undelete datasets": "取消删除数据集",
"Permanently delete datasets": "永久删除数据集",
"This will permanently remove the data in your datasets. Are you sure?": "这将永久在你的数据集删除数据。你确定?",
"This will permanently remove the data in your datasets. Are you sure?": "这将永久在您的数据集删除数据。你确定?",
// ---- history-view-annotated
Dataset: "数据集",
//"Annotation" :
//false,
Dataset: "数据",
Annotation: "备注",
// ---- history-view-edit-current
"This history is empty. Click 'Get Data' on the left tool menu to start": "历史已空,请单击左边窗格中‘获取数据’",
"You must be logged in to create histories": "你必须登录后才能创建历史",
//TODO:
//"You can <% loadYourOwn %> or <% externalSource %>" :
"You can ": "您可以 ",
" or ": " 或者 ",
"load your own data": "上传您的个人数据",
"get data from an external source": "从外部来源获取数据",
// these aren't in zh/ginga.po and the template doesn't localize
//"Include Deleted Datasets" :
//false,
//"load your own data" :
//false,
//"get data from an external source" :
//"Include Hidden Datasets" :
//false,
// ---------------------------------------------------------------------------- datasets
// ---- hda-model
//"Unable to purge dataset" :
//false,
"Unable to purge dataset": "无法清除数据集",
// ---- hda-base
// display button
//"Cannot display datasets removed from disk" :
//false,
//"This dataset must finish uploading before it can be viewed" :
//false,
//"This dataset is not yet viewable" :
//false,
"View data": "数据",
"Cannot display datasets removed from disk": "无法显示已从磁盘中删除的数据集",
"This dataset must finish uploading before it can be viewed": "此数据集必须先完成上传, 然后才能查看",
"This dataset is not yet viewable": "此数据集是不可见的",
"View data": "查看数据",
// download button
Download: "下载",
"Download dataset": "下载数据集",
//"Additional files" :
//false,
"Additional files": "其他文件",
// info/show_params
"View details": "查看详情",
// dataset states
// state: new
//"This is a new dataset and not all of its data are available yet" :
//false,
"This is a new dataset and not all of its data are available yet": "这是一个新的数据集,并不是所有的数据都可用",
// state: noPermission
//"You do not have permission to view this dataset" :
//false,
"You do not have permission to view this dataset": "您无权查看此数据集",
// state: discarded
//"The job creating this dataset was cancelled before completion" :
//false,
"The job creating this dataset was cancelled before completion": "创建此数据集的任务在完成之前已被取消",
// state: queued
"This job is waiting to run": "等待运行的进程",
"This job is waiting to run": "任务正在等待运行",
// state: upload
//"This dataset is currently uploading" :
//false,
"This dataset is currently uploading": "此数据集正在上传中",
// state: setting_metadata
//"Metadata is being auto-detected" :
//false,
"Metadata is being auto-detected": "元数据正在被自动检测中",
// state: running
"This job is currently running": "正在运行的进程",
"This job is currently running": "任务正在运行中",
// state: paused
//"This job is paused. Use the \"Resume Paused Jobs\" in the history menu to resume" :
//false,
'This job is paused. Use the "Resume Paused Jobs" in the history menu to resume':
'此任务已暂停。使用历史菜单中的 "恢复已暂停的工作" 来恢复',
// state: error
"An error occurred with this dataset": "进程运行时出错",
"An error occurred with this dataset": "此数据集发生错误",
// state: empty
"No data": "没有数据",
// state: failed_metadata
//"An error occurred setting the metadata for this dataset" :
//false,
"An error occurred setting the metadata for this dataset": "设置此数据集的元数据时发生错误",
// ajax error prefix
//"There was an error getting the data for this dataset" :
//false,
"There was an error getting the data for this dataset": "获取此数据集的数据时出错",
// purged'd/del'd msg
//"This dataset has been deleted and removed from disk" :
//false,
"This dataset has been deleted and removed from disk": "此数据集已被删除并从磁盘中删除",
"This dataset has been deleted": "此数据集已被删除",
"This dataset has been hidden": "此数据集已隐藏",
"This dataset has been hidden": "此数据集已被隐藏",
format: "格式",
database: "数据库",
// ---- hda-edit
"Edit attributes": "编辑属性",
//"Cannot edit attributes of datasets removed from disk" :
//false,
//"Undelete dataset to edit attributes" :
//false,
//"This dataset must finish uploading before it can be edited" :
//false,
//"This dataset is not yet editable" :
//false,
"Cannot edit attributes of datasets removed from disk": "无法编辑已从磁盘中删除的数据集的属性",
"Undelete dataset to edit attributes": "取消删除数据集以编辑属性",
"This dataset must finish uploading before it can be edited": "该数据集必须先上传完成, 然后才能编辑",
"This dataset is not yet editable": "该数据集不可编辑",
Delete: "删除",
//"Dataset is already deleted" :
//false,
"Dataset is already deleted": "数据集已被删除",
"View or report this error": "报告错误",
"View or report this error": "查看或报告此错误",
"Run this job again": "重新运行",
"Run this job again": "重新运行此任务",
Visualize: "图形",
//"Visualize in" :
//false,
Visualize: "可视化",
"Visualize in": "的可视化",
"Undelete it": "反删除",
"Undelete it": "取消删除",
"Permanently remove it from disk": "从磁盘中永久删除",
"Unhide it": "取消隐藏"
"Unhide it": "取消隐藏",
//"You may be able to" :
//false,
//"set it manually or retry auto-detection" :
//false,
"You may be able to": "您可能可以",
"set it manually or retry auto-detection": "手动设置或重试自动检测",
//"Edit dataset tags" :
//false,
//"Edit dataset annotation" :
//false,
"Edit dataset tags": "编辑数据集标签",
"Edit dataset annotation": "编辑数据集备注",
"Tool Help": "工具帮助",
// ---------------------------------------------------------------------------- admin
"Search Tool Shed": "搜索 Tool Shed",
"Monitor installing repositories": "",
"Manage installed tools": "管理已安装的工具",
"Reset metadata": "重置元数据",
"Download local tool": "下载本地工具",
"Tool lineage": false,
"Reload a tool's configuration": "重新加载工具的配置",
"Review tool migration stages": "查看工具迁移状态",
"View Tool Error Logs": "查看工具错误日志",
"Manage Display Whitelist": "管理显示白名单",
"Manage Tool Dependencies": "管理工具依赖",
Users: "用户",
Groups: "组别",
"API keys": false,
"Impersonate a user": "模拟用户",
Data: "数据",
Quotas: "配额",
Roles: "角色",
"Local data": "本地数据",
"Form Definitions": "定义表单",
// ---------------------------------------------------------------------------- Scratchbook
"Enable/Disable Scratchbook": "启用/禁用 Scratchbook",
"Show/Hide Scratchbook": "显示/隐藏 Scratchbook",
// ---------------------------------------------------------------------------- misc. MVC
//"Tags" :
//false,
//"Annotation" :
//false,
//"Edit annotation" :
//false,
Tags: "标签",
"Edit annotation": "编辑备注",
// ----------------------------------------------------------------------------
ja: true,
fr: true,
zh: true
});
@@ -0,0 +1,138 @@
import * as mod_toastr from "libs/toastr";
import mod_group_model from "toolshed/groups/group-model";
// toolshed group detail view
const GroupDetailView = Backbone.View.extend({
el: "#groups_element",
options: {},
app: null,
initialize: function(options) {
this.options = _.extend(this.options, options);
this.app = window.globalTS.groups;
if (this.app.collection !== null) {
this.model = this.app.collection.get(this.options.group_id);
this.render();
} else {
this.fetchGroup();
}
},
fetchGroup: function(options) {
const that = this;
this.options = _.extend(this.options, options);
this.model = new mod_group_model.Group({ id: this.options.group_id });
this.model.fetch({
success: function(model) {
console.log("received data: ");
console.log(model);
that.render();
},
error: function(model, response) {
if (typeof response.responseJSON !== "undefined") {
mod_toastr.error(response.responseJSON.err_msg);
} else {
mod_toastr.error("An error occurred.");
}
}
});
},
render: function() {
const template = this.templateRow();
this.$el.html(template({ group: this.model }));
$("#center [data-toggle]").tooltip();
$("#center").css("overflow", "auto");
},
templateRow: function() {
return _.template(
[
"<div>",
'<h3><%= _.escape(group.get("name")) %></h3>',
'<p class="" style="color:gray;">',
'A group of <%= group.get("members").length %> members with <%= group.get("repositories").length %> repositories and a total of <%= group.get("total_downloads") %> combined repository clones.</p>',
"<h3>Members</h3>",
'<table class="grid table table-condensed">',
"<thead>",
"<th>Name</th>",
"<th>Repositories</th>",
"<th>Registered</th>",
"</thead>",
"<tbody>",
'<% _.each(group.get("members"), function(member) { %>',
"<tr>",
"<td>",
"<%= _.escape(member.username) %>",
"</td>",
"<td>",
'<a data-toggle="tooltip" data-placement="top" title="Repositories of <%= _.escape(member.username) %>" href="/repository/browse_repositories_by_user?user_id=<%= member.id %>&use_panels=true" id="<%= member.id %>"><%= member.user_repos_count %></a>',
"</td>",
"<td>",
"<%= member.time_created %>",
"</td>",
"</tr>",
"<% }); %>",
"</tbody>",
"</table>",
"<h3>Repositories</h3>",
'<table class="grid table table-condensed">',
"<thead>",
"<th>Name</th>",
"<th>Description</th>",
"<th>Clones</th>",
"<th>Owner</th>",
"<th>Categories</th>",
"<th>Created</th>",
"<th>Updated</th>",
"<th>Rating</th>",
"<th>Verified</th>",
"</thead>",
"<tbody>",
'<% _.each(group.get("repositories"), function(repo) { %>',
"<tr>",
"<td>",
'<a data-toggle="tooltip" data-placement="top" title="Details of <%= _.escape(repo.name) %>" href="/view/<%= _.escape(repo.owner) %>/<%= _escape(repo.name) %>" id="<%= repo.id %>"><%= _.escape(repo.name) %></a>',
"</td>",
"<td>",
"<%= _.escape(repo.description) %>",
"</td>",
"<td>",
"<%= repo.times_downloaded %>",
"</td>",
"<td>",
"<%= _.escape(repo.owner) %>",
"</td>",
"<td>",
"<% _.each((repo.categories), function(cat) { %>",
'<a data-toggle="tooltip" data-placement="top" title="Repositories in <%= cat.name %>" href="/repository/browse_repositories_in_category?id=<%= cat.id %>&use_panels=true"><%= cat.name %></a><br/>',
// '<%= repo.categories %>',
"<% }); %>",
"</td>",
'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_created_full %>">',
"<%= repo.time_created %>",
"</td>",
'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_updated_full %>">',
"<%= repo.time_updated %>",
"</td>",
"<td>",
"<%= repo.ratings_mean %>",
"</td>",
"<td>",
"<%= repo.approved %>",
"</td>",
"</tr>",
"<% }); %>",
"</tbody>",
"</table>",
"</div>"
].join("")
);
}
});
export default {
GroupDetailView: GroupDetailView
};
@@ -0,0 +1,128 @@
import * as mod_toastr from "libs/toastr";
import mod_group_model from "toolshed/groups/group-model";
import mod_group_row from "toolshed/groups/group-listrow-view";
const GroupListView = Backbone.View.extend({
el: "#groups_element",
defaults: {},
/**
* Initialize and fetch the groups from server.
* Async render afterwards.
* @param {object} options an object with options
*/
initialize: function(options) {
this.options = _.defaults(this.options || {}, this.defaults, options);
const that = this;
window.globalTS.groups.collection = new mod_group_model.Groups();
window.globalTS.groups.collection.fetch({
success: function(model) {
console.log("received data: ");
console.log(model);
that.render();
},
error: function(model, response) {
if (typeof response.responseJSON !== "undefined") {
mod_toastr.error(response.responseJSON.err_msg);
} else {
mod_toastr.error("An error occurred.");
}
}
});
},
fetch: function() {},
/**
* Render the groups table from the object's own collection.
*/
render: function(options) {
this.options = _.extend(this.options, options);
$(".tooltip").hide();
const template = this.templateGroupsList();
this.$el.html(template({ length: window.globalTS.groups.collection.models.length }));
this.renderRows(window.globalTS.groups.collection.models);
$("#center [data-toggle]").tooltip();
$("#center").css("overflow", "auto");
},
/**
* Render all given models as rows in the groups list
* @param {array} groups_to_render array of group models to render
*/
renderRows: function(groups_to_render) {
for (let i = 0; i < groups_to_render.length; i++) {
const group = groups_to_render[i];
this.renderOne({ group: group });
}
},
/**
* Create a view for the given model and add it to the groups view.
* @param {Group} model of the view that will be rendered
*/
renderOne: function(options) {
const rowView = new mod_group_row.GroupListRowView(options);
this.$el.find("#group_list_body").append(rowView.el);
},
/**
* Table heading was clicked, update sorting preferences and re-render.
* @return {[type]} [description]
*/
// sort_clicked : function(){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// Galaxy.libraries.preferences.set({'sort_order': 'desc'});
// } else {
// Galaxy.libraries.preferences.set({'sort_order': 'asc'});
// }
// this.render();
// },
/**
* Sort the underlying collection according to the parameters received.
* Currently supports only sorting by name.
*/
// sortLibraries: function(){
// if (Galaxy.libraries.preferences.get('sort_by') === 'name'){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// this.collection.sortByNameAsc();
// } else if (Galaxy.libraries.preferences.get('sort_order') === 'desc'){
// this.collection.sortByNameDesc();
// }
// }
// },
// MMMMMMMMMMMMMMMMMM
// === TEMPLATES ====
// MMMMMMMMMMMMMMMMMM
templateGroupsList: function() {
const tmpl_array = [];
tmpl_array.push('<div id="groups">');
tmpl_array.push("</div>");
tmpl_array.push('<div class="groups_container table-responsive">');
tmpl_array.push("<% if(length === 0) { %>");
tmpl_array.push("<div>There are no groups yet.</div>");
tmpl_array.push("<% } else{ %>");
tmpl_array.push('<table class="grid table table-condensed">');
tmpl_array.push(" <thead>");
tmpl_array.push(" <th>Name</th>");
// tmpl_array.push(' <th style="width:22%;">description</th>');
tmpl_array.push(" <th>Members</th> ");
tmpl_array.push(" <th>Repositories</th>");
tmpl_array.push(" </thead>");
tmpl_array.push(' <tbody id="group_list_body">');
// group item views will attach here
tmpl_array.push(" </tbody>");
tmpl_array.push("</table>");
tmpl_array.push("<% }%>");
tmpl_array.push("</div>");
return _.template(tmpl_array.join(""));
}
});
export default {
GroupListView: GroupListView
};
@@ -1,36 +1,32 @@
define([],
function() {
// toolshed group row view
var GroupListRowView = Backbone.View.extend({
const GroupListRowView = Backbone.View.extend({
events: {},
initialize : function( options ){
this.render( options.group );
initialize: function(options) {
this.render(options.group);
},
render: function( group ){
var tmpl = this.templateRow();
this.setElement(tmpl( { group:group } ));
render: function(group) {
const tmpl = this.templateRow();
this.setElement(tmpl({ group: group }));
this.$el.show();
return this;
},
templateRow: function() {
return _.template([
return _.template(
[
'<tr class="" data-id="<%- group.get("id") %>">',
'<td><a href="groups#/<%= group.get("id") %>"><%= _.escape(group.get("name")) %></a></td>',
// '<td>description</td>',
'<td><%= group.get("total_members") %></td>',
'<td><%= group.get("total_repos") %></td>',
'</tr>'
].join(''));
}
"</tr>"
].join("")
);
}
});
return {
export default {
GroupListRowView: GroupListRowView
};
});
@@ -0,0 +1,17 @@
// ============================================================================
// TS GROUP RELATED MODELS
const Group = Backbone.Model.extend({
urlRoot: `${Galaxy.root}api/groups`
});
const Groups = Backbone.Collection.extend({
url: `${Galaxy.root}api/groups`,
model: Group
});
export default {
Group: Group,
Groups: Groups
};
@@ -0,0 +1,42 @@
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// === MAIN TOOLSHED GROUP MODULE ====
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
import mod_group_list from "toolshed/groups/group-list-view";
import mod_group_detail from "toolshed/groups/group-detail-view";
// ============================================================================
// ROUTER
const ToolshedRouter = Backbone.Router.extend({
routes: {
"": "groups",
":group_id": "group_page"
}
});
const ToolshedGroups = Backbone.View.extend({
groupListView: null,
groupDetailView: null,
collection: null,
initialize: function() {
window.globalTS.groups = this;
this.ts_router = new ToolshedRouter();
this.ts_router.on("route:groups", () => {
window.globalTS.groups.groupListView = new mod_group_list.GroupListView();
});
this.ts_router.on("route:group_page", group_id => {
window.globalTS.groups.groupDetailView = new mod_group_detail.GroupDetailView({
group_id: group_id
});
});
Backbone.history.start({ pushState: false });
}
});
export default {
ToolshedGroups: ToolshedGroups
};
+7 -9
View File
@@ -1,6 +1,7 @@
import _l from "utils/localization";
import * as _ from "libs/underscore";
import * as d3 from "libs/d3";
import * as d3 from "d3";
import { event as currentEvent } from "d3";
import visualization from "viz/visualization";
import mod_utils from "utils/utils";
import config from "utils/config";
@@ -193,7 +194,6 @@ var CircsterView = Backbone.View.extend({
tracks_start_radii = d3.range(radius_start, min_dimension / 2, dataset_arc_height + track_gap);
// Map from track start to bounds.
var self = this;
return _.map(tracks_start_radii, radius => [radius, radius + dataset_arc_height]);
},
@@ -221,8 +221,8 @@ var CircsterView = Backbone.View.extend({
.call(
d3.behavior.zoom().on("zoom", () => {
// Do zoom, drag.
var scale = d3.event.scale;
svg.attr("transform", `translate(${d3.event.translate}) scale(${scale})`);
var scale = currentEvent.scale;
svg.attr("transform", `translate(${currentEvent.translate}) scale(${scale})`);
// Propagate scale changes to views.
if (self.scale !== scale) {
@@ -628,7 +628,6 @@ var CircsterTrackView = Backbone.View.extend({
* default data bounds.
*/
_update_data_bounds: function(new_bounds) {
var old_bounds = this.data_bounds;
this.data_bounds =
new_bounds || this.get_data_bounds(this.track.get("data_manager").get_genome_wide_data(this.genome));
this._transition_chrom_data();
@@ -962,7 +961,6 @@ var CircsterQuantitativeTrackView = CircsterTrackView.extend({
_data_bounds_ticks_fn: function() {
// Closure vars.
var self = this;
visibleChroms = 0;
// Return function for locating ticks based on chrom arc data.
return (
@@ -1101,9 +1099,9 @@ var Circster = Backbone.View.extend({
// load css
mod_utils.cssLoadFile("static/style/circster.css");
// -- Configure visualization --
var genome = new visualization.Genome(galaxy_config.app.genome);
var genome = new visualization.Genome(window.galaxy_config.app.genome);
var vis = new visualization.GenomeVisualization(galaxy_config.app.viz_config);
var vis = new visualization.GenomeVisualization(window.galaxy_config.app.viz_config);
// Add Circster-specific config options.
vis.get("config").add([
@@ -1143,7 +1141,7 @@ var Circster = Backbone.View.extend({
// setup title
$("#center .unified-panel-header-inner").append(
`${galaxy_config.app.viz_config.title} ${galaxy_config.app.viz_config.dbkey}`
`${window.galaxy_config.app.viz_config.title} ${window.galaxy_config.app.viz_config.dbkey}`
);
// setup menu
+20 -17
View File
@@ -2,13 +2,7 @@ import _l from "utils/localization";
/**
* Top-level trackster code, used for creating/loading visualizations and user interface elements.
*/
// global variables
var ui = null;
var view = null;
var browser_router = null;
// trackster viewer
//import * as $ from 'jquery';
import * as _ from "libs/underscore";
import tracks from "viz/trackster/tracks";
import visualization from "viz/visualization";
@@ -25,6 +19,12 @@ import "libs/farbtastic";
import "libs/jquery/jquery.form";
import "libs/jquery/jquery.rating";
import "ui/editable-text";
// trackster global variables
var ui = null;
var view = null;
var browser_router = null;
/**
* Base Object/Model for inhertiance.
*/
@@ -152,7 +152,7 @@ var TracksterUI = Base.extend({
title: _l("Bookmarks"),
on_click: function() {
// HACK -- use style to determine if panel is hidden and hide/show accordingly.
force_right_panel($("div#right").css("right") == "0px" ? "hide" : "show");
window.force_right_panel($("div#right").css("right") == "0px" ? "hide" : "show");
}
},
{
@@ -250,7 +250,7 @@ var TracksterUI = Base.extend({
// Create view.
var self = this;
var view = new tracks.TracksterView(_.extend(view_config, { header: false }));
view = new tracks.TracksterView(_.extend(view_config, { header: false }));
view.editor = true;
$.when(view.load_chroms_deferred).then(chrom_info => {
@@ -408,10 +408,10 @@ var TracksterView = Backbone.View.extend({
});
// hide right panel
force_right_panel("hide");
window.force_right_panel("hide");
// check if id is available
if (galaxy_config.app.id) {
if (window.galaxy_config.app.id) {
this.view_existing();
} else if (query_string.get("dataset_id")) {
this.choose_existing_or_new();
@@ -483,7 +483,7 @@ var TracksterView = Backbone.View.extend({
// view
view_existing: function() {
// get config
var viz_config = galaxy_config.app.viz_config;
var viz_config = window.galaxy_config.app.viz_config;
// view
view = ui.create_visualization(
@@ -533,8 +533,11 @@ var TracksterView = Backbone.View.extend({
// select default
var dbkeys_in_genomes = response.map(r => r[1]);
if (galaxy_config.app.default_dbkey && _.contains(dbkeys_in_genomes, galaxy_config.app.default_dbkey)) {
$("#new-dbkey").val(galaxy_config.app.default_dbkey);
if (
window.galaxy_config.app.default_dbkey &&
_.contains(dbkeys_in_genomes, window.galaxy_config.app.default_dbkey)
) {
$("#new-dbkey").val(window.galaxy_config.app.default_dbkey);
}
// change focus
@@ -588,7 +591,7 @@ var TracksterView = Backbone.View.extend({
name: name,
dbkey: dbkey
},
galaxy_config.app.gene_region
window.galaxy_config.app.gene_region
);
// initialize editor
@@ -604,9 +607,9 @@ var TracksterView = Backbone.View.extend({
$("#center .unified-panel-title").text(`${view.config.get_value("name")} (${view.dbkey})`);
// add dataset
if (galaxy_config.app.add_dataset)
if (window.galaxy_config.app.add_dataset)
$.ajax({
url: `${Galaxy.root}api/datasets/${galaxy_config.app.add_dataset}`,
url: `${Galaxy.root}api/datasets/${window.galaxy_config.app.add_dataset}`,
data: { hda_ldda: "hda", data_type: "track_config" },
dataType: "json",
success: function(track_data) {
+4 -2
View File
@@ -221,7 +221,9 @@
}
}
}
span.nametags {
div.nametags {
max-height:26px;
overflow-y: auto;
span.label {
display: inline-block;
margin-right: 2px;
@@ -698,4 +700,4 @@
margin-right: 8px;
}
}
}
}
+19 -58
View File
@@ -104,7 +104,7 @@ th.button_heading{
margin-right: 0.2em;
}
.toolbar-item{
margin-left: 1em;
margin-left: 0.5em;
}
}
#libraries_element, #folder_items_element{
@@ -112,7 +112,7 @@ th.button_heading{
margin-left: 0.5em;
}
}
.help-button{
.right-float{
float: right;
}
.pagination-sm{
@@ -128,11 +128,6 @@ th.button_heading{
.libimport-select-all{
margin-left: 0.5em;
}
.library-modal-item{
width:90%;
margin-left: 1em;
margin-right: 1em;
}
.paginator-bottom{
width: 27em;
margin-left: auto;
@@ -143,60 +138,26 @@ th.button_heading{
}
// Extra style for Galaxy modal
.modal-content #selected_history_content{
ul{
list-style-type: none;
.modal-content{
.library_selected_history_content{
ul{
list-style-type: none;
}
}
.library-collection-type-select, .library-collection-history-select{
margin-left:auto;
margin-right:auto;
width:200px;
min-width:200px;
}
.library-modal-item{
width:90%;
margin-left: auto;
margin-right: auto;
margin-top: 1.5em;
}
}
// Follows the style for the deprecated admin libraries interface
#library-grid{
ul{
list-style: none;
}
span.expandLink{
padding-left: 12px;
display: inline-block;
vertical-align: middle;
background: url(../images/silk/resultset_next.png) no-repeat;
}
.folderRow.expanded span.expandLink{
background: url(../images/silk/resultset_bottom.png) no-repeat;
}
.folderRow span.rowIcon{
float: left;
margin-right: 5px;
width: 16px;
height: 16px;
display: inline-block;
vertical-align: middle;
background: url(../images/silk/folder.png);
}
.libraryItem-error{
margin-right: 2px;
padding: 0 2px 0 2px;
border: 1px solid @state-danger-border;
background: @state-danger-bg;
}
.libraryItem-queued{
margin-right: 2px;
padding: 0 2px 0 2px;
border: 1px solid @state-default-border;
background: @state-default-bg;
}
.libraryItem-running{
margin-right: 2px;
padding: 0 2px 0 2px;
border: 1px solid @state-running-border;
background: @state-running-bg;
}
.libraryItem-upload{
margin-right: 2px;
padding: 0 2px 0 2px;
border: 1px solid @state-upload-border;
background: @state-upload-bg;
}
}
.libraryTitle{
th{
text-align: left;
-80
View File
@@ -1,80 +0,0 @@
/**
* Grunt task to fetch third-party libraries using bower and copy them to the proper location in client/.
* @param {Object} grunt main grunt file
* @return {Function} callback to build this task
*/
module.exports = function( grunt ){
"use strict";
var dev_path = './galaxy/scripts',
// where to move fetched bower components into the build structure (libName: [ bower-location, libs-location ])
libraryLocations = {
'farbtastic': [ 'src/farbtastic.js', 'farbtastic.js' ],
'bootstrap-tour': [ 'build/js/bootstrap-tour.js', 'bootstrap-tour.js' ],
// these need to be updated and tested
//'jquery-form': [ 'jquery.form.js', 'jquery/jquery.form.js' ],
//'jquery-autocomplete': [ 'src/jquery.autocomplete.js', 'jquery/jquery.autocomplete.js' ],
//'select2': [ 'select2.js', 'jquery/select2.js' ],
//'jStorage': [ 'jstorage.js', 'jquery/jstorage.js' ],
//'dynatree': [ 'dist/jquery.dynatree.js', 'jquery/jquery.dynatree.js' ],
//'jquery.event.drag-drop': [
// [ 'event.drag/jquery.event.drag.js', 'jquery/jquery.event.drag.js' ],
// [ 'event.drag/jquery.event.drop.js', 'jquery/jquery.event.drop.js' ]
//],
// these are complicated by additional css/less
//'toastr': [ 'toastr.js', 'toastr.js' ],
//'wymeditor': [ 'dist/wymeditor/jquery.wymeditor.js', 'jquery/jquery.wymeditor.js' ],
//'jstree': [ 'jstree.js', 'jquery/jstree.js' ],
// these have been customized by Galaxy
//'bootstrap': [ 'dist/js/bootstrap.js', 'bootstrap.js' ],
//'jquery-ui': [
// // multiple components now
// [ '', 'jquery/jquery-ui.js' ]
//],
};
// call bower to install libraries and other external resources
grunt.config( 'bower-install-simple', {
options: {
color: true
},
"prod": {
options: {
production: true
}
},
"dev": {
options: {
production: false
}
}
});
/** copy external libraries from bower components to scripts/libs */
function copyLibs(){
var lib_path = dev_path + '/libs/';
for( var libName in libraryLocations ){
if( libraryLocations.hasOwnProperty( libName ) ){
var bower_dir = 'bower_components',
location = libraryLocations[ libName ],
source = [ bower_dir, libName, location[0] ].join( '/' ),
destination = lib_path + location[1];
grunt.log.writeln( source + ' -> ' + destination );
grunt.file.copy( source, destination );
}
}
}
grunt.loadNpmTasks( 'grunt-bower-install-simple' );
grunt.registerTask( 'copy-libs', 'copy external libraries to src', copyLibs );
grunt.registerTask( 'install-libs', 'fetch external libraries and copy to src',
[ 'bower-install-simple:prod', 'copy-libs' ] );
};
-123
View File
@@ -1,123 +0,0 @@
/**
* Grunt task to compress/bundle static/scripts.
* @param {Object} grunt main grunt file
* @return {Function} callback to build this task
*/
module.exports = function( grunt ){
"use strict";
var app = grunt.config.get( 'app' ),
paths = grunt.config.get( 'paths' ),
// uglify settings used when scripts are decompressed/not-minified
decompressedSettings = {
mangle : false,
beautify : true,
compress : {
drop_debugger : false
}
},
// uglify settings used when scripts are compressed/minified
compressedSettings = {
mangle : {
screw_ie8 : true
},
compress : {
// high compression options
screw_ie8 : true,
sequences: true,
dead_code : true,
drop_debugger : true,
comparisons : true,
conditionals : true,
evaluate : true,
booleans : true,
loops : true,
unused : true,
hoist_funs : true,
if_return : true,
join_vars : true,
cascade : true,
}
};
grunt.config( 'uglify', {
target : {
files: [{
expand : true,
cwd : paths.srcSymlink,
// NOTE: do not use uglify in the apps dir (webpack will do that section)
src : [ '**/*.js', '!apps/**/*.js' ],
// src : '**/*.js',
dest : paths.dist
}],
}
});
if (grunt.option( 'develop' )){
grunt.config( 'uglify.options', decompressedSettings );
} else {
grunt.config( 'uglify.target.options', {
sourceMap : true,
sourceMapName : function( path ){
// rewrite name to have all source maps in 'static/maps'
return path.replace( paths.dist, paths.maps ) + '.map';
}
});
grunt.config( 'uglify.options', compressedSettings );
}
// -------------------------------------------------------------------------- decompress for easier debugging
grunt.registerTask( 'decompress', function(){
grunt.log.writeln( "decompressing... (don't forget to call 'grunt' again before committing)" );
grunt.config( 'uglify.options', decompressedSettings );
grunt.config( 'uglify.target.options', {});
grunt.task.run( 'uglify' );
});
// alias for symmetry
grunt.registerTask( 'compress', [ 'uglify' ] );
// -------------------------------------------------------------------------- watch & copy,pack only those changed
// use 'grunt watch' (from a new tab in your terminal) to have grunt re-copy changed files automatically
grunt.config( 'watch', {
watch: {
// watch for changes in the src dir
// NOTE: but not in the apps dir (which is only used by webpack)
files: [ paths.srcSymlink + '/**', '!' + paths.srcSymlink + '/apps/**' ],
tasks: [ 'uglify' ],
options: {
spawn: false
}
}
});
// outer scope variable for the event handler and onChange fn - begin with empty hash
var changedFiles = Object.create(null);
// when files are changed, set the copy src and packScripts target to the filenames of the updated files
var onChange = grunt.util._.debounce(function() {
grunt.log.writeln( 'onChange, changedFiles:', Object.keys( changedFiles ) );
grunt.config( 'uglify.target.files', [{
expand : true,
cwd : paths.srcSymlink,
src : Object.keys( changedFiles ),
dest : paths.dist
}]);
changedFiles = Object.create(null);
}, 200);
var addChangedFile = function( action, filepath ) {
// store each filepath in a Files obj, the debounced fn above will use it as an aggregate list for copying
// we need to take galaxy/scripts out of the filepath or it will be copied to the wrong loc
filepath = filepath.replace( paths.srcSymlink + '/', '' );
// grunt.log.writeln( 'on.watch, filepath:', filepath );
changedFiles[ filepath ] = action;
onChange();
};
grunt.event.on( 'watch', addChangedFile );
// --------------------------------------------------------------------------
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
};
@@ -1,146 +0,0 @@
define([
"libs/toastr",
"toolshed/scripts/mvc/groups/group-model"
],
function(
mod_toastr,
mod_group_model
) {
// toolshed group detail view
var GroupDetailView = Backbone.View.extend({
el: "#groups_element",
options: {},
app: null,
initialize : function( options ){
this.options = _.extend( this.options, options );
this.app = window.globalTS.groups;
if ( this.app.collection !== null ){
this.model = this.app.collection.get( this.options.group_id );
this.render();
} else {
this.fetchGroup();
}
},
fetchGroup: function( options ){
var that = this;
this.options = _.extend( this.options, options );
this.model = new mod_group_model.Group( { id: this.options.group_id } );
this.model.fetch({
success: function( model ){
console.log( 'received data: ' );
console.log( model );
that.render();
},
error: function( model, response ){
if ( typeof response.responseJSON !== "undefined" ){
mod_toastr.error( response.responseJSON.err_msg );
} else {
mod_toastr.error( 'An error occurred.' );
}
}
});
},
render: function(){
var template = this.templateRow();
this.$el.html( template( { group: this.model } ) );
$( "#center [data-toggle]" ).tooltip();
$( "#center" ).css( 'overflow','auto' );
},
templateRow: function() {
return _.template([
'<div>',
'<h3><%= _.escape(group.get("name")) %></h3>',
'<p class="" style="color:gray;">',
'A group of <%= group.get("members").length %> members with <%= group.get("repositories").length %> repositories and a total of <%= group.get("total_downloads") %> combined repository clones.</p>',
'<h3>Members</h3>',
'<table class="grid table table-condensed">',
'<thead>',
'<th>Name</th>',
'<th>Repositories</th>',
'<th>Registered</th>',
'</thead>',
'<tbody>',
'<% _.each(group.get("members"), function(member) { %>',
'<tr>',
'<td>',
'<%= _.escape(member.username) %>',
'</td>',
'<td>',
'<a data-toggle="tooltip" data-placement="top" title="Repositories of <%= _.escape(member.username) %>" href="/repository/browse_repositories_by_user?user_id=<%= member.id %>&use_panels=true" id="<%= member.id %>"><%= member.user_repos_count %></a>',
'</td>',
'<td>',
'<%= member.time_created %>',
'</td>',
'</tr>',
'<% }); %>',
'</tbody>',
'</table>',
'<h3>Repositories</h3>',
'<table class="grid table table-condensed">',
'<thead>',
'<th>Name</th>',
'<th>Description</th>',
'<th>Clones</th>',
'<th>Owner</th>',
'<th>Categories</th>',
'<th>Created</th>',
'<th>Updated</th>',
'<th>Rating</th>',
'<th>Verified</th>',
'</thead>',
'<tbody>',
'<% _.each(group.get("repositories"), function(repo) { %>',
'<tr>',
'<td>',
'<a data-toggle="tooltip" data-placement="top" title="Details of <%= _.escape(repo.name) %>" href="/view/<%= _.escape(repo.owner) %>/<%= _escape(repo.name) %>" id="<%= repo.id %>"><%= _.escape(repo.name) %></a>',
'</td>',
'<td>',
'<%= _.escape(repo.description) %>',
'</td>',
'<td>',
'<%= repo.times_downloaded %>',
'</td>',
'<td>',
'<%= _.escape(repo.owner) %>',
'</td>',
'<td>',
'<% _.each((repo.categories), function(cat) { %>',
'<a data-toggle="tooltip" data-placement="top" title="Repositories in <%= cat.name %>" href="/repository/browse_repositories_in_category?id=<%= cat.id %>&use_panels=true"><%= cat.name %></a><br/>',
// '<%= repo.categories %>',
'<% }); %>',
'</td>',
'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_created_full %>">',
'<%= repo.time_created %>',
'</td>',
'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_updated_full %>">',
'<%= repo.time_updated %>',
'</td>',
'<td>',
'<%= repo.ratings_mean %>',
'</td>',
'<td>',
'<%= repo.approved %>',
'</td>',
'</tr>',
'<% }); %>',
'</tbody>',
'</table>',
'</div>'
].join(''));
}
});
return {
GroupDetailView: GroupDetailView
};
});
@@ -1,141 +0,0 @@
define([
"libs/toastr",
"toolshed/scripts/mvc/groups/group-model",
"toolshed/scripts/mvc/groups/group-listrow-view"
], function(
mod_toastr,
mod_group_model,
mod_group_row
){
var GroupListView = Backbone.View.extend({
el: '#groups_element',
defaults: {},
/**
* Initialize and fetch the groups from server.
* Async render afterwards.
* @param {object} options an object with options
*/
initialize : function( options ){
this.options = _.defaults( this.options || {}, this.defaults, options );
var that = this;
window.globalTS.groups.collection = new mod_group_model.Groups();
window.globalTS.groups.collection.fetch({
success: function( model ){
console.log( 'received data: ' );
console.log( model );
that.render();
},
error: function( model, response ){
if ( typeof response.responseJSON !== "undefined" ){
mod_toastr.error( response.responseJSON.err_msg );
} else {
mod_toastr.error( 'An error occurred.' );
}
}
});
},
fetch: function(){
},
/**
* Render the groups table from the object's own collection.
*/
render: function ( options ) {
this.options = _.extend( this.options, options );
$( ".tooltip" ).hide();
var template = this.templateGroupsList();
this.$el.html( template( { length: window.globalTS.groups.collection.models.length } ) );
this.renderRows( window.globalTS.groups.collection.models );
$( "#center [data-toggle]" ).tooltip();
$( "#center" ).css( 'overflow','auto' );
},
/**
* Render all given models as rows in the groups list
* @param {array} groups_to_render array of group models to render
*/
renderRows: function( groups_to_render ){
for ( var i = 0; i < groups_to_render.length; i++ ) {
var group = groups_to_render[i];
this.renderOne( { group: group } )
}
},
/**
* Create a view for the given model and add it to the groups view.
* @param {Group} model of the view that will be rendered
*/
renderOne: function( options ){
var rowView = new mod_group_row.GroupListRowView( options );
this.$el.find( '#group_list_body' ).append( rowView.el );
},
/**
* Table heading was clicked, update sorting preferences and re-render.
* @return {[type]} [description]
*/
// sort_clicked : function(){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// Galaxy.libraries.preferences.set({'sort_order': 'desc'});
// } else {
// Galaxy.libraries.preferences.set({'sort_order': 'asc'});
// }
// this.render();
// },
/**
* Sort the underlying collection according to the parameters received.
* Currently supports only sorting by name.
*/
// sortLibraries: function(){
// if (Galaxy.libraries.preferences.get('sort_by') === 'name'){
// if (Galaxy.libraries.preferences.get('sort_order') === 'asc'){
// this.collection.sortByNameAsc();
// } else if (Galaxy.libraries.preferences.get('sort_order') === 'desc'){
// this.collection.sortByNameDesc();
// }
// }
// },
// MMMMMMMMMMMMMMMMMM
// === TEMPLATES ====
// MMMMMMMMMMMMMMMMMM
templateGroupsList: function(){
var tmpl_array = [];
tmpl_array.push('<div id="groups">');
tmpl_array.push('</div>');
tmpl_array.push('<div class="groups_container table-responsive">');
tmpl_array.push('<% if(length === 0) { %>');
tmpl_array.push('<div>There are no groups yet.</div>');
tmpl_array.push('<% } else{ %>');
tmpl_array.push('<table class="grid table table-condensed">');
tmpl_array.push(' <thead>');
tmpl_array.push(' <th>Name</th>');
// tmpl_array.push(' <th style="width:22%;">description</th>');
tmpl_array.push(' <th>Members</th> ');
tmpl_array.push(' <th>Repositories</th>');
tmpl_array.push(' </thead>');
tmpl_array.push(' <tbody id="group_list_body">');
// group item views will attach here
tmpl_array.push(' </tbody>');
tmpl_array.push('</table>');
tmpl_array.push('<% }%>');
tmpl_array.push('</div>');
return _.template(tmpl_array.join(''));
},
});
return {
GroupListView: GroupListView
};
});
@@ -1,22 +0,0 @@
define([], function() {
// ============================================================================
// TS GROUP RELATED MODELS
var Group = Backbone.Model.extend({
urlRoot: Galaxy.root + 'api/groups',
});
var Groups = Backbone.Collection.extend({
url: Galaxy.root + 'api/groups',
model: Group,
});
return {
Group: Group,
Groups: Groups
};
});
@@ -1,51 +0,0 @@
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
// === MAIN TOOLSHED GROUP MODULE ====
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
define([
'toolshed/scripts/mvc/groups/group-list-view',
'toolshed/scripts/mvc/groups/group-detail-view',
'toolshed/scripts/mvc/groups/group-model'
],
function(
mod_group_list,
mod_group_detail,
mod_group_model
) {
// ============================================================================
// ROUTER
var ToolshedRouter = Backbone.Router.extend({
routes: {
"" : "groups",
":group_id" : "group_page"
}
});
var ToolshedGroups = Backbone.View.extend({
groupListView: null,
groupDetailView: null,
collection: null,
initialize : function(){
window.globalTS.groups = this;
this.ts_router = new ToolshedRouter();
this.ts_router.on( 'route:groups', function() {
window.globalTS.groups.groupListView = new mod_group_list.GroupListView();
});
this.ts_router.on( 'route:group_page', function( group_id ) {
window.globalTS.groups.groupDetailView = new mod_group_detail.GroupDetailView( { group_id: group_id } );
});
Backbone.history.start({pushState: false});
}
});
return {
ToolshedGroups: ToolshedGroups
};
});
+5
View File
@@ -920,6 +920,11 @@ use_interactive = True
# create symlinks to them).
#user_library_import_symlink_whitelist = None
# In conjunction or alternatively, Galaxy can restrict user library imports to
# those files that the user can read (by checking basic unix permissions).
# For this to work, the username has to match the username on the filesystem.
#user_library_import_check_permissions = False
# Allow admins to paste filesystem paths during upload. For libraries this
# adds an option to the admin library upload tool allowing admins to paste
# filesystem paths to files and directories in a box, and these paths will be
+87 -30
View File
@@ -8,6 +8,11 @@ import os.path
from markupsafe import escape
from galaxy import util
from galaxy.exceptions import (
AdminRequiredException,
ConfigDoesNotAllowException,
RequestParameterInvalidException,
)
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import populate_state
from galaxy.util.path import (
@@ -19,6 +24,47 @@ from galaxy.util.path import (
log = logging.getLogger(__name__)
def validate_server_directory_upload(trans, server_dir):
if server_dir in [None, 'None', '']:
raise RequestParameterInvalidException("Invalid or unspecified server_dir parameter")
if trans.user_is_admin():
import_dir = trans.app.config.library_import_dir
import_dir_desc = 'library_import_dir'
if not import_dir:
raise ConfigDoesNotAllowException('"library_import_dir" is not set in the Galaxy configuration')
else:
import_dir = trans.app.config.user_library_import_dir
if not import_dir:
raise ConfigDoesNotAllowException('"user_library_import_dir" is not set in the Galaxy configuration')
if server_dir != trans.user.email:
import_dir = os.path.join(import_dir, trans.user.email)
import_dir_desc = 'user_library_import_dir'
full_dir = os.path.join(import_dir, server_dir)
unsafe = None
if safe_relpath(server_dir):
username = trans.user.username if trans.app.config.user_library_import_check_permissions else None
if import_dir_desc == 'user_library_import_dir' and safe_contains(import_dir, full_dir, whitelist=trans.app.config.user_library_import_symlink_whitelist, username=username):
for unsafe in unsafe_walk(full_dir, whitelist=[import_dir] + trans.app.config.user_library_import_symlink_whitelist):
log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', unsafe, os.path.realpath(unsafe))
else:
log.error('User attempted to import a directory path that resolves to a path outside of their import dir: %s -> %s', server_dir, os.path.realpath(full_dir))
unsafe = True
if unsafe:
raise RequestParameterInvalidException("Invalid server_dir specified")
return full_dir, import_dir_desc
def validate_path_upload(trans):
if not trans.app.config.allow_library_path_paste:
raise ConfigDoesNotAllowException('"allow_path_paste" is not set to True in the Galaxy configuration file')
if not trans.user_is_admin():
raise AdminRequiredException('Uploading files via filesystem paths can only be performed by administrators')
class LibraryActions(object):
"""
Mixin for controllers that provide library functionality.
@@ -42,37 +88,11 @@ class LibraryActions(object):
upload_option = kwd.get('upload_option', 'upload_file')
response_code = 200
if upload_option == 'upload_directory':
if server_dir in [None, 'None', '']:
response_code = 400
if trans.user_is_admin():
import_dir = trans.app.config.library_import_dir
import_dir_desc = 'library_import_dir'
else:
import_dir = trans.app.config.user_library_import_dir
if server_dir != trans.user.email:
import_dir = os.path.join(import_dir, trans.user.email)
import_dir_desc = 'user_library_import_dir'
full_dir = os.path.join(import_dir, server_dir)
unsafe = None
if safe_relpath(server_dir):
if import_dir_desc == 'user_library_import_dir' and safe_contains(import_dir, full_dir, whitelist=trans.app.config.user_library_import_symlink_whitelist):
for unsafe in unsafe_walk(full_dir, whitelist=[import_dir] + trans.app.config.user_library_import_symlink_whitelist):
log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', unsafe, os.path.realpath(unsafe))
else:
log.error('User attempted to import a directory path that resolves to a path outside of their import dir: %s -> %s', server_dir, os.path.realpath(full_dir))
unsafe = True
if unsafe:
response_code = 403
message = 'Invalid server_dir'
if import_dir:
message = 'Select a directory'
else:
response_code = 403
message = '"%s" is not defined in the Galaxy configuration file' % import_dir_desc
full_dir, import_dir_desc = validate_server_directory_upload(trans, server_dir)
message = 'Select a directory'
elif upload_option == 'upload_paths':
if not trans.app.config.allow_library_path_paste:
response_code = 403
message = '"allow_library_path_paste" is not defined in the Galaxy configuration file'
# Library API already checked this - following check isn't actually needed.
validate_path_upload(trans)
# Some error handling should be added to this method.
try:
# FIXME: instead of passing params here ( which have been processed by util.Params(), the original kwd
@@ -118,6 +138,43 @@ class LibraryActions(object):
uploaded_datasets.append(self._make_library_uploaded_dataset(trans, params, name, file, 'server_dir', library_bunch))
return uploaded_datasets, 200, None
def _get_server_dir_files(self, params, full_dir, import_dir_desc):
files = []
try:
for entry in os.listdir(full_dir):
# Only import regular files
path = os.path.join(full_dir, entry)
link_data_only = params.get('link_data_only', 'copy_files')
if os.path.islink(full_dir) and link_data_only == 'link_to_files':
# If we're linking instead of copying and the
# sub-"directory" in the import dir is actually a symlink,
# dereference the symlink, but not any of its contents.
link_path = os.readlink(full_dir)
if os.path.isabs(link_path):
path = os.path.join(link_path, entry)
else:
path = os.path.abspath(os.path.join(link_path, entry))
elif os.path.islink(path) and os.path.isfile(path) and link_data_only == 'link_to_files':
# If we're linking instead of copying and the "file" in the
# sub-directory of the import dir is actually a symlink,
# dereference the symlink (one dereference only, Vasili).
link_path = os.readlink(path)
if os.path.isabs(link_path):
path = link_path
else:
path = os.path.abspath(os.path.join(os.path.dirname(path), link_path))
if os.path.isfile(path):
files.append(path)
except Exception as e:
message = "Unable to get file list for configured %s, error: %s" % (import_dir_desc, str(e))
response_code = 500
return None, response_code, message
if not files:
message = "The directory '%s' contains no valid files" % full_dir
response_code = 400
return None, response_code, message
return files, None, None
def _get_path_paste_uploaded_datasets(self, trans, params, library_bunch, response_code, message):
preserve_dirs = util.string_as_bool(params.get('preserve_dirs', False))
uploaded_datasets = []
+1
View File
@@ -426,6 +426,7 @@ class Configuration(object):
self.library_import_dir = kwargs.get('library_import_dir', None)
self.user_library_import_dir = kwargs.get('user_library_import_dir', None)
self.user_library_import_symlink_whitelist = listify(kwargs.get('user_library_import_symlink_whitelist', []), do_strip=True)
self.user_library_import_check_permissions = string_as_bool(kwargs.get('user_library_import_check_permissions', False))
# Searching data libraries
self.ftp_upload_dir = kwargs.get('ftp_upload_dir', None)
self.ftp_upload_dir_identifier = kwargs.get('ftp_upload_dir_identifier', 'email') # attribute on user - email, username, id, etc...
+1 -1
View File
@@ -530,7 +530,7 @@ def build_isolated_environment(
# - https://github.com/galaxyproject/galaxy/issues/3635
# - https://github.com/conda/conda/issues/2035
offline_works = (conda_context.conda_version < LooseVersion("4.3")) or \
(conda_context.conda_version >= LooseVersion("4.3.18"))
(conda_context.conda_version >= LooseVersion("4.4"))
if offline_works:
create_args.extend(["--offline"])
else:
+75 -6
View File
@@ -4,16 +4,20 @@ from __future__ import absolute_import
import errno
import imp
import logging
from functools import partial
from grp import getgrgid
from itertools import starmap
from operator import getitem
from os import (
extsep,
makedirs,
walk,
stat,
walk
)
from os.path import (
abspath,
dirname,
exists,
isabs,
join,
@@ -21,10 +25,13 @@ from os.path import (
pardir,
realpath,
relpath,
sep as separator,
)
from pwd import getpwuid
from six import iteritems, string_types
from six.moves import filterfalse, map, zip
from six.moves import map, zip
log = logging.getLogger(__name__)
def safe_contains(prefix, path, whitelist=None):
@@ -82,7 +89,7 @@ def safe_relpath(path):
return not (isabs(path) or normpath(path).startswith(pardir))
def unsafe_walk(path, whitelist=None):
def unsafe_walk(path, whitelist=None, username=None):
"""Walk a path and ensure that none of its contents are symlinks outside the path.
It is assumed that ``path`` itself has already been validated e.g. with :func:`safe_relpath` or
@@ -92,10 +99,72 @@ def unsafe_walk(path, whitelist=None):
:param path: a directory to check for unsafe contents
:type whitelist: list of strings
:param whitelist: list of additional paths under which contents may be located
:rtype: iterator
:returns: Iterator of "bad" files found under ``path``
:rtype: list of strings
:returns: A list of "bad" files found under ``path``
"""
return filterfalse(partial(safe_contains, path, whitelist=whitelist), __walk(abspath(path)))
unsafe_paths = []
for walked_path in __walk(abspath(path)):
is_safe = safe_contains(path, walked_path, whitelist=whitelist)
if username and is_safe:
is_safe = full_path_permission_for_user(path, walked_path, username=username, skip_prefix=True)
if not is_safe:
unsafe_paths.append(walked_path)
return unsafe_paths
def __path_permission_for_user(path, username):
"""
:type path: string
:param path: a directory or file to check
:type username: string
:param username: a username matching the systems username
"""
group_id_of_file = stat(path).st_gid
file_owner = getpwuid(stat(path).st_uid)
group_members = getgrgid(group_id_of_file).gr_mem
oct_mode = oct(stat(path).st_mode)
owner_permissions = int(oct_mode[-3])
group_permissions = int(oct_mode[-2])
other_permissions = int(oct_mode[-1])
if other_permissions >= 4 or \
(file_owner == username and owner_permissions >= 4) or \
(username in group_members and group_permissions >= 4):
return True
return False
def full_path_permission_for_user(prefix, path, username, skip_prefix=False):
"""
Assuming username is identical to the os username, this checks that the
given user can read the specified path by checking the file permission
and each parent directory permission.
:type prefix: string
:param prefix: a directory under which ``path`` is to be checked
:type path: string
:param path: a filename to check
:type username: string
:param username: a username matching the systems username
:type skip_prefix: bool
:param skip_prefix: skip the given prefix from being checked for permissions
"""
full_path = realpath(join(prefix, path))
top_path = realpath(prefix) if skip_prefix else None
can_read = __path_permission_for_user(full_path, username)
if can_read:
depth = 0
max_depth = full_path.count(separator)
parent_path = dirname(full_path)
while can_read and depth != max_depth:
if parent_path in [separator, top_path]:
break
if not __path_permission_for_user(parent_path, username):
can_read = False
depth += 1
parent_path = dirname(parent_path)
return can_read
def joinext(root, ext):
@@ -12,9 +12,8 @@ from galaxy import (
exceptions,
managers,
util,
web
)
from galaxy.actions.library import LibraryActions
from galaxy.actions.library import LibraryActions, validate_path_upload
from galaxy.managers.collections_util import (
api_payload_to_create_params,
dictify_dataset_collection_instance
@@ -158,7 +157,7 @@ class LibraryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
rval['parent_library_id'] = trans.security.encode_id(rval['parent_library_id'])
return rval
@web.expose_api
@expose_api
def create(self, trans, library_id, payload, **kwd):
"""
create( self, trans, library_id, payload, **kwd )
@@ -314,12 +313,8 @@ class LibraryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
if folder and last_used_build in ['None', None, '?']:
last_used_build = folder.genome_build
error = False
if upload_option == 'upload_paths' and not trans.app.config.allow_library_path_paste:
error = True
message = '"allow_library_path_paste" is not defined in the Galaxy configuration file'
elif upload_option == 'upload_paths' and not is_admin:
error = True
message = 'Uploading files via filesystem paths can only be performed by administrators'
if upload_option == 'upload_paths':
validate_path_upload(trans) # Duplicate check made in _upload_dataset.
elif upload_option not in ('upload_file', 'upload_directory', 'upload_paths'):
error = True
message = 'Invalid upload_option'
@@ -373,7 +368,7 @@ class LibraryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
# for cross type comparisions, ie "True" == True
yield prefix, ("%s" % (meta)).encode("utf8", errors='replace')
@web.expose_api
@expose_api
def update(self, trans, id, library_id, payload, **kwd):
"""
update( self, trans, id, library_id, payload, **kwd )
@@ -411,7 +406,7 @@ class LibraryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
else:
raise HTTPBadRequest('Malformed library content id ( %s ) specified, unable to decode.' % str(content_id))
@web.expose_api
@expose_api
def delete(self, trans, library_id, id, **kwd):
"""
delete( self, trans, library_id, id, **kwd )
@@ -25,7 +25,7 @@ from galaxy.managers import (
)
from galaxy.tools.actions import upload_common
from galaxy.tools.parameters import populate_state
from galaxy.util.path import safe_contains, safe_relpath, unsafe_walk
from galaxy.util.path import full_path_permission_for_user, safe_contains, safe_relpath, unsafe_walk
from galaxy.util.streamball import StreamBall
from galaxy.web import (
_future_expose_api as expose_api,
@@ -432,20 +432,30 @@ class LibraryDatasetsController(BaseAPIController, UsesVisualizationMixin, Libra
path = os.path.join(import_base_dir, path)
elif source in ['userdir_file', 'userdir_folder']:
unsafe = None
username = trans.user.username if trans.app.config.user_library_import_check_permissions else None
user_login = trans.user.email
user_base_dir = trans.app.config.user_library_import_dir
if user_base_dir is None:
raise exceptions.ConfigDoesNotAllowException('The configuration of this Galaxy instance does not allow upload from user directories.')
full_dir = os.path.join(user_base_dir, user_login)
if not safe_contains(full_dir, path, whitelist=trans.app.config.user_library_import_symlink_whitelist):
# the path is a symlink outside the user dir
path = os.path.join(full_dir, path)
log.error('User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', path, os.path.realpath(path))
raise exceptions.RequestParameterInvalidException('The given path is invalid.')
if trans.app.config.user_library_import_check_permissions and not full_path_permission_for_user(full_dir, path, username):
log.error('User attempted to import a path that resolves to a path outside of their import dir: '
'%s -> %s and cannot be read by them.', path, os.path.realpath(path))
raise exceptions.RequestParameterInvalidException('The given path is invalid.')
path = os.path.join(full_dir, path)
for unsafe in unsafe_walk(path, whitelist=[full_dir] + trans.app.config.user_library_import_symlink_whitelist):
for unsafe in unsafe_walk(path, whitelist=[full_dir] + trans.app.config.user_library_import_symlink_whitelist, username=username):
# the path is a dir and contains files that symlink outside the user dir
log.error('User attempted to import a directory containing a path that resolves to a path outside of their import dir: %s -> %s', unsafe, os.path.realpath(unsafe))
error = 'User attempted to import a path that resolves to a path outside of their import dir: %s -> %s', \
path, os.path.realpath(path)
if trans.app.config.user_library_import_check_permissions:
error += ' or is not readable for them.'
log.error(error)
if unsafe:
raise exceptions.RequestParameterInvalidException('The given path is invalid.')
if not os.path.exists(path):
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
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
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("galaxy",["exports","libs/underscore","libs/backbone","mvc/base-mvc","mvc/user/user-model","utils/metrics-logger","utils/add-logging","utils/localization"],function(e,t,o,a,r,n,l,i){"use strict";function g(e){return e&&e.__esModule?e:{default:e}}function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t.default=e,t}function c(e,t){return this._init(e||{},t||{})}Object.defineProperty(e,"__esModule",{value:!0});var u=s(t),p=s(o),f=g(a),d=g(r),y=g(n),b=g(l),v=g(i);(0,b.default)(c,"GalaxyApp");var m="galaxy:debug:namespaces",_=!1;try{_="true"==localStorage.getItem("galaxy:debug")}catch(e){console.log((0,v.default)("localStorage not available for debug flag retrieval"))}c.prototype._init=function(e,t){var o=this;return u.extend(o,p.Events),_&&(o.logger=console,console.debug("debugging galaxy:","options:",e,"bootstrapped:",t)),o._processOptions(e),o.root=e.root||"/",o.params=e.params||{},o.session_csrf_token=e.session_csrf_token||null,o._initConfig(e.config||{}),o._patchGalaxy(window.Galaxy),o._initLogger(o.options.loggerOptions||{}),o.debug("GalaxyApp.options: ",o.options),o.debug("GalaxyApp.config: ",o.config),o.debug("GalaxyApp.logger: ",o.logger),o._initLocale(),o.debug("GalaxyApp.localize: ",o.localize),o.config=e.config||{},o.debug("GalaxyApp.config: ",o.config),o._initUser(e.user||{}),o.debug("GalaxyApp.user: ",o.user),o._setUpListeners(),o.trigger("ready",o),o},c.prototype.defaultOptions={patchExisting:!0,root:"/",session_csrf_token:null},c.prototype._processOptions=function(e){var t=this,o=t.defaultOptions;t.options={};for(var a in o)o.hasOwnProperty(a)&&(t.options[a]=e.hasOwnProperty(a)?e[a]:o[a]);return t},c.prototype._initConfig=function(e){var t=this;return t.config=e,t.config.debug=_||t.config.debug,t},c.prototype._patchGalaxy=function(e){var t=this;if(t.options.patchExisting&&e)for(var o in e)e.hasOwnProperty(o)&&(t[o]=e[o])},c.prototype._initLogger=function(e){var t=this;if(t.config.debug){e.consoleLogger=e.consoleLogger||console,e.consoleLevel=e.consoleLevel||y.default.MetricsLogger.ALL;try{e.consoleNamespaceWhitelist=localStorage.getItem(m).split(",")}catch(e){}try{e.consoleFlattenMessages="true"==localStorage.getItem("galaxy:debug:flatten")}catch(e){}console.log(e.consoleFlattenMessages)}return t.logger=new y.default.MetricsLogger(e),t.emit={},["log","debug","info","warn","error","metric"].map(function(e){t.emit[e]=function(o){t.logger.emit(e,arguments[0],Array.prototype.slice.call(arguments,1))}}),t.config.debug&&(f.default.LoggableMixin.logger=t.logger),t},c.prototype._initLocale=function(e){var t=this;return t.debug("_initLocale:",e),t.localize=v.default,window._l=t.localize,t},c.prototype._initUser=function(e){var t=this;return t.debug("_initUser:",e),t.user=new d.default.User(e),t.user.logger=t.logger,t},c.prototype._setUpListeners=function(){var e=this;return e.lastAjax={},$(document).bind("ajaxSend",function(t,o,a){var r=a.data;try{r=JSON.parse(r)}catch(e){}e.lastAjax={url:location.href.slice(0,-1)+a.url,data:r}}),e},c.prototype.debugging=function(e){var t=this;try{if(void 0===e)return"true"===localStorage.getItem("galaxy:debug");if(e)return localStorage.setItem("galaxy:debug",!0),!0;localStorage.removeItem("galaxy:debug"),t.debuggingNamespaces(null)}catch(e){console.log((0,v.default)("localStorage not available for debug flag retrieval"))}return!1},c.prototype.debuggingNamespaces=function(e){var t=this;try{if(void 0===e){var o=localStorage.getItem(m);return"string"==typeof o?o.split(","):[]}null===e?localStorage.removeItem(m):localStorage.setItem(m,e);var a=t.debuggingNamespaces();return t.logger&&(t.logger.options.consoleNamespaceWhitelist=a),a}catch(e){console.log((0,v.default)("localStorage not available for debug namespace retrieval"))}},c.prototype.toString=function(){return"GalaxyApp("+(this.user?this.user.get("email")||"(anonymous)":"uninitialized")+")"},e.default={GalaxyApp:c}});
define("galaxy",["exports","libs/underscore","libs/backbone","mvc/base-mvc","mvc/user/user-model","utils/metrics-logger","utils/add-logging","utils/localization"],function(e,t,o,a,r,n,l,i){"use strict";function g(e){return e&&e.__esModule?e:{default:e}}function s(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t.default=e,t}function c(e,t){return this._init(e||{},t||{})}Object.defineProperty(e,"__esModule",{value:!0});var u=s(t),p=s(o),f=g(a),d=g(r),y=g(n),b=g(l),v=g(i);(0,b.default)(c,"GalaxyApp");var m="galaxy:debug:namespaces",_=!1;try{_="true"==localStorage.getItem("galaxy:debug")}catch(e){console.log((0,v.default)("localStorage not available for debug flag retrieval"))}c.prototype._init=function(e,t){var o=this;return u.extend(o,p.Events),_&&(o.logger=console,console.debug("debugging galaxy:","options:",e,"bootstrapped:",t)),o._processOptions(e),o.root=e.root||"/",o.params=e.params||{},o.session_csrf_token=e.session_csrf_token||null,o._initConfig(e.config||{}),o._patchGalaxy(window.Galaxy),o._initLogger(o.options.loggerOptions||{}),o.debug("GalaxyApp.options: ",o.options),o.debug("GalaxyApp.config: ",o.config),o.debug("GalaxyApp.logger: ",o.logger),o._initLocale(),o.debug("GalaxyApp.localize: ",o.localize),o.config=e.config||{},o.debug("GalaxyApp.config: ",o.config),o._initUser(e.user||{}),o.debug("GalaxyApp.user: ",o.user),o._setUpListeners(),o.trigger("ready",o),o},c.prototype.defaultOptions={patchExisting:!0,root:"/",session_csrf_token:null},c.prototype._processOptions=function(e){var t=this,o=t.defaultOptions;t.options={};for(var a in o)o.hasOwnProperty(a)&&(t.options[a]=e.hasOwnProperty(a)?e[a]:o[a]);return t},c.prototype._initConfig=function(e){var t=this;return t.config=e,t.config.debug=_||t.config.debug,t},c.prototype._patchGalaxy=function(e){var t=this;if(t.options.patchExisting&&e)for(var o in e)e.hasOwnProperty(o)&&(t[o]=e[o])},c.prototype._initLogger=function(e){var t=this;if(t.config.debug){e.consoleLogger=e.consoleLogger||console,e.consoleLevel=e.consoleLevel||y.default.MetricsLogger.ALL;try{e.consoleNamespaceWhitelist=localStorage.getItem(m).split(",")}catch(e){}try{e.consoleFlattenMessages="true"==localStorage.getItem("galaxy:debug:flatten")}catch(e){}console.log(e.consoleFlattenMessages)}return t.logger=new y.default.MetricsLogger(e),t.emit={},["log","debug","info","warn","error","metric"].map(function(e){t.emit[e]=function(o){t.logger.emit(e,arguments[0],Array.prototype.slice.call(arguments,1))}}),t.config.debug&&(f.default.LoggableMixin.logger=t.logger),t},c.prototype._initLocale=function(e){var t=this;return t.debug("_initLocale:",e),t.localize=v.default,window._l=t.localize,t},c.prototype._initUser=function(e){var t=this;return t.debug("_initUser:",e),t.user=new d.default.User(e),t.user.logger=t.logger,t},c.prototype._setUpListeners=function(){var e=this;return e.lastAjax={},$(document).bind("ajaxSend",function(t,o,a){var r=a.data;try{r=JSON.parse(r)}catch(e){}e.lastAjax={url:location.href.slice(0,-1)+a.url,data:r}}),e},c.prototype.debugging=function(e){var t=this;try{if(void 0===e)return"true"===localStorage.getItem("galaxy:debug");if(e)return localStorage.setItem("galaxy:debug",!0),!0;localStorage.removeItem("galaxy:debug"),t.debuggingNamespaces(null)}catch(e){console.log((0,v.default)("localStorage not available for debug flag retrieval"))}return!1},c.prototype.debuggingNamespaces=function(e){var t=this;try{if(void 0===e){var o=localStorage.getItem(m);return"string"==typeof o?o.split(","):[]}null===e?localStorage.removeItem(m):localStorage.setItem(m,e);var a=t.debuggingNamespaces();return t.logger&&(t.logger.options.consoleNamespaceWhitelist=a),a}catch(e){console.log((0,v.default)("localStorage not available for debug namespace retrieval"))}},c.prototype.toString=function(){return"GalaxyApp("+(this.user?this.user.get("email")||"(anonymous)":"uninitialized")+")"},window.Galaxy=window.Galaxy||new c,e.default={GalaxyApp:c}});
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("layout/router",["exports","jquery","utils/query-string-parsing","mvc/ui/ui-misc"],function(e,t,i,a){"use strict";function s(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var u=s(t),n=s(i),r=s(a),o=u.default,c=Backbone.Router.extend({initialize:function(e,t){this.page=e,this.options=t},push:function(e,t){(t=t||{}).__identifer=Math.random().toString(36).substr(2),o.isEmptyObject(t)||(e+=-1==e.indexOf("?")?"?":"&",e+=o.param(t,!0)),Galaxy.params=t,this.navigate(e,{trigger:!0})},execute:function(e,t,i){Galaxy.debug("router execute:",e,t,i);var a=n.default.parse(t.pop());t.push(a),e&&(this.authenticate(t,i)?e.apply(this,t):this.access_denied())},authenticate:function(e,t){return!0},access_denied:function(){this.page.display(new r.default.Message({status:"danger",message:"You must be logged in with proper credentials to make this request.",persistent:!0}))}});e.default=c});
define("layout/router",["exports","jquery","utils/query-string-parsing","mvc/ui/ui-misc"],function(e,t,i,a){"use strict";function s(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var u=s(t),n=s(i),r=s(a),o=u.default,d=Backbone.Router.extend({initialize:function(e,t){this.page=e,this.options=t},push:function(e,t){(t=t||{}).__identifer=Math.random().toString(36).substr(2),e+=-1==e.indexOf("?")?"?":"&",e+=o.param(t,!0),Galaxy.params=t,this.navigate(e,{trigger:!0})},execute:function(e,t,i){Galaxy.debug("router execute:",e,t,i);var a=n.default.parse(t.pop());t.push(a),e&&(this.authenticate(t,i)?e.apply(this,t):this.access_denied())},authenticate:function(e,t){return!0},access_denied:function(){this.page.display(new r.default.Message({status:"danger",message:"You must be logged in with proper credentials to make this request.",persistent:!0}))}});e.default=d});
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
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
define("mvc/history/history-item-li",["exports"],function(e){"use strict";function n(e){return 0==e.indexOf("name:")?'<span class="label label-info">'+_.escape(e.slice(5))+"</span>":""}Object.defineProperty(e,"__esModule",{value:!0}),e.default={nametagTemplate:function(e){return'<span class="nametags">'+_.sortBy(_.uniq(e.tags)).map(n).join("")+"</span>"}}});
define("mvc/history/history-item-li",["exports"],function(e){"use strict";function n(e){return'<span class="label label-info">'+_.escape(e.slice(5))+"</span>"}Object.defineProperty(e,"__esModule",{value:!0}),e.default={nametagTemplate:function(e){var t=_.filter(_.uniq(e.tags),function(e){return 0===e.indexOf("name:")}),a=_.sortBy(t).map(n);return'\n <div class="nametags" title="'+t.length+' nametags">\n '+a.join("")+"\n </div>"}}});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define("mvc/ui/ui-modal",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=t.View=Backbone.View.extend({className:"ui-modal",optionsDefault:{container:"body",title:"ui-modal",cls:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1,closing_callback:null,title_separator:!0},buttonList:{},initialize:function(t){this.options=_.defaults(t||{},this.optionsDefault),$(this.options.container).prepend(this.el),t&&this.render()},show:function(t){if(t&&(this.options=_.defaults(t,this.optionsDefault),this.render()),!this.visible&&(this.visible=!0,this.$el.fadeIn("fast"),this.options.closing_events)){var i=this;$(document).on("keyup.ui-modal",function(t){27==t.keyCode&&i.hide(!0)}),this.$backdrop.on("click",function(){i.hide(!0)})}},hide:function(t){this.visible=!1,this.$el.fadeOut("fast"),this.options.closing_callback&&this.options.closing_callback(t),$(document).off("keyup.ui-modal"),this.$backdrop.off("click")},render:function(){var t=this;if(this.$el.html(this._template()),this.$header=this.$(".modal-header"),this.$dialog=this.$(".modal-dialog"),this.$body=this.$(".modal-body"),this.$footer=this.$(".modal-footer"),this.$backdrop=this.$(".modal-backdrop"),this.$buttons=this.$(".buttons"),"progress"==this.options.body&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"/></div>')),this.$el.removeClass().addClass("modal").addClass(this.options.cls),this.$header.find(".title").html(this.options.title),this.$body.html(this.options.body),this.$buttons.empty(),this.buttonList={},this.options.buttons){var i=0;$.each(this.options.buttons,function(s,o){var e=$("<button/>").attr("id","button-"+i++).text(s).click(o);t.$buttons.append(e).append("&nbsp;"),t.buttonList[s]=e})}else this.$footer.hide();this.$backdrop[this.options.backdrop&&"addClass"||"removeClass"]("in"),this.$header[!this.options.title_separator&&"addClass"||"removeClass"]("no-separator"),this.$body.removeAttr("style"),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width)},getButton:function(t){return this.buttonList[t]},enableButton:function(t){this.getButton(t).prop("disabled",!1)},disableButton:function(t){this.getButton(t).prop("disabled",!0)},showButton:function(t){this.getButton(t).show()},hideButton:function(t){this.getButton(t).hide()},scrollTop:function(){return this.$body.scrollTop()},_template:function(){return'<div class="modal-backdrop fade"/><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h4 class="title"/></div><div class="modal-body"/><div class="modal-footer"><div class="buttons"/></div></div></div>'}});t.default={View:i}});
define("mvc/ui/ui-modal",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=t.View=Backbone.View.extend({className:"ui-modal",optionsDefault:{container:"body",title:"ui-modal",cls:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1,closing_callback:null,title_separator:!0},buttonList:{},initialize:function(t){this.options=_.defaults(t||{},this.optionsDefault),$(this.options.container).prepend(this.el),t&&this.render()},show:function(t){var i=this;t&&(this.options=_.defaults(t,this.optionsDefault),this.render()),this.visible||(this.visible=!0,this.$el.fadeIn("fast")),this.options.closing_events&&($(document).on("keyup.ui-modal",function(t){27==t.keyCode&&i.hide(!0)}),this.$backdrop.on("click",function(){i.hide(!0)}))},hide:function(t){this.visible=!1,this.$el.fadeOut("fast"),this.options.closing_callback&&this.options.closing_callback(t),$(document).off("keyup.ui-modal"),this.$backdrop.off("click")},render:function(){var t=this;if(this.$el.html(this._template()),this.$header=this.$(".modal-header"),this.$dialog=this.$(".modal-dialog"),this.$body=this.$(".modal-body"),this.$footer=this.$(".modal-footer"),this.$backdrop=this.$(".modal-backdrop"),this.$buttons=this.$(".buttons"),"progress"==this.options.body&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"/></div>')),this.$el.removeClass().addClass("modal").addClass(this.options.cls),this.$header.find(".title").html(this.options.title),this.$body.html(this.options.body),this.$buttons.empty(),this.buttonList={},this.options.buttons){var i=0;$.each(this.options.buttons,function(s,o){var e=$("<button/>").attr("id","button-"+i++).text(s).click(o);t.$buttons.append(e).append("&nbsp;"),t.buttonList[s]=e})}else this.$footer.hide();this.$backdrop[this.options.backdrop&&"addClass"||"removeClass"]("in"),this.$header[!this.options.title_separator&&"addClass"||"removeClass"]("no-separator"),this.$body.removeAttr("style"),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width)},getButton:function(t){return this.buttonList[t]},enableButton:function(t){this.getButton(t).prop("disabled",!1)},disableButton:function(t){this.getButton(t).prop("disabled",!0)},showButton:function(t){this.getButton(t).show()},hideButton:function(t){this.getButton(t).hide()},scrollTop:function(){return this.$body.scrollTop()},_template:function(){return'<div class="modal-backdrop fade"/><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h4 class="title"/></div><div class="modal-body"/><div class="modal-footer"><div class="buttons"/></div></div></div>'}});t.default={View:i}});
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
define("mvc/ui/ui-select-library",["exports","utils/utils","mvc/ui/ui-misc","mvc/ui/ui-table","mvc/ui/ui-list"],function(e,t,i,a,l){"use strict";function n(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});n(t);var s=n(i),r=(n(a),n(l)),c=Backbone.Collection.extend({url:Galaxy.root+"api/libraries?deleted=false"}),o=Backbone.Collection.extend({initialize:function(){var e=this;this.config=new Backbone.Model({library_id:null}),this.config.on("change",function(){e.fetch({reset:!0})})},url:function(){return Galaxy.root+"api/libraries/"+this.config.get("library_id")+"/contents"}}),u=Backbone.View.extend({initialize:function(e){var t=this;this.libraries=new c,this.datasets=new o,this.options=e,this.library_select=new s.default.Select.View({onchange:function(e){t.datasets.config.set("library_id",e)}}),this.dataset_list=new r.default.View({name:"dataset",optional:e.optional,multiple:e.multiple,onchange:function(){t.trigger("change")}}),this.libraries.on("reset",function(){var e=[];t.libraries.each(function(t){e.push({value:t.id,label:t.get("name")})}),t.library_select.update(e)}),this.datasets.on("reset",function(){var e=[];null!==t.library_select.text()&&t.datasets.each(function(t){"file"===t.get("type")&&e.push({value:t.id,label:t.get("name")})}),t.dataset_list.update(e)}),this.on("change",function(){e.onchange&&e.onchange(t.value())}),this.setElement(this._template()),this.$(".library-select").append(this.library_select.$el),this.$el.append(this.dataset_list.$el),this.libraries.fetch({reset:!0,success:function(){t.library_select.trigger("change"),void 0!==t.options.value&&t.value(t.options.value)}})},value:function(e){return this.dataset_list.value(e)},_template:function(){return'<div class="ui-select-library"><div class="library ui-margin-bottom"><span class="library-title">Select Library</span><span class="library-select"/></div></div>'}});e.default={View:u}});
define("mvc/ui/ui-select-library",["exports","mvc/ui/ui-misc","mvc/ui/ui-list"],function(e,t,i){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var n=a(t),l=a(i),s=Backbone.Collection.extend({url:Galaxy.root+"api/libraries?deleted=false"}),r=Backbone.Collection.extend({initialize:function(){var e=this;this.config=new Backbone.Model({library_id:null}),this.config.on("change",function(){e.fetch({reset:!0})})},url:function(){return Galaxy.root+"api/libraries/"+this.config.get("library_id")+"/contents"}}),c=Backbone.View.extend({initialize:function(e){var t=this;this.libraries=new s,this.datasets=new r,this.options=e,this.library_select=new n.default.Select.View({onchange:function(e){t.datasets.config.set("library_id",e)}}),this.dataset_list=new l.default.View({name:"dataset",optional:e.optional,multiple:e.multiple,onchange:function(){t.trigger("change")}}),this.libraries.on("reset",function(){var e=[];t.libraries.each(function(t){e.push({value:t.id,label:t.get("name")})}),t.library_select.update(e)}),this.datasets.on("reset",function(){var e=[];null!==t.library_select.text()&&t.datasets.each(function(t){"file"===t.get("type")&&e.push({value:t.id,label:t.get("name")})}),t.dataset_list.update(e)}),this.on("change",function(){e.onchange&&e.onchange(t.value())}),this.setElement(this._template()),this.$(".library-select").append(this.library_select.$el),this.$el.append(this.dataset_list.$el),this.libraries.fetch({reset:!0,success:function(){t.library_select.trigger("change"),void 0!==t.options.value&&t.value(t.options.value)}})},value:function(e){return this.dataset_list.value(e)},_template:function(){return'<div class="ui-select-library"><div class="library ui-margin-bottom"><span class="library-title">Select Library</span><span class="library-select"/></div></div>'}});e.default={View:c}});
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
define("toolshed/groups/group-detail-view",["exports","libs/toastr","toolshed/groups/group-model"],function(e,t,o){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=e[o]);return t.default=e,t}(t),i=function(e){return e&&e.__esModule?e:{default:e}}(o),a=Backbone.View.extend({el:"#groups_element",options:{},app:null,initialize:function(e){this.options=_.extend(this.options,e),this.app=window.globalTS.groups,null!==this.app.collection?(this.model=this.app.collection.get(this.options.group_id),this.render()):this.fetchGroup()},fetchGroup:function(e){var t=this;this.options=_.extend(this.options,e),this.model=new i.default.Group({id:this.options.group_id}),this.model.fetch({success:function(e){console.log("received data: "),console.log(e),t.render()},error:function(e,t){void 0!==t.responseJSON?r.error(t.responseJSON.err_msg):r.error("An error occurred.")}})},render:function(){var e=this.templateRow();this.$el.html(e({group:this.model})),$("#center [data-toggle]").tooltip(),$("#center").css("overflow","auto")},templateRow:function(){return _.template(["<div>",'<h3><%= _.escape(group.get("name")) %></h3>','<p class="" style="color:gray;">','A group of <%= group.get("members").length %> members with <%= group.get("repositories").length %> repositories and a total of <%= group.get("total_downloads") %> combined repository clones.</p>',"<h3>Members</h3>",'<table class="grid table table-condensed">',"<thead>","<th>Name</th>","<th>Repositories</th>","<th>Registered</th>","</thead>","<tbody>",'<% _.each(group.get("members"), function(member) { %>',"<tr>","<td>","<%= _.escape(member.username) %>","</td>","<td>",'<a data-toggle="tooltip" data-placement="top" title="Repositories of <%= _.escape(member.username) %>" href="/repository/browse_repositories_by_user?user_id=<%= member.id %>&use_panels=true" id="<%= member.id %>"><%= member.user_repos_count %></a>',"</td>","<td>","<%= member.time_created %>","</td>","</tr>","<% }); %>","</tbody>","</table>","<h3>Repositories</h3>",'<table class="grid table table-condensed">',"<thead>","<th>Name</th>","<th>Description</th>","<th>Clones</th>","<th>Owner</th>","<th>Categories</th>","<th>Created</th>","<th>Updated</th>","<th>Rating</th>","<th>Verified</th>","</thead>","<tbody>",'<% _.each(group.get("repositories"), function(repo) { %>',"<tr>","<td>",'<a data-toggle="tooltip" data-placement="top" title="Details of <%= _.escape(repo.name) %>" href="/view/<%= _.escape(repo.owner) %>/<%= _escape(repo.name) %>" id="<%= repo.id %>"><%= _.escape(repo.name) %></a>',"</td>","<td>","<%= _.escape(repo.description) %>","</td>","<td>","<%= repo.times_downloaded %>","</td>","<td>","<%= _.escape(repo.owner) %>","</td>","<td>","<% _.each((repo.categories), function(cat) { %>",'<a data-toggle="tooltip" data-placement="top" title="Repositories in <%= cat.name %>" href="/repository/browse_repositories_in_category?id=<%= cat.id %>&use_panels=true"><%= cat.name %></a><br/>',"<% }); %>","</td>",'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_created_full %>">',"<%= repo.time_created %>","</td>",'<td data-toggle="tooltip" data-placement="top" title="<%= repo.time_updated_full %>">',"<%= repo.time_updated %>","</td>","<td>","<%= repo.ratings_mean %>","</td>","<td>","<%= repo.approved %>","</td>","</tr>","<% }); %>","</tbody>","</table>","</div>"].join(""))}});e.default={GroupDetailView:a}});
@@ -0,0 +1 @@
define("toolshed/groups/group-list-view",["exports","libs/toastr","toolshed/groups/group-model","toolshed/groups/group-listrow-view"],function(e,o,t,s){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var i=function(e){if(e&&e.__esModule)return e;var o={};if(null!=e)for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(o[t]=e[t]);return o.default=e,o}(o),n=r(t),l=r(s),u=Backbone.View.extend({el:"#groups_element",defaults:{},initialize:function(e){this.options=_.defaults(this.options||{},this.defaults,e);var o=this;window.globalTS.groups.collection=new n.default.Groups,window.globalTS.groups.collection.fetch({success:function(e){console.log("received data: "),console.log(e),o.render()},error:function(e,o){void 0!==o.responseJSON?i.error(o.responseJSON.err_msg):i.error("An error occurred.")}})},fetch:function(){},render:function(e){this.options=_.extend(this.options,e),$(".tooltip").hide();var o=this.templateGroupsList();this.$el.html(o({length:window.globalTS.groups.collection.models.length})),this.renderRows(window.globalTS.groups.collection.models),$("#center [data-toggle]").tooltip(),$("#center").css("overflow","auto")},renderRows:function(e){for(var o=0;o<e.length;o++){var t=e[o];this.renderOne({group:t})}},renderOne:function(e){var o=new l.default.GroupListRowView(e);this.$el.find("#group_list_body").append(o.el)},templateGroupsList:function(){var e=[];return e.push('<div id="groups">'),e.push("</div>"),e.push('<div class="groups_container table-responsive">'),e.push("<% if(length === 0) { %>"),e.push("<div>There are no groups yet.</div>"),e.push("<% } else{ %>"),e.push('<table class="grid table table-condensed">'),e.push(" <thead>"),e.push(" <th>Name</th>"),e.push(" <th>Members</th> "),e.push(" <th>Repositories</th>"),e.push(" </thead>"),e.push(' <tbody id="group_list_body">'),e.push(" </tbody>"),e.push("</table>"),e.push("<% }%>"),e.push("</div>"),_.template(e.join(""))}});e.default={GroupListView:u}});
@@ -0,0 +1 @@
define("toolshed/groups/group-listrow-view",["exports"],function(e){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var t=Backbone.View.extend({events:{},initialize:function(e){this.render(e.group)},render:function(e){var t=this.templateRow();return this.setElement(t({group:e})),this.$el.show(),this},templateRow:function(){return _.template(['<tr class="" data-id="<%- group.get("id") %>">','<td><a href="groups#/<%= group.get("id") %>"><%= _.escape(group.get("name")) %></a></td>','<td><%= group.get("total_members") %></td>','<td><%= group.get("total_repos") %></td>',"</tr>"].join(""))}});e.default={GroupListRowView:t}});
@@ -0,0 +1 @@
define("toolshed/groups/group-model",["exports"],function(o){"use strict";Object.defineProperty(o,"__esModule",{value:!0});var e=Backbone.Model.extend({urlRoot:Galaxy.root+"api/groups"}),r=Backbone.Collection.extend({url:Galaxy.root+"api/groups",model:e});o.default={Group:e,Groups:r}});
@@ -0,0 +1 @@
define("toolshed/toolshed.groups",["exports","toolshed/groups/group-list-view","toolshed/groups/group-detail-view"],function(o,e,t){"use strict";function u(o){return o&&o.__esModule?o:{default:o}}Object.defineProperty(o,"__esModule",{value:!0});var i=u(e),r=u(t),s=Backbone.Router.extend({routes:{"":"groups",":group_id":"group_page"}}),l=Backbone.View.extend({groupListView:null,groupDetailView:null,collection:null,initialize:function(){window.globalTS.groups=this,this.ts_router=new s,this.ts_router.on("route:groups",function(){window.globalTS.groups.groupListView=new i.default.GroupListView}),this.ts_router.on("route:group_page",function(o){window.globalTS.groups.groupDetailView=new r.default.GroupDetailView({group_id:o})}),Backbone.history.start({pushState:!1})}});o.default={ToolshedGroups: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
+1 -1
View File
@@ -1 +1 @@
a{text-decoration:underline}label{font-weight:normal}.library_style_container{width:95%;margin:auto;margin-top:2em;overflow:auto !important}.library_style_container .fa{font-size:12px}.library_style_container .fa-globe,.library_style_container .fa-shield,.library_style_container .fa-key,.library_style_container .fa-ban{font-size:initial;margin-left:.6em}.library_style_container .libraryRow{background-color:#ebd9b2}.library_style_container .datasetHighlighted{background-color:#f9f9f9}.library_style_container .libraryItemDeleted-True{font-style:italic}.library_style_container div.libraryItemBody{padding:4px 4px 2px 4px}.library_style_container li.folderRow,.library_style_container li.datasetRow{border-top:solid 1px #c6bfa8}.library_style_container li.folderRow:hover,.library_style_container li.datasetRow:hover{background-color:#f9f9f9}.library_style_container td.right-center{vertical-align:middle !important;text-align:right}.library_style_container .library-genome-select{max-width:350px}.library_style_container .library-extension-select{max-width:140px}.library_style_container .library_table td{border-top:1px solid #5f6990 !important}.library_style_container .library_table th{border-bottom:2px solid #5f6990 !important}.library_style_container .library_table a{color:#0A143D}.library_style_container .library_table a:hover{color:maroon}.library_style_container tr.light td{background-color:white;color:black}.library_style_container tr.light:hover td{background-color:#f5e8cc}.library_style_container tr.dark td{background-color:#d6b161;color:white}.library_style_container tr.dark:hover td{background-color:#ebd4a4;color:white}.library_style_container a.dark{color:white}.library_style_container .dataset_table tr,.library_style_container .dataset_table th,.library_style_container .dataset_table td{border:none}.library_style_container .dataset_table .dataset-first-column{width:30%}.library_style_container th.button_heading{width:2em}.library_style_container .bigdrop.select2-container .select2-results{max-height:300px}.library_style_container .bigdrop .select2-results{max-height:300px}.library_style_container .select2-container-multi{width:100%}.library_style_container .roles-selection{width:66%}.library_style_container #library_toolbar{margin-bottom:.5em}.library_style_container #library_toolbar span{margin-right:.2em}.library_style_container #library_toolbar .toolbar-item{margin-left:1em}.library_style_container #libraries_element button,.library_style_container #folder_items_element button{margin-left:.5em}.library_style_container .help-button{float:right}.library_style_container .pagination-sm{height:15px}.library_style_container .library-paginator{margin-left:2em}.library_style_container .import-type-switch{text-decoration:underline}.library_style_container .libimport-select-none,.library_style_container .libimport-select-all{margin-left:.5em}.library_style_container .library-modal-item{width:90%;margin-left:1em;margin-right:1em}.library_style_container .paginator-bottom{width:27em;margin-left:auto;margin-right:auto;margin-top:2em;margin-bottom:2em}.modal-content #selected_history_content ul{list-style-type:none}#library-grid ul{list-style:none}#library-grid span.expandLink{padding-left:12px;display:inline-block;vertical-align:middle;background:url(../images/silk/resultset_next.png) no-repeat}#library-grid .folderRow.expanded span.expandLink{background:url(../images/silk/resultset_bottom.png) no-repeat}#library-grid .folderRow span.rowIcon{float:left;margin-right:5px;width:16px;height:16px;display:inline-block;vertical-align:middle;background:url(../images/silk/folder.png)}#library-grid .libraryItem-error{margin-right:2px;padding:0 2px 0 2px;border:1px solid #dd1b15;background:#f9c7c5}#library-grid .libraryItem-queued{margin-right:2px;padding:0 2px 0 2px;border:1px solid #bfbfbf;background:#eee}#library-grid .libraryItem-running{margin-right:2px;padding:0 2px 0 2px;border:1px solid #AAAA66;background:#FFFFCC}#library-grid .libraryItem-upload{margin-right:2px;padding:0 2px 0 2px;border:1px solid #119ac2;background:#a8e5f7}.libraryTitle th{text-align:left}.libraryTitle .rowTitle{padding:2px}
a{text-decoration:underline}label{font-weight:normal}.library_style_container{width:95%;margin:auto;margin-top:2em;overflow:auto !important}.library_style_container .fa{font-size:12px}.library_style_container .fa-globe,.library_style_container .fa-shield,.library_style_container .fa-key,.library_style_container .fa-ban{font-size:initial;margin-left:.6em}.library_style_container .libraryRow{background-color:#ebd9b2}.library_style_container .datasetHighlighted{background-color:#f9f9f9}.library_style_container .libraryItemDeleted-True{font-style:italic}.library_style_container div.libraryItemBody{padding:4px 4px 2px 4px}.library_style_container li.folderRow,.library_style_container li.datasetRow{border-top:solid 1px #c6bfa8}.library_style_container li.folderRow:hover,.library_style_container li.datasetRow:hover{background-color:#f9f9f9}.library_style_container td.right-center{vertical-align:middle !important;text-align:right}.library_style_container .library-genome-select{max-width:350px}.library_style_container .library-extension-select{max-width:140px}.library_style_container .library_table td{border-top:1px solid #5f6990 !important}.library_style_container .library_table th{border-bottom:2px solid #5f6990 !important}.library_style_container .library_table a{color:#0A143D}.library_style_container .library_table a:hover{color:maroon}.library_style_container tr.light td{background-color:white;color:black}.library_style_container tr.light:hover td{background-color:#f5e8cc}.library_style_container tr.dark td{background-color:#d6b161;color:white}.library_style_container tr.dark:hover td{background-color:#ebd4a4;color:white}.library_style_container a.dark{color:white}.library_style_container .dataset_table tr,.library_style_container .dataset_table th,.library_style_container .dataset_table td{border:none}.library_style_container .dataset_table .dataset-first-column{width:30%}.library_style_container th.button_heading{width:2em}.library_style_container .bigdrop.select2-container .select2-results{max-height:300px}.library_style_container .bigdrop .select2-results{max-height:300px}.library_style_container .select2-container-multi{width:100%}.library_style_container .roles-selection{width:66%}.library_style_container #library_toolbar{margin-bottom:.5em}.library_style_container #library_toolbar span{margin-right:.2em}.library_style_container #library_toolbar .toolbar-item{margin-left:.5em}.library_style_container #libraries_element button,.library_style_container #folder_items_element button{margin-left:.5em}.library_style_container .right-float{float:right}.library_style_container .pagination-sm{height:15px}.library_style_container .library-paginator{margin-left:2em}.library_style_container .import-type-switch{text-decoration:underline}.library_style_container .libimport-select-none,.library_style_container .libimport-select-all{margin-left:.5em}.library_style_container .paginator-bottom{width:27em;margin-left:auto;margin-right:auto;margin-top:2em;margin-bottom:2em}.modal-content .library_selected_history_content ul{list-style-type:none}.modal-content .library-collection-type-select,.modal-content .library-collection-history-select{margin-left:auto;margin-right:auto;width:200px;min-width:200px}.modal-content .library-modal-item{width:90%;margin-left:auto;margin-right:auto;margin-top:1.5em}.libraryTitle th{text-align:left}.libraryTitle .rowTitle{padding:2px}
+1
View File
@@ -61,6 +61,7 @@
## TODO: remove when all libs are required directly in modules
'bundled/libs.bundled',
'libs/require',
'bundled/extended.bundled'
)}
<script type="text/javascript">
+3 -2
View File
@@ -54,6 +54,7 @@
## TODO: remove when all libs are required directly in modules
'bundled/libs.bundled',
'libs/require',
'bundled/extended.bundled'
)}
<script type="text/javascript">
@@ -98,13 +99,13 @@
%if self.has_left_panel:
var lp = new panels.LeftPanel({ el: '#left' });
force_left_panel = function( x ) { lp.force_panel( x ) };
window.force_left_panel = function( x ) { lp.force_panel( x ) };
%endif
%if self.has_right_panel:
var rp = new panels.RightPanel({ el: '#right' });
window.handle_minwidth_hint = function( x ) { rp.handle_minwidth_hint( x ) };
force_right_panel = function( x ) { rp.force_panel( x ) };
window.force_right_panel = function( x ) { rp.force_panel( x ) };
%endif
%if t.webapp.name == 'galaxy' and app.config.ga_code:
+9 -12
View File
@@ -24,19 +24,16 @@ ${ h.dumps( dictionary, indent=( 2 if trans.debug else 0 ) ) }
## 1) bootstrap kwargs (as above), 2) build Galaxy global var, 3) load 'app' by AMD (optional)
${ self.bootstrap( **kwargs ) }
<script type="text/javascript">
require([ 'require', 'galaxy' ], function( require, galaxy ){
//TODO: global...
window.Galaxy = new galaxy.default.GalaxyApp({
root : '${h.url_for( "/" )}',
config : ${ render_json( get_config_dict() )},
user : ${ render_json( get_user_dict() )},
session_csrf_token : '${ trans.session_csrf_token }'
}, window.bootstrapped );
window.Galaxy = new window.bundleEntries.GalaxyApp.GalaxyApp({
root : '${h.url_for( "/" )}',
config : ${ render_json( get_config_dict() )},
user : ${ render_json( get_user_dict() )},
session_csrf_token : '${ trans.session_csrf_token }'
}, window.bootstrapped );
%if app:
require([ '${app}' ]);
%endif
});
%if app:
require([ '${app}' ]);
%endif
</script>
</%def>
+2 -4
View File
@@ -64,10 +64,8 @@
## load javascript
<script type="text/javascript">
require(['legacy/grid/grid-view'], function(GridView) {
$(function() {
var gridView = new GridView.default( ${ h.dumps( self.get_grid_config( embedded=embedded, insert=insert ) ) } );
});
$(function() {
var gridView = new window.bundleEntries.LegacyGridView( ${ h.dumps( self.get_grid_config( embedded=embedded, insert=insert ) ) } );
});
</script>
</%def>
@@ -7,7 +7,6 @@
<%def name="javascripts()">
${parent.javascripts()}
${h.js("bundled/extended.bundled")}
</%def>
<%def name="late_javascripts()">
+14 -21
View File
@@ -5,31 +5,24 @@
<%def name="javascripts()">
${parent.javascripts()}
${h.js("bundled/extended.bundled")}
## If data is chunkable, use JavaScript for display.
%if item.datatype.CHUNKABLE:
<script type="text/javascript">
require(['mvc/dataset/data'], function(data) {
//
// Use tabular data display progressively by deleting data from page body
// and then showing dataset view.
//
$('.page-body').children().remove();
data.default.createTabularDatasetChunkedView({
// TODO: encode id.
dataset_config:
_.extend( ${h.dumps( item.to_dict() )}, {
chunk_url: "${h.url_for( controller='/dataset', action='display',
dataset_id=trans.security.encode_id( item.id ))}",
first_data_chunk: ${first_chunk}
}),
parent_elt: $('.page-body')
<script type="text/javascript">
$(function(){
// Use tabular data display progressively by deleting data from page body
// and then showing dataset view.
var dataset_config = _.extend( ${h.dumps( item.to_dict() )}, {
chunk_url: "${h.url_for( controller='/dataset', action='display', dataset_id=trans.security.encode_id( item.id ))}",
first_data_chunk: ${first_chunk}});
$('.page-body').children().remove();
window.bundleEntries.createTabularDatasetChunkedView({
dataset_config: dataset_config,
parent_elt: $('.page-body')
});
});
});
</script>
</script>
%endif
</%def>
@@ -5,10 +5,11 @@
<%def name="javascripts()">
${parent.javascripts()}
${h.js("bundled/extended.bundled")}
<script type="text/javascript">
require([ 'mvc/dataset/data' ], function( data ) {
data.default.createTabularDatasetChunkedView({
$(function(){
bundleEntries.createTabularDatasetChunkedView({
dataset_config : _.extend( ${ h.dumps( trans.security.encode_dict_ids( dataset.to_dict() ) )}, {
first_data_chunk: ${ chunk }
}),
+3 -2
View File
@@ -110,6 +110,7 @@
// extra configuration global
var galaxy_config = ${ h.dumps( self.galaxy_config ) };
window.galaxy_config = galaxy_config;
</script>
${h.js(
@@ -146,14 +147,14 @@
## configure left panel
%if self.galaxy_config['left_panel']:
var lp = new panels.LeftPanel({ el: '#left' });
force_left_panel = function( x ) { lp.force_panel( x ) };
window.force_left_panel = function( x ) { lp.force_panel( x ) };
%endif
## configure right panel
%if self.galaxy_config['right_panel']:
var rp = new panels.RightPanel({ el: '#right' });
window.handle_minwidth_hint = function( x ) { rp.handle_minwidth_hint( x ) };
force_right_panel = function( x ) { rp.force_panel( x ) };
window.force_right_panel = function( x ) { rp.force_panel( x ) };
%endif
</script>
</%def>
+7 -17
View File
@@ -47,18 +47,8 @@
.css( 'height', '100%' )
.addClass( 'flex-vertical-container' );
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}",
urlArgs: 'v=${app.server_starttime}'
})([
'mvc/history/history-view-annotated',
'mvc/history/copy-dialog',
], function( panelMod, historyCopyDialog ){
// history module is already in the dpn chain from the panel. We can re-scope it here.
var HISTORY = require( 'mvc/history/history-model' );
var HISTORY_CONTENTS = require( 'mvc/history/history-contents' );
var HistoryContentsWithAnnotations = HISTORY_CONTENTS.default.HistoryContents.extend({
$(function(){
var HistoryContentsWithAnnotations = window.bundleEntries.HistoryContents.extend({
_buildFetchData : function( options ){
console.log( '_buildFetchData:' );
options = options || {};
@@ -66,10 +56,10 @@
options.view = 'summary';
options.keys = 'annotation,tags';
}
return HISTORY_CONTENTS.default.HistoryContents.prototype._buildFetchData.call( this, options );
return window.bundleEntries.HistoryContents.prototype._buildFetchData.call( this, options );
}
});
var HistoryWithAnnotations = HISTORY.default.History.extend({
var HistoryWithAnnotations = window.bundleEntries.History.extend({
contentsClass : HistoryContentsWithAnnotations
});
@@ -78,16 +68,16 @@
});
$( '.history-copy-link' ).click( function( ev ){
historyCopyDialog.default( historyModel, { useImport: true, allowAll: false })
window.bundleEntries.HistoryCopyDialog( historyModel, { useImport: true, allowAll: false })
.done( function(){
var mainWindow = ( window && ( window !== window.parent ) )? window.top : window;
mainWindow.location.href = Galaxy.root;
});
});
window.historyView = new panelMod.default.AnnotatedHistoryView({
window.historyView = new window.bundleEntries.HistoryViewAnnotated.AnnotatedHistoryView({
el : $( "#history-" + historyJSON.id ),
className : panelMod.default.AnnotatedHistoryView.prototype.className + ' wide',
className : window.bundleEntries.HistoryViewAnnotated.AnnotatedHistoryView.prototype.className + ' wide',
model : historyModel,
show_deleted : false,
show_hidden : false,
@@ -141,22 +141,21 @@
hda_dicts.append( hda_dict )
%>
${parent.javascripts()}
${h.js("bundled/extended.bundled")}
## load edit views for each of the hdas
<script type="text/javascript">
define( 'display-structured', function(){
require([ 'mvc/history/hda-li-edit', 'mvc/history/hda-model' ], function( hdaEdit, hdaModel ){
var hdaJSON = ${ h.dumps( hda_dicts, indent=( 2 if trans.debug else 0 ) ) };
var hdaJSON = ${ h.dumps( hda_dicts, indent=( 2 if trans.debug else 0 ) ) };
window.hdas = hdaJSON.map( function( hda ){
return new hdaEdit.default.HDAListItemEdit({
model : new hdaModel.default.HistoryDatasetAssociation( hda ),
el : $( '#hda-' + hda.id ),
linkTarget : '_self',
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
logger : Galaxy.logger
}).render( 0 );
});
window.hdas = hdaJSON.map( function( hda ){
return new window.bundleEntries.HDAListItemEdit.HDAListItemEdit({
model : new window.bundleEntries.HDAModel.HistoryDatasetAssociation( hda ),
el : $( '#hda-' + hda.id ),
linkTarget : '_self',
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
logger : Galaxy.logger
}).render( 0 );
});
});
+74 -86
View File
@@ -40,99 +40,87 @@
// In order to handle this, find this script and cache the previous node (the div above).
// (Since we need thisScript to be locally scoped or it will get overwritten, enclose in self-calling function)
(function(){
var scripts = document.getElementsByTagName( 'script' ),
var scripts = document.getElementsByTagName( 'script' );
// this is executed immediately, so the last script will be this script
thisScript = scripts[ scripts.length - 1 ],
$embeddedHistory = $( thisScript ).prev();
var thisScript = scripts[ scripts.length - 1 ];
var $embeddedHistory = $( thisScript ).prev();
require.config({
baseUrl: "${h.url_for( '/static/scripts' )}",
urlArgs: 'v=${app.server_starttime}'
});
require([
'mvc/history/history-view-annotated',
'mvc/history/copy-dialog'
], function( viewMod, historyCopyDialog ){
var $embeddedHistory = $( thisScript ).prev();
$embeddedHistory.find( '.item-content' ).addClass( 'flex-vertical-container' );
var $embeddedHistory = $( thisScript ).prev();
$embeddedHistory.find( '.item-content' ).addClass( 'flex-vertical-container' );
$(function(){
var HISTORY = require( 'mvc/history/history-model' );
var HISTORY_CONTENTS = require( 'mvc/history/history-contents' );
$(function(){
var HistoryContentsWithAnnotations = window.bundleEntries.HistoryContents.extend({
_buildFetchData : function( options ){
console.log( '_buildFetchData:' );
options = options || {};
if( !options.keys && !options.view ){
options.view = 'summary';
options.keys = 'annotation,tags';
}
return window.bundleEntries.HistoryContents.prototype._buildFetchData.call( this, options );
}
});
var HistoryWithAnnotations = window.bundleEntries.History.extend({
contentsClass : HistoryContentsWithAnnotations
});
var HistoryContentsWithAnnotations = HISTORY_CONTENTS.default.HistoryContents.extend({
_buildFetchData : function( options ){
console.log( '_buildFetchData:' );
options = options || {};
if( !options.keys && !options.view ){
options.view = 'summary';
options.keys = 'annotation,tags';
}
return HISTORY_CONTENTS.default.HistoryContents.prototype._buildFetchData.call( this, options );
var historyJSON = ${h.dumps( history_dict )};
var historyModel = new HistoryWithAnnotations( historyJSON, null, {
order : 'hid-asc',
});
var historyView = new window.bundleEntries.HistoryViewAnnotated.AnnotatedHistoryView({
el : $embeddedHistory.find( ".history-panel" ),
className : window.bundleEntries.HistoryViewAnnotated.AnnotatedHistoryView.prototype.className + ' wide',
model : historyModel
});
historyView.trigger( 'loading' );
historyModel.fetchContents({ silent: true })
.fail( function(){ alert( 'Galaxy history failed to load' ); })
.done( function(){
historyView.trigger( 'loading-done' );
historyView.render();
});
function toggleExpanded( ev ){
ev.preventDefault();
$embeddedHistory.find( '.expand-content-btn' ).toggleClass( 'toggle-expand' ).toggleClass( 'toggle' );
$embeddedHistory.find( ".summary-content" ).slideToggle( "fast" );
$embeddedHistory.find( ".annotation" ).slideToggle( "fast" );
$embeddedHistory.find( ".expanded-content" ).slideToggle( "fast" );
}
$embeddedHistory.find( '.expand-content-btn' ).click( toggleExpanded );
$embeddedHistory.find( '.toggle-embed' ).click( toggleExpanded );
function showConfirmationModal( name ){
var body = [
'<div class="donemessagelarge">',
_l( 'History imported' ), ': ', _.escape( historyModel.get( 'name' ) ),
'</div>'
].join('');
Galaxy.modal.show({
title : _l( 'Success!' ),
body : $( body ),
buttons : {
'Return to the published page' : function(){
Galaxy.modal.hide();
},
'Start using the history' : function(){
window.location = Galaxy.root;
},
}
});
var HistoryWithAnnotations = HISTORY.default.History.extend({
contentsClass : HistoryContentsWithAnnotations
});
Galaxy.modal.$( '.modal-header' ).hide();
Galaxy.modal.$( '.modal-body' ).css( 'padding-bottom', 0 );
Galaxy.modal.$( '.modal-footer' ).css({ border : 0, 'padding-top': 0 });
}
var historyJSON = ${h.dumps( history_dict )};
var historyModel = new HistoryWithAnnotations( historyJSON, null, {
order : 'hid-asc',
});
var historyView = new viewMod.default.AnnotatedHistoryView({
el : $embeddedHistory.find( ".history-panel" ),
className : viewMod.default.AnnotatedHistoryView.prototype.className + ' wide',
model : historyModel
});
historyView.trigger( 'loading' );
historyModel.fetchContents({ silent: true })
.fail( function(){ alert( 'Galaxy history failed to load' ); })
.done( function(){
historyView.trigger( 'loading-done' );
historyView.render();
});
function toggleExpanded( ev ){
ev.preventDefault();
$embeddedHistory.find( '.expand-content-btn' ).toggleClass( 'toggle-expand' ).toggleClass( 'toggle' );
$embeddedHistory.find( ".summary-content" ).slideToggle( "fast" );
$embeddedHistory.find( ".annotation" ).slideToggle( "fast" );
$embeddedHistory.find( ".expanded-content" ).slideToggle( "fast" );
}
$embeddedHistory.find( '.expand-content-btn' ).click( toggleExpanded );
$embeddedHistory.find( '.toggle-embed' ).click( toggleExpanded );
function showConfirmationModal( name ){
var body = [
'<div class="donemessagelarge">',
_l( 'History imported' ), ': ', _.escape( historyModel.get( 'name' ) ),
'</div>'
].join('');
Galaxy.modal.show({
title : _l( 'Success!' ),
body : $( body ),
buttons : {
'Return to the published page' : function(){
Galaxy.modal.hide();
},
'Start using the history' : function(){
window.location = Galaxy.root;
},
}
});
Galaxy.modal.$( '.modal-header' ).hide();
Galaxy.modal.$( '.modal-body' ).css( 'padding-bottom', 0 );
Galaxy.modal.$( '.modal-footer' ).css({ border : 0, 'padding-top': 0 });
}
$embeddedHistory.find( '.import' ).click( function( ev ){
var dialogOptions = { useImport: true, allowAll: false, autoClose: false };
historyCopyDialog.default( historyModel, dialogOptions ).done( showConfirmationModal );
})
});
$embeddedHistory.find( '.import' ).click( function( ev ){
var dialogOptions = { useImport: true, allowAll: false, autoClose: false };
window.bundleEntries.HistoryCopyDialog( historyModel, dialogOptions ).done( showConfirmationModal );
})
});
})();
</script>
+15 -18
View File
@@ -6,6 +6,11 @@
</%def>
## -----------------------------------------------------------------------------
<%def name="javascripts()">
${ parent.javascripts() }
${h.js("bundled/extended.bundled")}
</%def>
<%def name="stylesheets()">
${ parent.stylesheets() }
@@ -68,26 +73,18 @@ ${ parent.stylesheets() }
<%def name="javascript_app()">
<script type="text/javascript">
define( 'app', function(){
require([
'mvc/history/history-model',
'mvc/history/history-structure-view'
], function( HISTORY, StructureView ){
console.debug(HISTORY);
console.debug(StructureView);
var historyModel = new HISTORY.default.History( bootstrapped.history, bootstrapped.contents );
console.debug("Got here?");
window.historymodel = historyModel;
window.jobs = bootstrapped.jobs;
window.tools = bootstrapped.tools;
var historyModel = new window.bundleEntries.History( bootstrapped.history, bootstrapped.contents );
window.historymodel = historyModel;
window.jobs = bootstrapped.jobs;
window.tools = bootstrapped.tools;
var structure = new StructureView.default({
model : historyModel,
jobs : bootstrapped.jobs,
tools : bootstrapped.tools
});
window.structure = structure;
structure.render().$el.appendTo( 'body' );
var structure = new window.bundleEntries.StructureView({
model : historyModel,
jobs : bootstrapped.jobs,
tools : bootstrapped.tools
});
window.structure = structure;
structure.render().$el.appendTo( 'body' );
});
</script>
${ galaxy_client.load( app='app', historyId=historyId, history=history, contents=contents, jobs=jobs, tools=tools ) }
+16 -103
View File
@@ -102,109 +102,22 @@ a.btn {
<script type="text/javascript">
// use_panels effects where the the center_panel() is rendered:
// w/o it renders to the body, w/ it renders to #center - we need to adjust a few things for scrolling to work
var hasMasthead = ${ 'true' if use_panels else 'false' },
userIsOwner = ${ 'true' if user_is_owner else 'false' },
isCurrent = ${ 'true' if history_is_current else 'false' },
historyJSON = ${ h.dumps( history ) },
viewToUse = ( userIsOwner )?
//TODO: change class names
({ location: 'mvc/history/history-view-edit', className: 'HistoryViewEdit' }):
({ location: 'mvc/history/history-view', className: 'HistoryView' });
require.config({
baseUrl : "${h.url_for( '/static/scripts' )}",
paths : {
'jquery' : 'libs/jquery/jquery'
},
urlArgs: 'v=${app.server_starttime}'
})([
'mvc/user/user-model',
viewToUse.location,
'mvc/history/copy-dialog',
'utils/localization',
'ui/mode-button'
], function( user, viewMod, historyCopyDialog, _l ){
+(function setUpBehaviors(){
$( '#toggle-deleted' ).modeButton({
initialMode : "${ 'showing_deleted' if show_deleted else 'not_showing_deleted' }",
modes: [
{ mode: 'showing_deleted', html: _l( 'Exclude deleted' ) },
{ mode: 'not_showing_deleted', html: _l( 'Include deleted' ) }
]
});
$( '#toggle-hidden' ).modeButton({
initialMode : "${ 'showing_hidden' if show_hidden else 'not_showing_hidden' }",
modes: [
{ mode: 'showing_hidden', html: _l( 'Exclude hidden' ) },
{ mode: 'not_showing_hidden', html: _l( 'Include hidden' ) }
]
});
$( '#switch' ).click( function( ev ){
//##HACK:ity hack hack
//##TODO: remove when out of iframe
var hview = Galaxy.currHistoryPanel
|| ( top.Galaxy && top.Galaxy.currHistoryPanel )? top.Galaxy.currHistoryPanel : null;
if( hview ){
hview.switchToHistory( "${ history[ 'id' ] }" );
} else {
window.location = "${ switch_to_url }";
}
});
})();
$(function(){
if( hasMasthead ){
$( '#center' ).addClass( 'flex-vertical-container' );
}
var viewClass = viewMod.default[ viewToUse.className ],
// history module is already in the dpn chain from the view. We can re-scope it here.
HISTORY = require( 'mvc/history/history-model' ),
historyModel = new HISTORY.default.History( historyJSON );
// attach the copy dialog to the import button now that we have a history
$( '#import' ).click( function( ev ){
historyCopyDialog.default( historyModel, {
useImport : true,
// use default datasets option to match the toggle-deleted button
allDatasets : $( '#toggle-deleted' ).modeButton( 'getMode' ).mode === 'showing_deleted',
}).done( function(){
if( window === window.parent ){
window.location = Galaxy.root;
} else if( Galaxy.currHistoryPanel ){
Galaxy.currHistoryPanel.loadCurrentHistory();
}
});
});
window.historyView = new viewClass({
el : $( "#history-" + historyJSON.id ),
className : viewClass.prototype.className + ' wide',
$scrollContainer: hasMasthead? function(){ return this.$el.parent(); } : undefined,
model : historyModel,
show_deleted : ${show_deleted_json},
show_hidden : ${show_hidden_json},
purgeAllowed : Galaxy.config.allow_user_dataset_purge,
});
historyView.trigger( 'loading' );
historyModel.fetchContents({ silent: true })
.fail( function(){ alert( 'Galaxy history failed to load' ); })
.done( function(){
historyView.trigger( 'loading-done' );
historyView.render();
});
$( '#toggle-deleted' ).on( 'click', function(){
historyView.toggleShowDeleted();
});
$( '#toggle-hidden' ).on( 'click', function(){
historyView.toggleShowHidden();
});
});
$(function(){
options = {
hasMasthead: ${ 'true' if use_panels else 'false' },
userIsOwner: ${ 'true' if user_is_owner else 'false' },
isCurrent: ${ 'true' if history_is_current else 'false' },
historyJSON: ${ h.dumps( history ) },
showDeletedJson: ${ show_deleted_json },
showHiddenJson: ${ show_hidden_json },
initialModeDeleted: "${ 'showing_deleted' if show_deleted else 'not_showing_deleted' }",
initialModeHidden: "${ 'showing_hidden' if show_hidden else 'not_showing_hidden' }",
allowUserDatasetPurge: ${ 'true' if trans.app.config.allow_user_dataset_purge else 'false' }
};
options.viewToUse = options.userIsOwner ?
({ location: 'mvc/history/history-view-edit', className: 'HistoryViewEdit' }):
({ location: 'mvc/history/history-view', className: 'HistoryView' });
window.bundleEntries.history(options);
});
</script>
@@ -1,4 +1,3 @@
<%inherit file="/webapps/galaxy/base_panels.mako"/>
<%namespace file="/galaxy_client_app.mako" name="galaxy_client"/>
@@ -24,36 +23,16 @@
<%def name="javascript_app()">
<script type="text/javascript">
define( 'app', function(){
require([
'mvc/history/history-model',
'mvc/history/multi-panel'
], function( HISTORY_MODEL, MULTI_HISTORY ){
$(function(){
histories = new HISTORY_MODEL.default.HistoryCollection( [], {
includeDeleted : bootstrapped.includingDeleted,
order : bootstrapped.order,
limitOnFirstFetch : bootstrapped.limit,
limitPerFetch : bootstrapped.limit,
// lastFetched : bootstrapped.limit,
currentHistoryId : bootstrapped.current_history_id,
});
multipanel = new MULTI_HISTORY.default.MultiPanelColumns({
el : $( '#center' ).get(0),
histories : histories,
})
histories.fetchFirst({ silent: true })
.done( function(){
multipanel.createColumns();
multipanel.render( 0 );
});
});
define( 'app', function(){
bundleEntries.multiHistory(bootstrapped);
});
});
</script>
${ galaxy_client.load( app='app', current_history_id=current_history_id,
includingDeleted=include_deleted_histories, order=order, limit=limit ) }
##${ galaxy_client.load( app='app', histories=histories,
## includingDeleted=include_deleted_histories, order=order, limit=limit ) }
${galaxy_client.load(
app='app',
current_history_id=current_history_id,
includingDeleted=include_deleted_histories,
order=order,
limit=limit
)}
</%def>
+2 -2
View File
@@ -22,8 +22,8 @@
iframe_base_path = "${h.url_for('/static/wymeditor/iframe/galaxy')}/",
save_url = "${h.url_for(controller='page', action='save' )}";
require(['galaxy.pages'], function(Pages){
Pages.default();
$(function(){
bundleEntries.pages()
});
</script>
@@ -18,9 +18,7 @@
<%def name="stylesheets()">
${parent.stylesheets()}
${h.css(
"trackster"
)}
${h.css("trackster")}
## Style changes needed for display.
<style type="text/css">
@@ -53,56 +51,44 @@
<div id="${trans.security.encode_id( visualization.id )}" class="unified-panel-body" style="overflow:none;top:0px;"></div>
<script type="text/javascript">
require.config({
baseUrl: "${h.url_for('/static/scripts') }",
shim: {
"libs/underscore": { exports: "_" },
"libs/backbone": { exports: "Backbone" },
},
urlArgs: 'v=${app.server_starttime}'
});
require( ["viz/trackster"], function(trackster) {
// FIXME: deliberate global required for now due to requireJS integration.
view = null;
// FIXME: deliberate global required for now due to requireJS integration.
view = null;
var ui = new (window.bundleEntries.Trackster.TracksterUI)( "${h.url_for('/')}" );
var container_element = $("#${trans.security.encode_id( visualization.id )}");
var ui = new (trackster.default.TracksterUI)( "${h.url_for('/')}" )
container_element = $("#${trans.security.encode_id( visualization.id )}");
$(function() {
var is_embedded = (container_element.parents(".item-content").length > 0);
$(function() {
var is_embedded = (container_element.parents(".item-content").length > 0);
// HTML setup.
if (is_embedded) {
container_element.css( { "position": "relative" } );
} else { // Viewing just one shared viz
$("#right-border").click(function() { view.resize_window(); });
}
// HTML setup.
if (is_embedded) {
container_element.css( { "position": "relative" } );
} else { // Viewing just one shared viz
$("#right-border").click(function() { view.resize_window(); });
}
// Create visualization.
var callback;
%if 'viewport' in config:
var callback = function() { view.change_chrom( '${config['viewport']['chrom']}', ${config['viewport']['start']}, ${config['viewport']['end']} ); }
%endif
view = ui.create_visualization( {
container: container_element,
name: "${config.get('title') | h}",
vis_id: "${config.get('vis_id')}",
dbkey: "${config.get('dbkey')}"
},
${ h.dumps( config.get( 'viewport', dict() ) ) },
${ h.dumps( config['tracks'] ) },
${ h.dumps( config.get('bookmarks') ) }
);
// Create visualization.
var callback;
%if 'viewport' in config:
var callback = function() { view.change_chrom( '${config['viewport']['chrom']}', ${config['viewport']['start']}, ${config['viewport']['end']} ); }
%endif
view = ui.create_visualization( {
container: container_element,
name: "${config.get('title') | h}",
vis_id: "${config.get('vis_id')}",
dbkey: "${config.get('dbkey')}"
},
${ h.dumps( config.get( 'viewport', dict() ) ) },
${ h.dumps( config['tracks'] ) },
${ h.dumps( config.get('bookmarks') ) }
);
// Set up keyboard navigation.
ui.init_keyboard_nav(view);
// HACK: set viewport height because it cannot be set automatically. Currently, max height for embedded
// elts is 25em, so use 20em.
view.viewport_container.height("20em");
});
// Set up keyboard navigation.
ui.init_keyboard_nav(view);
// HACK: set viewport height because it cannot be set automatically. Currently, max height for embedded
// elts is 25em, so use 20em.
view.viewport_container.height("20em");
});
</script>
@@ -138,41 +138,23 @@
<%def name="javascripts()">
${parent.javascripts()}
${h.js( "libs/require" )}
<script type="text/javascript">
require.config({
baseUrl: "${h.url_for('/static/scripts')}",
shim: {
"libs/underscore": { exports: "_" },
"libs/d3": { exports: "d3" }
},
urlArgs: 'v=${app.server_starttime}'
});
$(function(){
var config = ${ h.dumps( config )};
var data = ${h.dumps(data['data'])};
require(["viz/phyloviz"], function(phyloviz_mod) {
function initPhyloViz(data, config) {
var phyloviz;
// -- Initialization code |-->
phyloviz = new phyloviz_mod.default.PhylovizView({
data : data,
layout : "Linear",
config : config
});
// -- Render viz. --
phyloviz.render();
};
$(function firstVizLoad(){ // calls when viz is loaded for the first time
var config = ${ h.dumps( config )};
var data = ${h.dumps(data['data'])};
initPhyloViz(data, config);
// -- Initialization code |-->
var phyloviz = new bundleEntries.phyloviz({
data : data,
layout : "Linear",
config : config
});
// -- Render viz. --
phyloviz.render();
});
</script>
@@ -109,31 +109,13 @@
${h.js( "libs/jquery/jquery-ui" )}
<script type="text/javascript">
// require.config({
// baseUrl: "${h.url_for('/static/scripts') }",
// shim: {
// "libs/underscore": { exports: "_" },
// "libs/backbone": {
// deps: [ 'jquery', 'libs/underscore' ],
// exports: "Backbone"
// },
// "libs/d3": { exports: "d3" },
// },
// // cache buster based on templated server (re)start time
// urlArgs: 'v=${app.server_starttime}'
// });
require(["viz/sweepster"], function(sweepster) {
var viz;
$(function() {
// -- Viz set up. --
var viz = new sweepster.default.SweepsterVisualization(
${ h.dumps( config )}
);
var viz_view = new sweepster.default.SweepsterVisualizationView({ model: viz });
viz_view.render();
});
$(function() {
// -- Viz set up. --
var viz = new window.bundleEntries.SweepsterVisualization(
${ h.dumps( config )}
);
var viz_view = new window.bundleEntries.SweepsterVisualizationView({ model: viz });
viz_view.render();
});
</script>
</%def>
+7 -7
View File
@@ -5,13 +5,13 @@
${parent.javascripts()}
<script type="text/javascript">
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");
run_stats.create_chart(${jc_dy_data}, "jc_dy_chart", "days", "Jobs Created per Day");
run_stats.create_histogram(${et_hr_data}, "et_hr_chart", "Job Run Times (past day)");
run_stats.create_histogram(${et_dy_data}, "et_dy_chart", "Job Run Time (past 30 days)");
$(function(){
window.bundleEntries.run_stats.create_chart(${jf_hr_data}, "jf_hr_chart", "hours", "Jobs Finished per Hour");
window.bundleEntries.run_stats.create_chart(${jf_dy_data}, "jf_dy_chart", "days", "Jobs Finished per Day");
window.bundleEntries.run_stats.create_chart(${jc_hr_data}, "jc_hr_chart", "hours", "Jobs Created per Hour");
window.bundleEntries.run_stats.create_chart(${jc_dy_data}, "jc_dy_chart", "days", "Jobs Created per Day");
window.bundleEntries.run_stats.create_histogram(${et_hr_data}, "et_hr_chart", "Job Run Times (past day)");
window.bundleEntries.run_stats.create_histogram(${et_dy_data}, "et_dy_chart", "Job Run Time (past 30 days)");
});
</script>
</%def>
+1 -8
View File
@@ -41,14 +41,7 @@
<script type="text/javascript">
window.globalTS = new Object();
$( function(){
require.config({
paths: {
'toolshed': '../toolshed'
}
});
require([ '${config.get( "app" ).get( "jscript" )}' ], function( groups ){
app = new groups.default.ToolshedGroups();
});
new window.bundleEntries.ToolshedGroups.ToolshedGroups();
});
</script>
<div id="groups_element" style="width: 95%; margin:auto; margin-top:2em; "></div>
+1 -1
View File
@@ -29,7 +29,7 @@ class ConfigurationApiTestCase(api.ApiTestCase):
def setUp(self):
super(ConfigurationApiTestCase, self).setUp()
self.library_populator = LibraryPopulator(self)
self.library_populator = LibraryPopulator(self.galaxy_interactor)
def test_normal_user_configuration(self):
config = self._get_configuration()
+1 -1
View File
@@ -22,7 +22,7 @@ class HistoryContentsApiTestCase(api.ApiTestCase, TestsDatasets):
self.history_id = self._new_history()
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
self.dataset_collection_populator = DatasetCollectionPopulator(self.galaxy_interactor)
self.library_populator = LibraryPopulator(self)
self.library_populator = LibraryPopulator(self.galaxy_interactor)
def test_index_hda_summary(self):
hda1 = self._new_dataset(self.history_id)
+1 -1
View File
@@ -13,7 +13,7 @@ class LibrariesApiTestCase(api.ApiTestCase, TestsDatasets):
super(LibrariesApiTestCase, self).setUp()
self.dataset_populator = DatasetPopulator(self.galaxy_interactor)
self.dataset_collection_populator = DatasetCollectionPopulator(self.galaxy_interactor)
self.library_populator = LibraryPopulator(self)
self.library_populator = LibraryPopulator(self.galaxy_interactor)
def test_create(self):
data = dict(name="CreateTestLibrary")
+1 -1
View File
@@ -259,7 +259,7 @@ class ToolsTestCase(api.ApiTestCase):
@skip_without_tool("library_data")
def test_library_data_param(self):
with self.dataset_populator.test_history() as history_id:
ld = LibraryPopulator(self).new_library_dataset("lda_test_library")
ld = LibraryPopulator(self.galaxy_interactor).new_library_dataset("lda_test_library")
inputs = {
"library_dataset": ld["ldda_id"],
"library_dataset_multiple": [ld["ldda_id"], ld["ldda_id"]]
+25 -13
View File
@@ -461,9 +461,8 @@ class WorkflowPopulator(BaseWorkflowPopulator, ImporterGalaxyInterface):
class LibraryPopulator(object):
def __init__(self, api_test_case):
self.api_test_case = api_test_case
self.galaxy_interactor = api_test_case.galaxy_interactor
def __init__(self, galaxy_interactor):
self.galaxy_interactor = galaxy_interactor
def new_private_library(self, name):
library = self.new_library(name)
@@ -500,44 +499,57 @@ class LibraryPopulator(object):
def user_private_role_id(self):
user_email = self.user_email()
roles_response = self.api_test_case.galaxy_interactor.get("roles", admin=True)
roles_response = self.galaxy_interactor.get("roles", admin=True)
users_roles = [r for r in roles_response.json() if r["name"] == user_email]
assert len(users_roles) == 1
return users_roles[0]["id"]
def create_dataset_request(self, library, **kwds):
upload_option = kwds.get("upload_option", "upload_file")
create_data = {
"folder_id": kwds.get("folder_id", library["root_folder_id"]),
"create_type": "file",
"files_0|NAME": kwds.get("name", "NewFile"),
"upload_option": kwds.get("upload_option", "upload_file"),
"upload_option": upload_option,
"file_type": kwds.get("file_type", "auto"),
"db_key": kwds.get("db_key", "?"),
}
files = {
"files_0|file_data": kwds.get("file", StringIO(kwds.get("contents", "TestData"))),
}
if upload_option == "upload_file":
files = {
"files_0|file_data": kwds.get("file", StringIO(kwds.get("contents", "TestData"))),
}
elif upload_option == "upload_paths":
create_data["filesystem_paths"] = kwds["paths"]
files = {}
elif upload_option == "upload_directory":
create_data["server_dir"] = kwds["server_dir"]
files = {}
return create_data, files
def new_library_dataset(self, name, **create_dataset_kwds):
library = self.new_private_library(name)
payload, files = self.create_dataset_request(library, **create_dataset_kwds)
url_rel = "libraries/%s/contents" % (library["id"])
dataset = self.api_test_case.galaxy_interactor.post(url_rel, payload, files=files).json()[0]
dataset = self.raw_library_contents_create(library["id"], payload, files=files).json()[0]
def show():
return self.api_test_case.galaxy_interactor.get("libraries/%s/contents/%s" % (library["id"], dataset["id"]))
return self.galaxy_interactor.get("libraries/%s/contents/%s" % (library["id"], dataset["id"]))
wait_on_state(show, timeout=DEFAULT_TIMEOUT)
return show().json()
def raw_library_contents_create(self, library_id, payload, files={}):
url_rel = "libraries/%s/contents" % library_id
return self.galaxy_interactor.post(url_rel, payload, files=files)
def show_ldda(self, library_id, library_dataset_id):
return self.api_test_case.galaxy_interactor.get("libraries/%s/contents/%s" % (library_id, library_dataset_id))
return self.galaxy_interactor.get("libraries/%s/contents/%s" % (library_id, library_dataset_id))
def new_library_dataset_in_private_library(self, library_name="private_dataset", wait=True):
library = self.new_private_library(library_name)
payload, files = self.create_dataset_request(library, file_type="txt", contents="create_test")
create_response = self.api_test_case.galaxy_interactor.post("libraries/%s/contents" % library["id"], payload, files=files)
create_response = self.galaxy_interactor.post("libraries/%s/contents" % library["id"], payload, files=files)
api_asserts.assert_status_code_is(create_response, 200)
library_datasets = create_response.json()
assert len(library_datasets) == 1
+26 -2
View File
@@ -612,6 +612,11 @@ class NavigatesGalaxy(HasDriver):
self.components.masthead.libraries.wait_for_and_click()
self.components.libraries.selector.wait_for_visible()
def libraries_open_with_name(self, name):
self.libraries_open()
self.libraries_index_search_for(name)
self.libraries_index_table_elements()[0].find_element_by_css_selector("td a").click()
@retry_during_transitions
def libraries_index_table_elements(self):
container = self.wait_for_selector_visible(".library_container")
@@ -657,8 +662,7 @@ class NavigatesGalaxy(HasDriver):
self.driver.execute_script("$(arguments[0]).keyup();", search_box)
def libraries_folder_create(self, name):
create_folder_button = self.wait_for_selector_clickable("#toolbtn_create_folder")
create_folder_button.click()
self.components.libraries.folder.add_folder.wait_for_and_click()
name_text_box = self.wait_for_selector_clickable("input[name='Name']")
name_text_box.send_keys(name)
@@ -681,6 +685,26 @@ class NavigatesGalaxy(HasDriver):
self.wait_for_visible(self.navigation.libraries.folder.selectors.add_items_menu)
self.wait_for_and_click(self.navigation.libraries.folder.labels.from_path)
def libraries_dataset_import_from_history_select(self, to_select_items):
self.wait_for_visible(self.navigation.libraries.folder.selectors.import_history_content)
history_elements = self.find_elements(self.navigation.libraries.folder.selectors.import_history_contents_items)
for to_select_item in to_select_items:
found = False
for history_element in history_elements:
if to_select_item in history_element.text:
history_element.find_element_by_css_selector("input").click()
found = True
break
if not found:
raise Exception("Failed to find history item [%s] to select" % to_select_item)
def libraries_dataset_import_from_history_click_ok(self, wait=True):
self.wait_for_and_click(self.navigation.libraries.folder.selectors.import_datasets_ok_button)
if wait:
# Let the progress bar disappear...
self.wait_for_absent_or_hidden(self.navigation.libraries.folder.selectors.import_progress_bar)
def libraries_table_elements(self):
tbody_element = self.wait_for_selector_visible("#folder_list_body")
return tbody_element.find_elements_by_css_selector("tr")[1:]

Some files were not shown because too many files have changed in this diff Show More