mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'dev' into remove_unused_workflow_endpoint
This commit is contained in:
@@ -16,6 +16,7 @@ env:
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: TOX_ENV=check-python-dependencies
|
||||
- env: TOX_ENV=qunit
|
||||
|
||||
addons:
|
||||
apt:
|
||||
|
||||
@@ -138,6 +138,9 @@ client-watch: node-deps ## A useful target for parallel development building.
|
||||
cd client && yarn run watch
|
||||
@echo "Remember to 'make client' when finished developing!"
|
||||
|
||||
client-test:
|
||||
cd client && yarn run test
|
||||
|
||||
charts: node-deps ## Rebuild charts
|
||||
cd client && yarn run build-charts
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import AdminToolshed from "admin.toolshed";
|
||||
|
||||
export function App(options) {
|
||||
new AdminToolshed.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.adminToolshedApp = App;
|
||||
@@ -9,6 +9,8 @@ import QueryStringParsing from "utils/query-string-parsing";
|
||||
import Router from "layout/router";
|
||||
import Utils from "utils/utils";
|
||||
import Page from "layout/page";
|
||||
import Vue from "libs/vue";
|
||||
import UserAPIKeys from "components/user_api_keys.vue";
|
||||
|
||||
window.app = function app(options, bootstrapped) {
|
||||
window.Galaxy = new GalaxyApp.GalaxyApp(options, bootstrapped);
|
||||
@@ -24,7 +26,8 @@ window.app = function app(options, bootstrapped) {
|
||||
"(/)admin(/)quotas": "show_quotas",
|
||||
"(/)admin(/)repositories": "show_repositories",
|
||||
"(/)admin(/)forms": "show_forms",
|
||||
"(/)admin(/)form(/)(:form_id)": "show_form"
|
||||
"(/)admin(/)form(/)(:form_id)": "show_form",
|
||||
"(/)admin/api_keys": "show_user_api_keys"
|
||||
},
|
||||
|
||||
authenticate: function(args, name) {
|
||||
@@ -91,6 +94,12 @@ window.app = function app(options, bootstrapped) {
|
||||
);
|
||||
},
|
||||
|
||||
show_user_api_keys: function() {
|
||||
var vuemount = document.createElement("div");
|
||||
this.page.display(vuemount);
|
||||
new Vue(UserAPIKeys).$mount(vuemount);
|
||||
},
|
||||
|
||||
show_forms: function() {
|
||||
this.page.display(
|
||||
new GridView({
|
||||
|
||||
@@ -20,6 +20,8 @@ import Utils from "utils/utils";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import DatasetError from "mvc/dataset/dataset-error";
|
||||
import DatasetEditAttributes from "mvc/dataset/dataset-edit-attributes";
|
||||
import Citations from "components/citations.vue";
|
||||
import Vue from "libs/vue";
|
||||
|
||||
/** define the 'Analyze Data'/analysis/main/home page for Galaxy
|
||||
* * has a masthead
|
||||
@@ -54,6 +56,7 @@ window.app = function app(options, bootstrapped) {
|
||||
"(/)workflows(/)list": "show_workflows",
|
||||
"(/)workflows/list_published(/)": "show_workflows_published",
|
||||
"(/)workflows/create(/)": "show_workflows_create",
|
||||
"(/)histories(/)citations(/)": "show_history_citations",
|
||||
"(/)histories(/)rename(/)": "show_histories_rename",
|
||||
"(/)histories(/)permissions(/)": "show_histories_permissions",
|
||||
"(/)histories(/)(:action_id)": "show_histories",
|
||||
@@ -120,6 +123,13 @@ window.app = function app(options, bootstrapped) {
|
||||
this.page.display(new HistoryList.View({ action_id: action_id }));
|
||||
},
|
||||
|
||||
show_history_citations: function() {
|
||||
var citationInstance = Vue.extend(Citations);
|
||||
var vm = document.createElement("div");
|
||||
this.page.display(vm);
|
||||
new citationInstance({ propsData: { id: QueryStringParsing.get("id"), source: "histories" } }).$mount(vm);
|
||||
},
|
||||
|
||||
show_histories_rename: function() {
|
||||
this.page.display(
|
||||
new FormWrapper.View({
|
||||
@@ -197,11 +207,10 @@ window.app = function app(options, bootstrapped) {
|
||||
},
|
||||
|
||||
show_custom_builds: function() {
|
||||
var self = this;
|
||||
var historyPanel = this.page.historyPanel.historyView;
|
||||
if (!historyPanel || !historyPanel.model || !historyPanel.model.id) {
|
||||
window.setTimeout(() => {
|
||||
self.show_custom_builds();
|
||||
this.show_custom_builds();
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
@@ -257,20 +266,19 @@ window.app = function app(options, bootstrapped) {
|
||||
|
||||
/** load workflow by its url in run mode */
|
||||
_loadWorkflow: function() {
|
||||
var self = this;
|
||||
Utils.get({
|
||||
url: `${Galaxy.root}api/workflows/${Utils.getQueryString("id")}/download?style=run`,
|
||||
success: function(response) {
|
||||
self.page.display(new ToolFormComposite.View(response));
|
||||
success: response => {
|
||||
this.page.display(new ToolFormComposite.View(response));
|
||||
},
|
||||
error: function(response) {
|
||||
error: response => {
|
||||
var error_msg = response.err_msg || "Error occurred while loading the resource.";
|
||||
var options = {
|
||||
message: error_msg,
|
||||
status: "danger",
|
||||
persistent: true
|
||||
};
|
||||
self.page.display(new Ui.Message(options));
|
||||
this.page.display(new Ui.Message(options));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import GalaxyLibrary from "galaxy.library";
|
||||
|
||||
export function App(options) {
|
||||
new GalaxyLibrary.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.libraryApp = App;
|
||||
@@ -0,0 +1,16 @@
|
||||
import Masthead from "layout/masthead";
|
||||
import user from "mvc/user/user-model";
|
||||
import Modal from "mvc/ui/ui-modal";
|
||||
|
||||
export default function masthead(options) {
|
||||
if (!Galaxy.user) {
|
||||
Galaxy.user = new user.User(options.user_json);
|
||||
}
|
||||
if (!Galaxy.masthead) {
|
||||
Galaxy.masthead = new Masthead.View(options);
|
||||
Galaxy.modal = new Modal.View();
|
||||
$("#masthead").replaceWith(Galaxy.masthead.render().$el);
|
||||
}
|
||||
}
|
||||
|
||||
window.masthead = masthead;
|
||||
@@ -69,7 +69,8 @@ var AdminPanel = Backbone.View.extend({
|
||||
},
|
||||
{
|
||||
title: "API keys",
|
||||
url: "userskeys/all_users"
|
||||
url: "admin/api_keys",
|
||||
target: "__use_router__"
|
||||
},
|
||||
{
|
||||
title: "Impersonate a user",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import Trackster from "viz/trackster";
|
||||
import Circster from "viz/circster";
|
||||
|
||||
export function tracksterApp(options) {
|
||||
new Trackster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export function circsterApp(options) {
|
||||
new Circster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.tracksterApp = tracksterApp;
|
||||
window.circsterApp = circsterApp;
|
||||
@@ -0,0 +1,7 @@
|
||||
import WorkflowView from "mvc/workflow/workflow-view";
|
||||
|
||||
export default function workflowApp(options) {
|
||||
new WorkflowView(options);
|
||||
}
|
||||
|
||||
window.workflowApp = workflowApp;
|
||||
@@ -0,0 +1,202 @@
|
||||
<template>
|
||||
<div class="toolForm">
|
||||
<div class="toolFormTitle">
|
||||
Citations
|
||||
<button v-if="viewRender" v-on:click="toggleViewRender" type="button" class="btn btn-xs" title="Show all in BibTeX format.">
|
||||
<i class="fa fa-pencil-square-o"></i>
|
||||
Show BibTeX
|
||||
</button>
|
||||
<button v-else type="button" v-on:click="toggleViewRender" class="btn btn-xs" title="Return to formatted citation list.">
|
||||
<i class="fa fa-times"></i>
|
||||
Hide BibTeX
|
||||
</button>
|
||||
</div>
|
||||
<div class="citations-bibtex toolFormBody citation-padding">
|
||||
<div v-if="source === 'histories'" class="infomessage">
|
||||
When writing up your analysis, remember to include all references that should be cited in order
|
||||
to completely describe your work. Also, please remember to <a href="https://galaxyproject.org/citing-galaxy">cite Galaxy</a>.
|
||||
</div>
|
||||
<span v-if="viewRender" class="citations-formatted">
|
||||
<p v-html="formattedReferences">
|
||||
</p>
|
||||
</span>
|
||||
<textarea v-else class="citations-bibtex-text">
|
||||
{{ content }}
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import axios from "axios";
|
||||
import * as bibtexParse from "libs/bibtexParse";
|
||||
import { convertLaTeX } from "latex-to-unicode-converter";
|
||||
import { stringifyLaTeX } from "latex-parser";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
source: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
viewRender: {
|
||||
type: Boolean,
|
||||
requried: false,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
citations: [],
|
||||
content: "",
|
||||
errors: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
formattedReferences: function() {
|
||||
return this.citations.reduce((a, b) => a.concat(`<p class="formatted-reference">${this.formattedReference(b)}</p>`), "");
|
||||
}
|
||||
},
|
||||
created: function() {
|
||||
axios
|
||||
.get(`${Galaxy.root}api/${this.source}/${this.id}/citations`)
|
||||
.then(response => {
|
||||
this.content = "";
|
||||
for (var rawCitation of response.data) {
|
||||
try {
|
||||
var citation = {
|
||||
fields: {},
|
||||
entryType: undefined
|
||||
};
|
||||
var parsed = bibtexParse.toJSON(rawCitation.content);
|
||||
if (parsed) {
|
||||
parsed = _.first(parsed);
|
||||
citation.entryType = parsed.entryType || undefined;
|
||||
for (var key in parsed.entryTags) {
|
||||
citation.fields[key.toLowerCase()] = parsed.entryTags[key];
|
||||
}
|
||||
}
|
||||
this.citations.push(citation);
|
||||
this.content += rawCitation.content;
|
||||
} catch (err) {
|
||||
console.warn("Error parsing bibtex: " + err);
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
formattedReference: function(citation) {
|
||||
var entryType = citation.entryType;
|
||||
var fields = citation.fields;
|
||||
|
||||
var ref = "";
|
||||
var authorsAndYear = `${this._asSentence(
|
||||
(fields.author ? fields.author : "") + (fields.year ? ` (${fields.year})` : "")
|
||||
)} `;
|
||||
var title = fields.title || "";
|
||||
var pages = fields.pages ? `pp. ${fields.pages}` : "";
|
||||
var address = fields.address;
|
||||
if (entryType == "article") {
|
||||
var volume =
|
||||
(fields.volume ? fields.volume : "") +
|
||||
(fields.number ? ` (${fields.number})` : "") +
|
||||
(pages ? `, ${pages}` : "");
|
||||
ref = `${authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.journal ? `In <em>${fields.journal}, ` : "") +
|
||||
this._asSentence(volume) +
|
||||
this._asSentence(fields.address)}</em>`;
|
||||
} else if (entryType == "inproceedings" || entryType == "proceedings") {
|
||||
ref = `${authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.booktitle ? `In <em>${fields.booktitle}, ` : "") +
|
||||
(pages ? pages : "") +
|
||||
(address ? `, ${address}` : "")}.</em>`;
|
||||
} else if (entryType == "mastersthesis" || entryType == "phdthesis") {
|
||||
ref =
|
||||
authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.howpublished ? `${fields.howpublished}. ` : "") +
|
||||
(fields.note ? `${fields.note}.` : "");
|
||||
} else if (entryType == "techreport") {
|
||||
ref =
|
||||
authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
this._asSentence(fields.institution) +
|
||||
this._asSentence(fields.number) +
|
||||
this._asSentence(fields.type);
|
||||
} else if (entryType == "book" || entryType == "inbook" || entryType == "incollection") {
|
||||
ref = `${authorsAndYear} ${this._formatBookInfo(fields)}`;
|
||||
} else {
|
||||
ref = `${authorsAndYear} ${this._asSentence(title)}${this._asSentence(
|
||||
fields.howpublished
|
||||
)}${this._asSentence(fields.note)}`;
|
||||
}
|
||||
var doiUrl = "";
|
||||
if (fields.doi) {
|
||||
doiUrl = `http://dx.doi.org/${fields.doi}`;
|
||||
ref += `[<a href="${doiUrl}" target="_blank">doi:${fields.doi}</a>]`;
|
||||
}
|
||||
var url = fields.url || doiUrl;
|
||||
if (url) {
|
||||
ref += `[<a href="${url}" target="_blank">Link</a>]`;
|
||||
}
|
||||
return convertLaTeX({ onError: (error, latex) => `{${stringifyLaTeX(latex)}}` }, ref);
|
||||
},
|
||||
_formatBookInfo: function(fields) {
|
||||
var info = "";
|
||||
if (fields.chapter) {
|
||||
info += `${fields.chapter} in `;
|
||||
}
|
||||
if (fields.title) {
|
||||
info += `<em>${fields.title}</em>`;
|
||||
}
|
||||
if (fields.editor) {
|
||||
info += `, Edited by ${fields.editor}, `;
|
||||
}
|
||||
if (fields.publisher) {
|
||||
info += `, ${fields.publisher}`;
|
||||
}
|
||||
if (fields.pages) {
|
||||
info += `, pp. ${fields.pages}`;
|
||||
}
|
||||
if (fields.series) {
|
||||
info += `, <em>${fields.series}</em>`;
|
||||
}
|
||||
if (fields.volume) {
|
||||
info += `, Vol.${fields.volume}`;
|
||||
}
|
||||
if (fields.issn) {
|
||||
info += `, ISBN: ${fields.issn}`;
|
||||
}
|
||||
return `${info}.`;
|
||||
},
|
||||
_asSentence: function(str) {
|
||||
return str && str.trim() ? `${str}. ` : "";
|
||||
},
|
||||
toggleViewRender: function() {
|
||||
this.viewRender = !this.viewRender;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
.citations-formatted{
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.citations-bibtex-text{
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.citation-padding{
|
||||
padding:5px 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div id="form-userkeys" class="toolForm" v-cloak>
|
||||
<div class="toolFormTitle">User Information</div>
|
||||
<div v-if="users && users.length > 0">
|
||||
<table class="grid">
|
||||
<thead><th>Encoded UID</th><th>Email</th><th>API Key</th><th>Actions</th></thead>
|
||||
<tbody>
|
||||
<tr v-for="user in users">
|
||||
<td>
|
||||
{{ user.uid }}
|
||||
</td>
|
||||
<td>
|
||||
{{ user.email }}
|
||||
</td>
|
||||
<td>
|
||||
{{ user.key }}
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" value="Generate a new key now" v-on:click="generateKey( user.uid )" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div>No user information available</div>
|
||||
</div>
|
||||
<div style="clear: both"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// Should really do something with errors here. Eventually.
|
||||
users: [],
|
||||
errors: []
|
||||
};
|
||||
},
|
||||
created: function() {
|
||||
axios
|
||||
.get(`${Galaxy.root}userskeys/all_users`)
|
||||
.then(response => {
|
||||
this.users = response.data;
|
||||
})
|
||||
.catch(e => {
|
||||
this.errors.push(e);
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
generateKey: function(id) {
|
||||
axios
|
||||
.get(`${Galaxy.root}userskeys/admin_api_keys`, { params: { uid: id } })
|
||||
.then(response => {
|
||||
this.users = response.data;
|
||||
})
|
||||
.catch(e => {
|
||||
this.errors.push(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
</style>
|
||||
@@ -2,7 +2,6 @@
|
||||
// === MAIN GALAXY LIBRARY MODULE ====
|
||||
// MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
|
||||
|
||||
import mod_masthead from "layout/masthead";
|
||||
import mod_utils from "utils/utils";
|
||||
import mod_toastr from "libs/toastr";
|
||||
import mod_baseMVC from "mvc/base-mvc";
|
||||
|
||||
@@ -230,7 +230,7 @@ var CenterPanel = Backbone.View.extend({
|
||||
this.$panel
|
||||
.empty()
|
||||
.scrollTop(0)
|
||||
.append(view.$el)
|
||||
.append(view.$el || view)
|
||||
.show();
|
||||
Galaxy.trigger("center-panel:load", view);
|
||||
}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import * as parseBibtex from "libs/bibtex";
|
||||
import baseMVC from "mvc/base-mvc";
|
||||
import _l from "utils/localization";
|
||||
|
||||
/* global Backbone */
|
||||
|
||||
_.extend(parseBibtex.ENTRY_TYPES_, {
|
||||
online: 998, // Galaxy MOD: Handle @online entries for preprints.
|
||||
data: 999 // Galaxy MOD: Handle @data citations coming from figshare.
|
||||
});
|
||||
|
||||
var logNamespace = "citation";
|
||||
//==============================================================================
|
||||
/** @class model for tool citations.
|
||||
* @name Citation
|
||||
* @augments Backbone.Model
|
||||
*/
|
||||
var Citation = Backbone.Model.extend(baseMVC.LoggableMixin).extend({
|
||||
_logNamespace: logNamespace,
|
||||
|
||||
defaults: {
|
||||
content: ""
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
var parsed;
|
||||
try {
|
||||
// TODO: to model.parse/.validate
|
||||
parsed = parseBibtex(this.attributes.content);
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
// bibtex returns successfully parsed in .entries and any parsing errors in .errors
|
||||
if (parsed.errors.length) {
|
||||
// the gen. form of these errors seems to be [ line, col, char, error message ]
|
||||
var errors = parsed.errors.reduce((all, current) => `${all}; ${current}`);
|
||||
// throw new Error( 'Error parsing bibtex: ' + errors );
|
||||
this.log(`Error parsing bibtex: ${errors}`);
|
||||
}
|
||||
|
||||
this._fields = {};
|
||||
this.entry = _.first(parsed.entries);
|
||||
if (this.entry) {
|
||||
var rawFields = this.entry.Fields;
|
||||
for (var key in rawFields) {
|
||||
var value = rawFields[key];
|
||||
var lowerKey = key.toLowerCase();
|
||||
this._fields[lowerKey] = value;
|
||||
}
|
||||
}
|
||||
},
|
||||
entryType: function() {
|
||||
return this.entry ? this.entry.EntryType : undefined;
|
||||
},
|
||||
fields: function() {
|
||||
return this._fields;
|
||||
}
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
/** @class Backbone collection of citations.
|
||||
*/
|
||||
var BaseCitationCollection = Backbone.Collection.extend(baseMVC.LoggableMixin).extend({
|
||||
_logNamespace: logNamespace,
|
||||
|
||||
/** root api url */
|
||||
urlRoot: `${Galaxy.root}api`,
|
||||
partial: true, // Assume some tools in history/workflow may not be properly annotated yet.
|
||||
model: Citation
|
||||
});
|
||||
|
||||
var HistoryCitationCollection = BaseCitationCollection.extend({
|
||||
/** complete api url */
|
||||
url: function() {
|
||||
return `${this.urlRoot}/histories/${this.history_id}/citations`;
|
||||
}
|
||||
});
|
||||
|
||||
var ToolCitationCollection = BaseCitationCollection.extend({
|
||||
/** complete api url */
|
||||
url: function() {
|
||||
return `${this.urlRoot}/tools/${this.tool_id}/citations`;
|
||||
},
|
||||
partial: false // If a tool has citations, assume they are complete.
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
|
||||
export default {
|
||||
Citation: Citation,
|
||||
HistoryCitationCollection: HistoryCitationCollection,
|
||||
ToolCitationCollection: ToolCitationCollection
|
||||
};
|
||||
@@ -1,189 +0,0 @@
|
||||
import baseMVC from "mvc/base-mvc";
|
||||
import citationModel from "mvc/citation/citation-model";
|
||||
import _l from "utils/localization";
|
||||
var CitationView = Backbone.View.extend({
|
||||
tagName: "div",
|
||||
className: "citations",
|
||||
render: function() {
|
||||
this.$el.append(`<p>${this.formattedReference()}</p>`);
|
||||
return this;
|
||||
},
|
||||
formattedReference: function() {
|
||||
var model = this.model;
|
||||
var entryType = model.entryType();
|
||||
var fields = model.fields();
|
||||
|
||||
var ref = "";
|
||||
// Code inspired by...
|
||||
// https://github.com/vkaravir/bib-publication-list/blob/master/src/bib-publication-list.js
|
||||
var authorsAndYear = `${this._asSentence(
|
||||
(fields.author ? fields.author : "") + (fields.year ? ` (${fields.year})` : "")
|
||||
)} `;
|
||||
var title = fields.title || "";
|
||||
var pages = fields.pages ? `pp. ${fields.pages}` : "";
|
||||
var address = fields.address;
|
||||
if (entryType == "article") {
|
||||
var volume =
|
||||
(fields.volume ? fields.volume : "") +
|
||||
(fields.number ? ` (${fields.number})` : "") +
|
||||
(pages ? `, ${pages}` : "");
|
||||
ref = `${authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.journal ? `In <em>${fields.journal}, ` : "") +
|
||||
this._asSentence(volume) +
|
||||
this._asSentence(fields.address)}</em>`;
|
||||
} else if (entryType == "inproceedings" || entryType == "proceedings") {
|
||||
ref = `${authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.booktitle ? `In <em>${fields.booktitle}, ` : "") +
|
||||
(pages ? pages : "") +
|
||||
(address ? `, ${address}` : "")}.</em>`;
|
||||
} else if (entryType == "mastersthesis" || entryType == "phdthesis") {
|
||||
ref =
|
||||
authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
(fields.howpublished ? `${fields.howpublished}. ` : "") +
|
||||
(fields.note ? `${fields.note}.` : "");
|
||||
} else if (entryType == "techreport") {
|
||||
ref =
|
||||
authorsAndYear +
|
||||
this._asSentence(title) +
|
||||
this._asSentence(fields.institution) +
|
||||
this._asSentence(fields.number) +
|
||||
this._asSentence(fields.type);
|
||||
} else if (entryType == "book" || entryType == "inbook" || entryType == "incollection") {
|
||||
ref = `${authorsAndYear} ${this._formatBookInfo(fields)}`;
|
||||
} else {
|
||||
ref = `${authorsAndYear} ${this._asSentence(title)}${this._asSentence(
|
||||
fields.howpublished
|
||||
)}${this._asSentence(fields.note)}`;
|
||||
}
|
||||
var doiUrl = "";
|
||||
if (fields.doi) {
|
||||
doiUrl = `http://dx.doi.org/${fields.doi}`;
|
||||
ref += `[<a href="${doiUrl}" target="_blank">doi:${fields.doi}</a>]`;
|
||||
}
|
||||
var url = fields.url || doiUrl;
|
||||
if (url) {
|
||||
ref += `[<a href="${url}" target="_blank">Link</a>]`;
|
||||
}
|
||||
return ref;
|
||||
},
|
||||
_formatBookInfo: function(fields) {
|
||||
var info = "";
|
||||
if (fields.chapter) {
|
||||
info += `${fields.chapter} in `;
|
||||
}
|
||||
if (fields.title) {
|
||||
info += `<em>${fields.title}</em>`;
|
||||
}
|
||||
if (fields.editor) {
|
||||
info += `, Edited by ${fields.editor}, `;
|
||||
}
|
||||
if (fields.publisher) {
|
||||
info += `, ${fields.publisher}`;
|
||||
}
|
||||
if (fields.pages) {
|
||||
info += `, pp. ${fields.pages}`;
|
||||
}
|
||||
if (fields.series) {
|
||||
info += `, <em>${fields.series}</em>`;
|
||||
}
|
||||
if (fields.volume) {
|
||||
info += `, Vol.${fields.volume}`;
|
||||
}
|
||||
if (fields.issn) {
|
||||
info += `, ISBN: ${fields.issn}`;
|
||||
}
|
||||
return `${info}.`;
|
||||
},
|
||||
_asSentence: function(str) {
|
||||
return str && str.trim() ? `${str}. ` : "";
|
||||
}
|
||||
});
|
||||
|
||||
var CitationListView = Backbone.View.extend({
|
||||
el: "#citations",
|
||||
/**
|
||||
* Set up view.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.listenTo(this.collection, "add", this.renderCitation);
|
||||
},
|
||||
|
||||
events: {
|
||||
"click .citations-to-bibtex": "showBibtex",
|
||||
"click .citations-to-formatted": "showFormatted"
|
||||
},
|
||||
|
||||
renderCitation: function(citation) {
|
||||
var citationView = new CitationView({ model: citation });
|
||||
this.$(".citations-formatted").append(citationView.render().el);
|
||||
var rawTextarea = this.$(".citations-bibtex-text");
|
||||
rawTextarea.val(`${rawTextarea.val()}\n\r${citation.attributes.content}`);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.citationsElement());
|
||||
this.collection.each(function(item) {
|
||||
this.renderCitation(item);
|
||||
}, this);
|
||||
this.showFormatted();
|
||||
},
|
||||
|
||||
showBibtex: function() {
|
||||
this.$(".citations-to-formatted").show();
|
||||
this.$(".citations-to-bibtex").hide();
|
||||
this.$(".citations-bibtex").show();
|
||||
this.$(".citations-formatted").hide();
|
||||
this.$(".citations-bibtex-text").select();
|
||||
},
|
||||
|
||||
showFormatted: function() {
|
||||
this.$(".citations-to-formatted").hide();
|
||||
this.$(".citations-to-bibtex").show();
|
||||
this.$(".citations-bibtex").hide();
|
||||
this.$(".citations-formatted").show();
|
||||
},
|
||||
|
||||
partialWarningElement: function() {
|
||||
if (this.collection.partial) {
|
||||
return [
|
||||
'<div style="padding:5px 10px">',
|
||||
"<b>Warning: This is a experimental feature.</b> Most Galaxy tools will not annotate",
|
||||
" citations explicitly at this time. When writing up your analysis, please manually",
|
||||
" review your histories and find all references",
|
||||
" that should be cited in order to completely describe your work. Also, please remember to",
|
||||
' <a href="https://galaxyproject.org/citing-galaxy">cite Galaxy</a>.',
|
||||
"</div>"
|
||||
].join("");
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
|
||||
citationsElement: function() {
|
||||
return [
|
||||
'<div class="toolForm">',
|
||||
'<div class="toolFormTitle">',
|
||||
_l("Citations"),
|
||||
' <button type="button" class="btn btn-xs citations-to-bibtex" title="Show all in BibTeX format."><i class="fa fa-pencil-square-o"></i> Show BibTeX</button>',
|
||||
' <button type="button" class="btn btn-xs citations-to-formatted" title="Return to formatted citation list."><i class="fa fa-times"></i> Hide BibTeX</button>',
|
||||
"</div>",
|
||||
'<div class="toolFormBody" style="padding:5px 10px">',
|
||||
this.partialWarningElement(),
|
||||
'<span class="citations-formatted" style="word-wrap: break-word;"></span>',
|
||||
"</div>",
|
||||
'<div class="citations-bibtex toolFormBody" style="padding:5px 10px">',
|
||||
'<textarea style="width: 100%; height: 500px;" class="citations-bibtex-text"></textarea>',
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("");
|
||||
}
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
export default {
|
||||
CitationView: CitationView,
|
||||
CitationListView: CitationListView
|
||||
};
|
||||
@@ -150,8 +150,12 @@ var menu = [
|
||||
},
|
||||
{
|
||||
html: _l("Export Tool Citations"),
|
||||
href: "history/citations",
|
||||
anon: true
|
||||
anon: true,
|
||||
func: function() {
|
||||
if (Galaxy && Galaxy.currHistoryPanel && Galaxy.router) {
|
||||
Galaxy.router.push(`/histories/citations?id=${Galaxy.currHistoryPanel.model.id}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
html: _l("Export History to File"),
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import mod_masthead from "layout/masthead";
|
||||
import mod_utils from "utils/utils";
|
||||
import mod_toastr from "libs/toastr";
|
||||
import mod_library_model from "mvc/library/library-model";
|
||||
import mod_library_folderrow_view from "mvc/library/library-folderrow-view";
|
||||
import mod_library_dataset_view from "mvc/library/library-dataset-view";
|
||||
|
||||
var FolderListView = Backbone.View.extend({
|
||||
el: "#folder_items_element",
|
||||
// progress percentage
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import mod_masthead from "layout/masthead";
|
||||
import mod_utils from "utils/utils";
|
||||
import mod_toastr from "libs/toastr";
|
||||
import mod_library_model from "mvc/library/library-model";
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// dependencies
|
||||
import mod_masthead from "layout/masthead";
|
||||
import mod_utils from "utils/utils";
|
||||
import mod_toastr from "libs/toastr";
|
||||
// galaxy library row view
|
||||
var LibraryRowView = Backbone.View.extend({
|
||||
|
||||
@@ -5,8 +5,8 @@ import Utils from "utils/utils";
|
||||
import Deferred from "utils/deferred";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import FormBase from "mvc/form/form-view";
|
||||
import CitationModel from "mvc/citation/citation-model";
|
||||
import CitationView from "mvc/citation/citation-view";
|
||||
import Citations from "components/citations.vue";
|
||||
import Vue from "libs/vue";
|
||||
export default FormBase.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
@@ -225,16 +225,15 @@ export default FormBase.extend({
|
||||
var options = this.model.attributes;
|
||||
var $el = $("<div/>").append(this._templateHelp(options));
|
||||
if (options.citations) {
|
||||
var $citations = $("<div/>");
|
||||
var citations = new CitationModel.ToolCitationCollection();
|
||||
citations.tool_id = options.id;
|
||||
var citation_list_view = new CitationView.CitationListView({
|
||||
el: $citations,
|
||||
collection: citations
|
||||
});
|
||||
citation_list_view.render();
|
||||
citations.fetch();
|
||||
$el.append($citations);
|
||||
var citationInstance = Vue.extend(Citations);
|
||||
var vm = document.createElement("div");
|
||||
$el.append(vm);
|
||||
new citationInstance({
|
||||
propsData: {
|
||||
id: options.id,
|
||||
source: "tools"
|
||||
}
|
||||
}).$mount(vm);
|
||||
}
|
||||
return $el;
|
||||
},
|
||||
|
||||
@@ -98,12 +98,14 @@ var Tool = Backbone.View.extend({
|
||||
__class__: "RuntimeValue"
|
||||
};
|
||||
input.is_workflow =
|
||||
(input.options && input.options.length == 0) || ["integer", "float"].indexOf(input.type) != -1;
|
||||
(input.options && input.options.length === 0) || ["integer", "float"].indexOf(input.type) != -1;
|
||||
}
|
||||
}
|
||||
});
|
||||
Utils.deepeach(options.inputs, input => {
|
||||
input.type == "conditional" && (input.test_param.collapsible_value = undefined);
|
||||
if (input.type === "conditional") {
|
||||
input.test_param.collapsible_value = undefined;
|
||||
}
|
||||
});
|
||||
_addSections(form);
|
||||
_addLabelAnnotation(form);
|
||||
@@ -151,182 +153,186 @@ function _addLabelAnnotation(form) {
|
||||
});
|
||||
}
|
||||
|
||||
/** Visit input nodes and enrich by name/value pairs from server data */
|
||||
function _visit(head, head_list, output_id, options) {
|
||||
var post_job_actions = options.node.post_job_actions;
|
||||
head_list = head_list || [];
|
||||
head_list.push(head);
|
||||
for (var i in head.inputs) {
|
||||
var input = head.inputs[i];
|
||||
var action = input.action;
|
||||
if (action) {
|
||||
input.name = `pja__${output_id}__${input.action}`;
|
||||
if (input.pja_arg) {
|
||||
input.name += `__${input.pja_arg}`;
|
||||
}
|
||||
if (input.payload) {
|
||||
for (var p_id in input.payload) {
|
||||
input.payload[`${input.name}__${p_id}`] = input.payload[p_id];
|
||||
delete input.payload[p_id];
|
||||
}
|
||||
}
|
||||
var d = post_job_actions[input.action + output_id];
|
||||
if (d) {
|
||||
for (var j in head_list) {
|
||||
head_list[j].expanded = true;
|
||||
}
|
||||
if (input.pja_arg) {
|
||||
input.value = (d.action_arguments && d.action_arguments[input.pja_arg]) || input.value;
|
||||
} else {
|
||||
input.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (input.inputs) {
|
||||
_visit(input, head_list.slice(0), output_id, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds sub section with step actions/annotation */
|
||||
function _makeSection(output_id, options) {
|
||||
var extensions = [];
|
||||
var input_terminal_names = [];
|
||||
var datatypes = options.datatypes;
|
||||
var node = options.node;
|
||||
var workflow = options.workflow;
|
||||
|
||||
for (var key in datatypes) {
|
||||
extensions.push({ 0: datatypes[key], 1: datatypes[key] });
|
||||
}
|
||||
for (key in node.input_terminals) {
|
||||
input_terminal_names.push(node.input_terminals[key].name);
|
||||
}
|
||||
extensions.sort((a, b) => (a.label > b.label ? 1 : a.label < b.label ? -1 : 0));
|
||||
extensions.unshift({
|
||||
0: "Sequences",
|
||||
1: "Sequences"
|
||||
});
|
||||
extensions.unshift({
|
||||
0: "Roadmaps",
|
||||
1: "Roadmaps"
|
||||
});
|
||||
extensions.unshift({
|
||||
0: "Leave unchanged",
|
||||
1: "__empty__"
|
||||
});
|
||||
var output;
|
||||
var input_config = {
|
||||
title: `Configure Output: '${output_id}'`,
|
||||
type: "section",
|
||||
flat: true,
|
||||
inputs: [
|
||||
{
|
||||
label: "Label",
|
||||
type: "text",
|
||||
value: ((output = node.getWorkflowOutput(output_id)) && output.label) || "",
|
||||
help: "This will provide a short name to describe the output - this must be unique across workflows.",
|
||||
onchange: function(new_value) {
|
||||
workflow.attemptUpdateOutputLabel(node, output_id, new_value);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "RenameDatasetAction",
|
||||
pja_arg: "newname",
|
||||
label: "Rename dataset",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: `This action will rename the output dataset. Click <a href="https://galaxyproject.org/learn/advanced-workflow/variables/">here</a> for more information. Valid inputs are: <strong>${input_terminal_names.join(
|
||||
", "
|
||||
)}</strong>.`
|
||||
},
|
||||
{
|
||||
action: "ChangeDatatypeAction",
|
||||
pja_arg: "newtype",
|
||||
label: "Change datatype",
|
||||
type: "select",
|
||||
ignore: "__empty__",
|
||||
value: "__empty__",
|
||||
options: extensions,
|
||||
help: "This action will change the datatype of the output to the indicated value."
|
||||
},
|
||||
{
|
||||
action: "TagDatasetAction",
|
||||
pja_arg: "tags",
|
||||
label: "Add Tags",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: "This action will set tags for the dataset."
|
||||
},
|
||||
{
|
||||
action: "RemoveTagDatasetAction",
|
||||
pja_arg: "tags",
|
||||
label: "Remove Tags",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: "This action will remove tags for the dataset."
|
||||
},
|
||||
{
|
||||
title: "Assign columns",
|
||||
type: "section",
|
||||
flat: true,
|
||||
inputs: [
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "chromCol",
|
||||
label: "Chrom column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "startCol",
|
||||
label: "Start column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "endCol",
|
||||
label: "End column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "strandCol",
|
||||
label: "Strand column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "nameCol",
|
||||
label: "Name column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
}
|
||||
],
|
||||
help: "This action will set column assignments in the output dataset. Blank fields are ignored."
|
||||
}
|
||||
]
|
||||
};
|
||||
_visit(input_config, [], output_id, options);
|
||||
return input_config;
|
||||
}
|
||||
|
||||
/** Builds all sub sections */
|
||||
function _addSections(form) {
|
||||
var options = form.model.attributes;
|
||||
var inputs = options.inputs;
|
||||
var datatypes = options.datatypes;
|
||||
var node = options.node;
|
||||
var workflow = options.workflow;
|
||||
var post_job_actions = node.post_job_actions;
|
||||
var output_id = node.output_terminals && Object.keys(node.output_terminals)[0];
|
||||
|
||||
/** Visit input nodes and enrich by name/value pairs from server data */
|
||||
function visit(head, head_list) {
|
||||
head_list = head_list || [];
|
||||
head_list.push(head);
|
||||
for (var i in head.inputs) {
|
||||
var input = head.inputs[i];
|
||||
var action = input.action;
|
||||
if (action) {
|
||||
input.name = `pja__${output_id}__${input.action}`;
|
||||
if (input.pja_arg) {
|
||||
input.name += `__${input.pja_arg}`;
|
||||
}
|
||||
if (input.payload) {
|
||||
for (var p_id in input.payload) {
|
||||
input.payload[`${input.name}__${p_id}`] = input.payload[p_id];
|
||||
delete input.payload[p_id];
|
||||
}
|
||||
}
|
||||
var d = post_job_actions[input.action + output_id];
|
||||
if (d) {
|
||||
for (var j in head_list) {
|
||||
head_list[j].expanded = true;
|
||||
}
|
||||
if (input.pja_arg) {
|
||||
input.value = (d.action_arguments && d.action_arguments[input.pja_arg]) || input.value;
|
||||
} else {
|
||||
input.value = "true";
|
||||
}
|
||||
}
|
||||
}
|
||||
input.inputs && visit(input, head_list.slice(0));
|
||||
}
|
||||
}
|
||||
|
||||
/** Builds sub section with step actions/annotation */
|
||||
function _makeSection(output_id, datatypes) {
|
||||
var extensions = [];
|
||||
var input_terminal_names = [];
|
||||
for (var key in datatypes) {
|
||||
extensions.push({ 0: datatypes[key], 1: datatypes[key] });
|
||||
}
|
||||
for (key in node.input_terminals) {
|
||||
input_terminal_names.push(node.input_terminals[key].name);
|
||||
}
|
||||
extensions.sort((a, b) => (a.label > b.label ? 1 : a.label < b.label ? -1 : 0));
|
||||
extensions.unshift({
|
||||
0: "Sequences",
|
||||
1: "Sequences"
|
||||
});
|
||||
extensions.unshift({
|
||||
0: "Roadmaps",
|
||||
1: "Roadmaps"
|
||||
});
|
||||
extensions.unshift({
|
||||
0: "Leave unchanged",
|
||||
1: "__empty__"
|
||||
});
|
||||
var output;
|
||||
var input_config = {
|
||||
title: `Configure Output: '${output_id}'`,
|
||||
type: "section",
|
||||
flat: true,
|
||||
inputs: [
|
||||
{
|
||||
label: "Label",
|
||||
type: "text",
|
||||
value: ((output = node.getWorkflowOutput(output_id)) && output.label) || "",
|
||||
help:
|
||||
"This will provide a short name to describe the output - this must be unique across workflows.",
|
||||
onchange: function(new_value) {
|
||||
workflow.attemptUpdateOutputLabel(node, output_id, new_value);
|
||||
}
|
||||
},
|
||||
{
|
||||
action: "RenameDatasetAction",
|
||||
pja_arg: "newname",
|
||||
label: "Rename dataset",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: `This action will rename the output dataset. Click <a href="https://galaxyproject.org/learn/advanced-workflow/variables/">here</a> for more information. Valid inputs are: <strong>${input_terminal_names.join(
|
||||
", "
|
||||
)}</strong>.`
|
||||
},
|
||||
{
|
||||
action: "ChangeDatatypeAction",
|
||||
pja_arg: "newtype",
|
||||
label: "Change datatype",
|
||||
type: "select",
|
||||
ignore: "__empty__",
|
||||
value: "__empty__",
|
||||
options: extensions,
|
||||
help: "This action will change the datatype of the output to the indicated value."
|
||||
},
|
||||
{
|
||||
action: "TagDatasetAction",
|
||||
pja_arg: "tags",
|
||||
label: "Add Tags",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: "This action will set tags for the dataset."
|
||||
},
|
||||
{
|
||||
action: "RemoveTagDatasetAction",
|
||||
pja_arg: "tags",
|
||||
label: "Remove Tags",
|
||||
type: "text",
|
||||
value: "",
|
||||
ignore: "",
|
||||
help: "This action will remove tags for the dataset."
|
||||
},
|
||||
{
|
||||
title: "Assign columns",
|
||||
type: "section",
|
||||
flat: true,
|
||||
inputs: [
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "chromCol",
|
||||
label: "Chrom column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "startCol",
|
||||
label: "Start column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "endCol",
|
||||
label: "End column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "strandCol",
|
||||
label: "Strand column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
},
|
||||
{
|
||||
action: "ColumnSetAction",
|
||||
pja_arg: "nameCol",
|
||||
label: "Name column",
|
||||
type: "integer",
|
||||
value: "",
|
||||
ignore: ""
|
||||
}
|
||||
],
|
||||
help: "This action will set column assignments in the output dataset. Blank fields are ignored."
|
||||
}
|
||||
]
|
||||
};
|
||||
visit(input_config);
|
||||
return input_config;
|
||||
}
|
||||
|
||||
if (output_id) {
|
||||
inputs.push({
|
||||
name: `pja__${output_id}__EmailAction`,
|
||||
@@ -349,7 +355,7 @@ function _addSections(form) {
|
||||
"Upon completion of this step, delete non-starred outputs from completed workflow steps if they are no longer required as inputs."
|
||||
});
|
||||
for (var i in node.output_terminals) {
|
||||
inputs.push(_makeSection(i, datatypes));
|
||||
inputs.push(_makeSection(i, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ var Node = Backbone.Model.extend({
|
||||
});
|
||||
},
|
||||
isWorkflowOutput: function(outputName) {
|
||||
return this.getWorkflowOutput(outputName) != undefined;
|
||||
return this.getWorkflowOutput(outputName) !== undefined;
|
||||
},
|
||||
removeWorkflowOutput: function(outputName) {
|
||||
while (this.isWorkflowOutput(outputName)) {
|
||||
@@ -25,7 +25,7 @@ var Node = Backbone.Model.extend({
|
||||
if (!this.isWorkflowOutput(outputName)) {
|
||||
var output = { output_name: outputName };
|
||||
if (label) {
|
||||
output["label"] = label;
|
||||
output.label = label;
|
||||
}
|
||||
this.workflow_outputs.push(output);
|
||||
return true;
|
||||
@@ -37,8 +37,8 @@ var Node = Backbone.Model.extend({
|
||||
var oldLabel = null;
|
||||
if (this.isWorkflowOutput(outputName)) {
|
||||
var workflowOutput = this.getWorkflowOutput(outputName);
|
||||
oldLabel = workflowOutput["label"];
|
||||
workflowOutput["label"] = label;
|
||||
oldLabel = workflowOutput.label;
|
||||
workflowOutput.label = label;
|
||||
changed = oldLabel != label;
|
||||
} else {
|
||||
changed = this.addWorkflowOutput(outputName, label);
|
||||
@@ -239,7 +239,7 @@ var Node = Backbone.Model.extend({
|
||||
this.config_form = data.config_form;
|
||||
this.tool_version = this.config_form && this.config_form.version;
|
||||
this.errors = data.errors;
|
||||
this.annotation = data["annotation"];
|
||||
this.annotation = data.annotation;
|
||||
this.label = data.label;
|
||||
if ("post_job_actions" in data) {
|
||||
// Won't be present in response for data inputs
|
||||
@@ -271,7 +271,7 @@ var Node = Backbone.Model.extend({
|
||||
old_body.replaceWith(new_body);
|
||||
if ("workflow_outputs" in data) {
|
||||
// Won't be present in response for data inputs
|
||||
this.workflow_outputs = workflow_outputs ? workflow_outputs : [];
|
||||
this.workflow_outputs = data.workflow_outputs ? data.workflow_outputs : [];
|
||||
}
|
||||
// If active, reactivate with new config_form
|
||||
this.markChanged();
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../static/style/blue/base.css
|
||||
@@ -0,0 +1,54 @@
|
||||
/** Creates a generic/global Galaxy environment, loads shared libraries and a fake server */
|
||||
define(
|
||||
[
|
||||
"jquery",
|
||||
"sinon",
|
||||
"libs/bootstrap",
|
||||
"qunit/test-data/bootstrapped",
|
||||
"qunit/test-data/fakeserver",
|
||||
"galaxy",
|
||||
"libs/jquery/select2",
|
||||
"libs/jquery/jstorage",
|
||||
"libs/jquery/jquery-ui"
|
||||
],
|
||||
function($, sinon, bootstrap, bootstrapped, serverdata, appBase) {
|
||||
var Galaxy = {
|
||||
root: "/"
|
||||
};
|
||||
|
||||
window.Galaxy = Galaxy;
|
||||
|
||||
$("head").append(
|
||||
$('<link rel="stylesheet" type="text/css" />').attr("href", "/base/galaxy/scripts/qunit/assets/base.css")
|
||||
);
|
||||
|
||||
appBase = appBase.default;
|
||||
return {
|
||||
create: function() {
|
||||
window.Galaxy = new appBase.GalaxyApp(bootstrapped);
|
||||
window.Galaxy.currHistoryPanel = { model: new Backbone.Model() };
|
||||
window.Galaxy.emit = {
|
||||
debug: function() {},
|
||||
error: function(v) {
|
||||
window.console.error(v);
|
||||
}
|
||||
};
|
||||
window.WAIT_FADE = 300;
|
||||
window.fakeserver = sinon.fakeServer.create();
|
||||
for (var route in serverdata) {
|
||||
window.fakeserver.respondWith("GET", window.Galaxy.root + route, [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
serverdata[route].data
|
||||
]);
|
||||
}
|
||||
},
|
||||
destroy: function() {
|
||||
if (window.fakeserver) {
|
||||
window.fakeserver.restore();
|
||||
delete window.fakeserver;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,29 @@
|
||||
define([], function() {
|
||||
return {
|
||||
config: {
|
||||
allow_user_deletion: false,
|
||||
allow_user_creation: true,
|
||||
wiki_url: "https://galaxyproject.org/",
|
||||
ftp_upload_site: null,
|
||||
support_url: "https://galaxyproject.org/support/",
|
||||
allow_user_dataset_purge: false,
|
||||
allow_library_path_paste: false,
|
||||
user_library_import_dir: null,
|
||||
terms_url: null,
|
||||
ftp_upload_dir: null,
|
||||
library_import_dir: null,
|
||||
logo_url: null,
|
||||
enable_unique_workflow_defaults: false
|
||||
},
|
||||
user: {
|
||||
username: "test",
|
||||
quota_percent: null,
|
||||
total_disk_usage: 61815527,
|
||||
nice_total_disk_usage: "59.0 MB",
|
||||
email: "test@test.test",
|
||||
tags_used: ["test"],
|
||||
model_class: "User",
|
||||
id: "f2db41e1fa331b3e"
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
define([], function() {
|
||||
return {
|
||||
"api/datatypes/mapping": {
|
||||
data:
|
||||
'{"ext_to_class_name" : {"txt" : "Text", "data":"Data","tabular":"Tabular", "binary": "Binary", "bam": "Bam" }, "class_to_classes": { "Data": { "Data": true }, "Text": { "Text": true, "Data": true }, "Tabular": { "Tabular": true, "Text": true, "Data": true }, "Binary": { "Data": true, "Binary": true }, "Bam": { "Data": true, "Binary": true, "Bam": true }}}'
|
||||
},
|
||||
"api/datatypes": {
|
||||
data: '["RData", "ab1", "affybatch", "txt"]'
|
||||
},
|
||||
"api/tools/test/build": {
|
||||
data:
|
||||
'{ "id": "test", "name": "_name", "version": "_version", "description": "_description", "display": "true", "requirements": [ { "name": "req_name_a", "version": "req_version_a" }, { "name": "req_name_b", "version": "req_version_b" } ], "inputs": [ { "name": "a", "type": "text" }, { "name": "b", "type": "conditional", "test_param": { "name": "c", "type": "select", "value": "h", "options": [ [ "d", "d", false ], [ "h", "h", false ] ] }, "cases": [ { "name": "d", "value": "d", "inputs": [ { "name": "f", "type": "text", "value": "f" }, { "name": "g", "type": "text", "value": "g" } ] }, { "name": "h", "value": "h", "inputs": [ { "name": "i", "type": "text", "value": "i" }, { "name": "j", "type": "text", "value": "j" } ] } ] }, { "name": "k", "min": 1, "max": 2, "type": "repeat", "cache": [[ { "name": "l", "type": "text", "value": "l"}, { "name": "m", "type": "conditional", "test_param": { "name": "n", "type": "select", "value": "r", "options": [ [ "o", "o", false ], [ "r", "r", false ] ] }, "cases": [ { "name": "o", "value": "o", "inputs": [ { "name": "p", "type": "text", "value": "p" }, { "name": "q", "type": "text", "value": "q" } ] }, { "name": "r", "value": "r", "inputs": [ { "name": "s", "type": "text", "value": "s" }, { "name": "t", "type": "text", "value": "t" } ] } ] } ] ], "inputs" : [ { "name": "l", "type": "text", "value": "l" }, { "name": "m", "type": "conditional", "test_param": { "name": "n", "type": "select", "value": "o", "options": [ [ "o", "o", false ], [ "r", "r", false ] ] }, "cases": [ { "name": "o", "value": "o", "inputs": [ { "name": "p", "type": "text", "value": "p" }, { "name": "q", "type": "text", "value": "q" } ] }, { "name": "r", "value": "r", "inputs": [ { "name": "s", "type": "text", "value": "s" }, { "name": "t", "type": "text", "value": "t" } ] } ] } ] } ] }'
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,531 @@
|
||||
define([], function() {
|
||||
// ============================================================================
|
||||
var tools = {
|
||||
upload1: {},
|
||||
"Show beginning1": {},
|
||||
"Show tail1": {},
|
||||
random_lines1: {},
|
||||
__SET_METADATA__: {},
|
||||
cat1: {}
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// plain 3 step job chain
|
||||
var jobs1 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-03T15:12:25.904033",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:12:22.589152",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "8a81cf6f989c4467",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-03T15:14:04.328484",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "132016f833b57406"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:14:01.060662",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "6505e875ddb66fd2",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "Show tail1",
|
||||
update_time: "2014-10-03T15:14:21.596871",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "132016f833b57406"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "846fb0a2a64137c0"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T15:14:18.425681",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "77f74776fd03cbc5",
|
||||
tool: null
|
||||
}
|
||||
];
|
||||
|
||||
var historyContents1 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "8c959c9304a2bc4b",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/8c959c9304a2bc4b",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "132016f833b57406",
|
||||
name: "Select first on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/132016f833b57406",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "911dde3ddb677bcd",
|
||||
id: "846fb0a2a64137c0",
|
||||
name: "Select last on data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/911dde3ddb677bcd/contents/datasets/846fb0a2a64137c0",
|
||||
visible: true
|
||||
}
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// single job chain with a __SET_METADATA__ job
|
||||
var jobs2 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-03T16:09:49.590769",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:09:45.190023",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "bf60fd5f5f7f44bf",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "random_lines1",
|
||||
update_time: "2014-10-03T16:10:44.743610",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "6fc9fbb81c497f69"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:10:41.446413",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "90240358ebde1489",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "__SET_METADATA__",
|
||||
update_time: "2014-10-03T16:14:44.196697",
|
||||
inputs: {
|
||||
input1: {
|
||||
src: "hda",
|
||||
id: "eca0af6fb47bf90c"
|
||||
}
|
||||
},
|
||||
outputs: {},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-03T16:14:37.901222",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "86cf1d3beeec9f1c",
|
||||
tool: null
|
||||
}
|
||||
];
|
||||
|
||||
var historyContents2 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "ff5476bcf6c921fa",
|
||||
id: "eca0af6fb47bf90c",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/ff5476bcf6c921fa/contents/datasets/eca0af6fb47bf90c",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "ff5476bcf6c921fa",
|
||||
id: "6fc9fbb81c497f69",
|
||||
name: "Select random lines on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/ff5476bcf6c921fa/contents/datasets/6fc9fbb81c497f69",
|
||||
visible: true
|
||||
}
|
||||
];
|
||||
|
||||
var jobs3 = [
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-13T20:28:58.549844",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "6fb17d0cc6e8fae5"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:28:43.162803",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "8c959c9304a2bc4b",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "upload1",
|
||||
update_time: "2014-10-13T20:28:58.932152",
|
||||
inputs: {},
|
||||
outputs: {
|
||||
output0: {
|
||||
src: "hda",
|
||||
id: "5114a2a207b7caff"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:28:47.421452",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "132016f833b57406",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-13T20:29:31.424058",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "6fb17d0cc6e8fae5"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "06ec17aefa2d49dd"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:29:28.769495",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "846fb0a2a64137c0",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "Show beginning1",
|
||||
update_time: "2014-10-13T20:29:55.851096",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "5114a2a207b7caff"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "b8a0d6158b9961df"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:29:53.291703",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "eca0af6fb47bf90c",
|
||||
tool: null
|
||||
},
|
||||
{
|
||||
tool_id: "Show tail1",
|
||||
update_time: "2014-10-13T20:30:16.225937",
|
||||
inputs: {
|
||||
input: {
|
||||
src: "hda",
|
||||
id: "b8a0d6158b9961df"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "24d84bcf64116fe7"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-13T20:30:13.789842",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "6fc9fbb81c497f69",
|
||||
tool: null
|
||||
}
|
||||
];
|
||||
|
||||
var historyContents3 = [
|
||||
{
|
||||
deleted: false,
|
||||
extension: "bed",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "6fb17d0cc6e8fae5",
|
||||
name: "1.bed",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/6fb17d0cc6e8fae5",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "5114a2a207b7caff",
|
||||
name: "1.interval",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/5114a2a207b7caff",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "bed",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "06ec17aefa2d49dd",
|
||||
name: "Select first on data 1",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/06ec17aefa2d49dd",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 4,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "b8a0d6158b9961df",
|
||||
name: "Select first on data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/b8a0d6158b9961df",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
deleted: false,
|
||||
extension: "interval",
|
||||
hid: 5,
|
||||
history_content_type: "dataset",
|
||||
history_id: "5564089c81cf7fe8",
|
||||
id: "24d84bcf64116fe7",
|
||||
name: "Select last on data 4",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/5564089c81cf7fe8/contents/datasets/24d84bcf64116fe7",
|
||||
visible: true
|
||||
}
|
||||
];
|
||||
|
||||
var jobs4 = [
|
||||
{
|
||||
tool_id: "cat1",
|
||||
update_time: "2014-10-21T17:33:36.960857",
|
||||
inputs: {
|
||||
input1: {
|
||||
src: "hda",
|
||||
id: "422eef6b1b545329",
|
||||
name: "input1"
|
||||
},
|
||||
"queries_0|input2": {
|
||||
src: "hda",
|
||||
id: "c86c1b73aa7102dd",
|
||||
name: "queries_0|input2"
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
out_file1: {
|
||||
src: "hda",
|
||||
id: "52d6bdfafedbb5e5",
|
||||
name: "out_file1"
|
||||
}
|
||||
},
|
||||
exit_code: 0,
|
||||
state: "ok",
|
||||
create_time: "2014-10-21T17:33:34.302245",
|
||||
params: {
|
||||
// ...
|
||||
},
|
||||
model_class: "Job",
|
||||
id: "92b83968e0b52980"
|
||||
}
|
||||
];
|
||||
|
||||
var historyContents4 = [
|
||||
{
|
||||
dataset_id: 29,
|
||||
deleted: false,
|
||||
extension: "vcf",
|
||||
hid: 1,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "422eef6b1b545329",
|
||||
name: "1.vcf",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/422eef6b1b545329",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
dataset_id: 56,
|
||||
deleted: false,
|
||||
extension: "maf",
|
||||
hid: 2,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "c86c1b73aa7102dd",
|
||||
name: "3.maf",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/c86c1b73aa7102dd",
|
||||
visible: true
|
||||
},
|
||||
{
|
||||
dataset_id: 131,
|
||||
deleted: false,
|
||||
extension: "maf",
|
||||
hid: 3,
|
||||
history_content_type: "dataset",
|
||||
history_id: "c24141d7e4e77705",
|
||||
id: "52d6bdfafedbb5e5",
|
||||
name: "Concatenate datasets on data 1 and data 2",
|
||||
purged: false,
|
||||
resubmitted: false,
|
||||
state: "ok",
|
||||
type: "file",
|
||||
url: "/api/histories/c24141d7e4e77705/contents/datasets/52d6bdfafedbb5e5",
|
||||
visible: true
|
||||
}
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
return {
|
||||
tools: tools,
|
||||
jobs1: jobs1,
|
||||
historyContents1: historyContents1,
|
||||
jobs2: jobs2,
|
||||
historyContents2: historyContents2,
|
||||
jobs3: jobs3,
|
||||
historyContents3: historyContents3,
|
||||
jobs4: jobs4,
|
||||
historyContents4: historyContents4
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,154 @@
|
||||
define([], function() {
|
||||
// ============================================================================
|
||||
// plain 3 step job chain
|
||||
var datasets1 = [
|
||||
{ name: "SET1-01_1.fastq" },
|
||||
{ name: "SET1-01_2.fastq" },
|
||||
{ name: "SET1-02_1.fastq" },
|
||||
{ name: "SET1-02_2.fastq" },
|
||||
{ name: "SET1-03_1.fastq" },
|
||||
{ name: "SET1-03_2.fastq" },
|
||||
{ name: "SET1-04_1.fastq" },
|
||||
{ name: "SET1-04_2.fastq" },
|
||||
{ name: "SET1-05_1.fastq" },
|
||||
{ name: "SET1-05_2.fastq" },
|
||||
{ name: "SET1-06_1.fastq" },
|
||||
{ name: "SET1-06_2.fastq" },
|
||||
{ name: "SET1-07_1.fastq" },
|
||||
{ name: "SET1-07_2.fastq" }
|
||||
];
|
||||
|
||||
var datasets1CreateRequestJSON = {
|
||||
type: "dataset_collection",
|
||||
collection_type: "list:paired",
|
||||
name: "Heres a collection",
|
||||
hide_source_items: false,
|
||||
element_identifiers: [
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-07",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "2",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "3",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-06",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "4",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "5",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-05",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "6",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "7",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-04",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "8",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "9",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-03",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "10",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "11",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-02",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "12",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "13",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
collection_type: "paired",
|
||||
src: "new_collection",
|
||||
name: "SET1-01",
|
||||
element_identifiers: [
|
||||
{
|
||||
name: "forward",
|
||||
id: "14",
|
||||
src: "hda"
|
||||
},
|
||||
{
|
||||
name: "reverse",
|
||||
id: "15",
|
||||
src: "hda"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
return {
|
||||
_1: datasets1,
|
||||
_1requestJSON: datasets1CreateRequestJSON
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,182 @@
|
||||
/* global define */
|
||||
define(
|
||||
[
|
||||
"qunit/test-app",
|
||||
"sinon",
|
||||
"mvc/form/form-input",
|
||||
"mvc/ui/ui-misc",
|
||||
"mvc/form/form-data",
|
||||
"mvc/tool/tool-form",
|
||||
"utils/utils"
|
||||
],
|
||||
function(testApp, sinon, InputElement, Ui, FormData, ToolForm, Utils) {
|
||||
"use strict";
|
||||
InputElement = InputElement.default;
|
||||
Ui = Ui.default;
|
||||
FormData = FormData.default;
|
||||
ToolForm = ToolForm.default;
|
||||
Utils = Utils.default;
|
||||
QUnit.module("Form test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
this.clock = sinon.useFakeTimers();
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("tool-form", function(assert) {
|
||||
var toolform = new ToolForm.View({ id: "test" });
|
||||
var form = toolform.form;
|
||||
$("body").prepend(toolform.$el);
|
||||
window.fakeserver.respond();
|
||||
var output = "";
|
||||
for (var property in assert) {
|
||||
output += property + ": ; ";
|
||||
}
|
||||
assert.ok(true, "MooCow");
|
||||
assert.ok(
|
||||
form.$(".portlet-title-text").html() == "<b>_name</b> _description (Galaxy Version _version)",
|
||||
"Title correct"
|
||||
);
|
||||
var tour_ids = [];
|
||||
$("[tour_id]").each(function() {
|
||||
tour_ids.push($(this).attr("tour_id"));
|
||||
});
|
||||
assert.ok(
|
||||
JSON.stringify(tour_ids) == '["a","b|c","b|i","b|j","k_0|l","k_0|m|n","k_0|m|s","k_0|m|t"]',
|
||||
"Tour ids correct"
|
||||
);
|
||||
assert.ok(
|
||||
JSON.stringify(form.data.create()) ==
|
||||
'{"a":"","b|c":"h","b|i":"i","b|j":"j","k_0|l":"l","k_0|m|n":"r","k_0|m|s":"s","k_0|m|t":"t"}',
|
||||
"Created data correct"
|
||||
);
|
||||
var mapped_ids = [];
|
||||
form.data.matchModel(form.model.attributes, function(input, id) {
|
||||
mapped_ids.push($("#" + id).attr("tour_id"));
|
||||
});
|
||||
assert.ok(
|
||||
JSON.stringify(mapped_ids) == '["a","b|c","b|i","b|j","k_0|l","k_0|m|n","k_0|m|s","k_0|m|t"]',
|
||||
"Remapped tour ids correct"
|
||||
);
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
var dropdown = form.$("#menu > .dropdown-menu");
|
||||
assert.ok(dropdown.children().length == 2, "Found two menu items");
|
||||
dropdown
|
||||
.find(".fa-info-circle")
|
||||
.parent()
|
||||
.click();
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
assert.ok(
|
||||
form.$(".ui-message").html() ===
|
||||
'<span>This tool requires req_name_a (Version req_version_a) and req_name_b (Version req_version_b). Click <a target="_blank" href="https://galaxyproject.org/tools/requirements/">here</a> for more information.</span>',
|
||||
"Check requirements message"
|
||||
);
|
||||
assert.ok(form.$(".form-repeat-delete").css("display") == "none", "Delete button disabled");
|
||||
var $add = form.$(".form-repeat-add");
|
||||
assert.ok(!$add.attr("disabled"), "Adding new repeat possible");
|
||||
$add.click();
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
assert.ok($add.attr("disabled"), "Adding new repeat has been disabled");
|
||||
form.$(".form-repeat-delete").each(function(i, d) {
|
||||
assert.ok($(d).css("display") == "block", "Delete buttons " + i + " enabled");
|
||||
});
|
||||
assert.ok(
|
||||
JSON.stringify(form.data.create()) ==
|
||||
'{"a":"","b|c":"h","b|i":"i","b|j":"j","k_0|l":"l","k_0|m|n":"r","k_0|m|s":"s","k_0|m|t":"t","k_1|l":"l","k_1|m|n":"o","k_1|m|p":"p","k_1|m|q":"q"}',
|
||||
"Created data correct, after adding repeat"
|
||||
);
|
||||
form.$(".form-repeat-delete:first").click();
|
||||
assert.ok(form.$(".form-repeat-delete").css("display") == "none", "Delete button disabled");
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
assert.ok(
|
||||
JSON.stringify(form.data.create()) ==
|
||||
'{"a":"","b|c":"h","b|i":"i","b|j":"j","k_0|l":"l","k_0|m|n":"o","k_0|m|p":"p","k_0|m|q":"q"}',
|
||||
"Created data correct, after removing first repeat"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("data", function(assert) {
|
||||
var visits = [];
|
||||
Utils.get({
|
||||
url: Galaxy.root + "api/tools/test/build",
|
||||
success: function(response) {
|
||||
FormData.visitInputs(response.inputs, function(node, name, context) {
|
||||
visits.push({ name: name, node: node });
|
||||
});
|
||||
}
|
||||
});
|
||||
window.fakeserver.respond();
|
||||
assert.ok(
|
||||
JSON.stringify(visits) ==
|
||||
'[{"name":"a","node":{"name":"a","type":"text"}},{"name":"b|c","node":{"name":"c","type":"select","value":"h","options":[["d","d",false],["h","h",false]]}},{"name":"b|i","node":{"name":"i","type":"text","value":"i"}},{"name":"b|j","node":{"name":"j","type":"text","value":"j"}},{"name":"k_0|l","node":{"name":"l","type":"text","value":"l"}},{"name":"k_0|m|n","node":{"name":"n","type":"select","value":"r","options":[["o","o",false],["r","r",false]]}},{"name":"k_0|m|s","node":{"name":"s","type":"text","value":"s"}},{"name":"k_0|m|t","node":{"name":"t","type":"text","value":"t"}}]',
|
||||
"Testing value visitor"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("input", function(assert) {
|
||||
var input = new InputElement(
|
||||
{},
|
||||
{
|
||||
field: new Ui.Input({})
|
||||
}
|
||||
);
|
||||
$("body").prepend(input.$el);
|
||||
assert.ok(input.$field.css("display") == "block", "Input field shown");
|
||||
assert.ok(input.$preview.css("display") == "none", "Preview hidden");
|
||||
assert.ok(input.$collapsible.css("display") == "none", "Collapsible hidden");
|
||||
assert.ok(input.$title_text.css("display") == "inline", "Title visible");
|
||||
assert.ok(input.$title_text.html() == "", "Title content unavailable");
|
||||
input.model.set("label", "_label");
|
||||
assert.ok(input.$title_text.html() == "_label", "Title content available");
|
||||
assert.ok(input.$error.css("display") == "none", "Error hidden");
|
||||
input.model.set("error_text", "_error_text");
|
||||
assert.ok(input.$error.css("display") == "block", "Error visible");
|
||||
assert.ok(input.$error_text.html() == "_error_text", "Error text correct");
|
||||
input.model.set("error_text", null);
|
||||
assert.ok(input.$error.css("display") == "none", "Error hidden, again");
|
||||
assert.ok(input.$backdrop.css("display") == "none", "Backdrop hidden");
|
||||
input.model.set("backdrop", true);
|
||||
assert.ok(input.$backdrop.css("display") == "block", "Backdrop shown");
|
||||
assert.ok(input.$backdrop.css("opacity") == 0, "Backdrop transparent");
|
||||
assert.ok(input.$backdrop.css("cursor") == "default", "Backdrop regular cursor");
|
||||
input.model.set("backdrop", false);
|
||||
assert.ok(input.$backdrop.css("display") == "none", "Backdrop hidden, again");
|
||||
input.model.set("disabled", true);
|
||||
assert.ok(input.$field.css("display") == "none", "Input field hidden");
|
||||
input.model.set("disabled", false);
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
assert.ok(input.$field.css("display") == "block", "Input field shown, again");
|
||||
this.clock.tick(window.WAIT_FADE);
|
||||
input.model.set("color", "red");
|
||||
assert.ok(
|
||||
input.$field
|
||||
.children()
|
||||
.first()
|
||||
.css("color") == "rgb(255, 0, 0)",
|
||||
"Shows correct new color"
|
||||
);
|
||||
input.model.set("color", null);
|
||||
assert.ok(
|
||||
input.$field
|
||||
.children()
|
||||
.first()
|
||||
.css("color") == "rgb(85, 85, 85)",
|
||||
"Shows correct old color"
|
||||
);
|
||||
input.model.set("collapsible_value", "_collapsible_value");
|
||||
assert.ok(input.$collapsible.css("display") == "block", "Collapsible field");
|
||||
assert.ok(input.$collapsible_text.html() == "_label", "Title content available");
|
||||
assert.ok(input.$title_text.css("display") == "none", "Regular title not visible");
|
||||
input.model.set("help", "_help");
|
||||
assert.ok(input.$info.html() == "_help", "Correct help text");
|
||||
input.model.set("argument", "_argument");
|
||||
assert.ok(input.$info.html() == "_help (_argument)", "Correct help text with argument");
|
||||
input.model.set("help", "_help (_argument)");
|
||||
assert.ok(input.$info.html() == "_help (_argument)", "Correct help text with argument from help");
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,96 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "galaxy", "jquery"], function(testApp, appBase, $) {
|
||||
"use strict";
|
||||
appBase = appBase.default;
|
||||
QUnit.module("Galaxy client app tests");
|
||||
|
||||
var options = {
|
||||
config: {
|
||||
allow_user_deletion: false,
|
||||
allow_user_creation: true,
|
||||
wiki_url: "https://galaxyproject.org/",
|
||||
ftp_upload_site: null,
|
||||
support_url: "https://galaxyproject.org/support/",
|
||||
allow_user_dataset_purge: false,
|
||||
allow_library_path_paste: false,
|
||||
user_library_import_dir: null,
|
||||
terms_url: null,
|
||||
ftp_upload_dir: null,
|
||||
library_import_dir: null,
|
||||
logo_url: null,
|
||||
enable_unique_workflow_defaults: false
|
||||
},
|
||||
user: {
|
||||
username: "test",
|
||||
quota_percent: null,
|
||||
total_disk_usage: 61815527,
|
||||
nice_total_disk_usage: "59.0 MB",
|
||||
email: "test@test.test",
|
||||
tags_used: ["test"],
|
||||
model_class: "User",
|
||||
id: "f2db41e1fa331b3e"
|
||||
}
|
||||
};
|
||||
|
||||
QUnit.test("App base construction/initializiation defaults", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
assert.ok(app.hasOwnProperty("options") && typeof app.options === "object");
|
||||
assert.ok(app.hasOwnProperty("logger") && typeof app.logger === "object");
|
||||
assert.ok(app.hasOwnProperty("localize") && typeof app.localize === "function");
|
||||
assert.ok(app.hasOwnProperty("config") && typeof app.config === "object");
|
||||
assert.ok(app.hasOwnProperty("user") && typeof app.config === "object");
|
||||
assert.equal(app.localize, window._l);
|
||||
});
|
||||
|
||||
QUnit.test("App base default options", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
assert.ok(app.hasOwnProperty("options") && typeof app.options === "object");
|
||||
assert.equal(app.options.root, "/");
|
||||
assert.equal(app.options.patchExisting, true);
|
||||
});
|
||||
|
||||
QUnit.test("App base extends from Backbone.Events", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
["on", "off", "trigger", "listenTo", "stopListening"].forEach(function(fn) {
|
||||
assert.ok(app.hasOwnProperty(fn) && typeof app[fn] === "function");
|
||||
});
|
||||
});
|
||||
|
||||
QUnit.test("App base has logging methods from utils/add-logging.js", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
["debug", "info", "warn", "error", "metric"].forEach(function(fn) {
|
||||
assert.ok(typeof app[fn] === "function");
|
||||
});
|
||||
assert.ok(app._logNamespace === "GalaxyApp");
|
||||
});
|
||||
|
||||
QUnit.test("App base will patch in attributes from existing Galaxy objects", function(assert) {
|
||||
window.Galaxy = {
|
||||
attribute: {
|
||||
subattr: 1
|
||||
}
|
||||
};
|
||||
var app = new appBase.GalaxyApp({});
|
||||
assert.ok(typeof app.attribute === "object" && app.attribute.subattr === 1);
|
||||
});
|
||||
|
||||
QUnit.test("App base logger", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
assert.ok(app.hasOwnProperty("logger") && typeof app.config === "object");
|
||||
});
|
||||
|
||||
QUnit.test("App base config", function(assert) {
|
||||
var app = new appBase.GalaxyApp(options);
|
||||
assert.ok(app.hasOwnProperty("config") && typeof app.config === "object");
|
||||
assert.equal(app.config.allow_user_deletion, false);
|
||||
assert.equal(app.config.allow_user_creation, true);
|
||||
assert.equal(app.config.wiki_url, "https://galaxyproject.org/");
|
||||
assert.equal(app.config.ftp_upload_site, null);
|
||||
});
|
||||
|
||||
QUnit.test("App base user", function(assert) {
|
||||
var app = new appBase.GalaxyApp({});
|
||||
assert.ok(app.hasOwnProperty("user") && typeof app.user === "object");
|
||||
assert.ok(app.user.isAdmin() === false);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,515 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "utils/graph", "jquery"], function(testApp, GRAPH, $) {
|
||||
"use strict";
|
||||
GRAPH = GRAPH.default;
|
||||
QUnit.module("utils/graph.js library tests");
|
||||
///*
|
||||
function testEmptyObject(assert, o) {
|
||||
assert.ok(typeof o === "object");
|
||||
assert.ok(Object.keys(o).length === 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------ vertices
|
||||
QUnit.test("Empty vertex construction", function(assert) {
|
||||
var vert = new GRAPH.Vertex();
|
||||
assert.ok(vert instanceof GRAPH.Vertex);
|
||||
assert.ok(vert.name === "(unnamed)");
|
||||
assert.ok(vert.data === null);
|
||||
testEmptyObject(assert, vert.edges);
|
||||
assert.ok(vert.degree === 0);
|
||||
assert.ok(vert + "" === "Vertex((unnamed))");
|
||||
assert.deepEqual(vert.toJSON(), { name: "(unnamed)", data: null });
|
||||
});
|
||||
|
||||
QUnit.test("Vertex construction", function(assert) {
|
||||
var vert = new GRAPH.Vertex("blah", { blorp: 1, bleep: 2 });
|
||||
assert.ok(vert instanceof GRAPH.Vertex);
|
||||
assert.ok(vert.name === "blah");
|
||||
assert.deepEqual(vert.data, { blorp: 1, bleep: 2 });
|
||||
testEmptyObject(assert, vert.edges);
|
||||
assert.ok(vert.degree === 0);
|
||||
assert.ok(vert + "" === "Vertex(blah)");
|
||||
assert.deepEqual(vert.toJSON(), { name: "blah", data: { blorp: 1, bleep: 2 } });
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ edges
|
||||
QUnit.test("Empty edge construction", function(assert) {
|
||||
var edge = new GRAPH.Edge();
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(edge.source === null);
|
||||
assert.ok(edge.target === null);
|
||||
assert.ok(edge.data === null);
|
||||
assert.ok(edge + "" === "null->null");
|
||||
assert.deepEqual(edge.toJSON(), { source: null, target: null });
|
||||
});
|
||||
|
||||
QUnit.test("Edge construction", function(assert) {
|
||||
var edge = new GRAPH.Edge("A", "B", { one: 1, two: 2 });
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(edge.source === "A");
|
||||
assert.ok(edge.target === "B");
|
||||
assert.deepEqual(edge.data, { one: 1, two: 2 });
|
||||
assert.ok(edge + "" === "A->B");
|
||||
assert.deepEqual(edge.toJSON(), { source: "A", target: "B", data: { one: 1, two: 2 } });
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ graphs
|
||||
function testEmptyGraph(assert, graph) {
|
||||
assert.ok(graph instanceof GRAPH.Graph);
|
||||
testEmptyObject(assert, graph.vertices);
|
||||
assert.ok(graph.numEdges === 0);
|
||||
}
|
||||
|
||||
QUnit.test("Empty graph construction", function(assert) {
|
||||
var graph = new GRAPH.Graph();
|
||||
|
||||
assert.ok(graph.directed === false);
|
||||
assert.ok(graph.allowReflexiveEdges === false);
|
||||
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Bad data graph construction", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, {});
|
||||
testEmptyGraph(assert, graph);
|
||||
|
||||
graph = new GRAPH.Graph(false, null);
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test directed and options", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, {}, { allowReflexiveEdges: true });
|
||||
|
||||
assert.ok(graph.directed);
|
||||
assert.ok(graph.allowReflexiveEdges);
|
||||
|
||||
testEmptyGraph(assert, graph);
|
||||
});
|
||||
|
||||
function testSampleDirectedGraph(assert, graph) {
|
||||
assert.ok(!graph.directed);
|
||||
|
||||
assert.ok(Object.keys(graph.vertices).length === 3);
|
||||
assert.ok(graph.vertices.A instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.B instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.C instanceof GRAPH.Vertex);
|
||||
|
||||
assert.deepEqual(Object.keys(graph.vertices.A.edges), ["B", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.B.edges), ["A", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.C.edges), ["A", "B"]);
|
||||
|
||||
assert.ok(graph.vertices.A.degree === 2);
|
||||
assert.ok(graph.vertices.B.degree === 2);
|
||||
assert.ok(graph.vertices.C.degree === 2);
|
||||
|
||||
assert.deepEqual(graph.vertices.A.edges.B.toJSON(), { source: "A", target: "B" });
|
||||
assert.deepEqual(graph.vertices.A.edges.C.toJSON(), { source: "A", target: "C" });
|
||||
assert.deepEqual(graph.vertices.B.edges.A.toJSON(), { source: "B", target: "A" });
|
||||
assert.deepEqual(graph.vertices.B.edges.C.toJSON(), { source: "B", target: "C" });
|
||||
assert.deepEqual(graph.vertices.C.edges.A.toJSON(), { source: "C", target: "A" });
|
||||
assert.deepEqual(graph.vertices.C.edges.B.toJSON(), { source: "C", target: "B" });
|
||||
|
||||
assert.ok(graph.numEdges === 6);
|
||||
}
|
||||
|
||||
function testSampleNonDirectedGraph(assert, graph) {
|
||||
assert.ok(graph.directed);
|
||||
|
||||
assert.ok(Object.keys(graph.vertices).length === 3);
|
||||
assert.ok(graph.vertices.A instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.B instanceof GRAPH.Vertex);
|
||||
assert.ok(graph.vertices.C instanceof GRAPH.Vertex);
|
||||
|
||||
assert.deepEqual(Object.keys(graph.vertices.A.edges), ["B", "C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.B.edges), ["C"]);
|
||||
assert.deepEqual(Object.keys(graph.vertices.C.edges), []);
|
||||
|
||||
assert.ok(graph.vertices.A.degree === 2);
|
||||
assert.ok(graph.vertices.B.degree === 1);
|
||||
assert.ok(graph.vertices.C.degree === 0);
|
||||
|
||||
assert.deepEqual(graph.vertices.A.edges.B.toJSON(), { source: "A", target: "B" });
|
||||
assert.deepEqual(graph.vertices.A.edges.C.toJSON(), { source: "A", target: "C" });
|
||||
assert.deepEqual(graph.vertices.B.edges.C.toJSON(), { source: "B", target: "C" });
|
||||
|
||||
assert.ok(graph.numEdges === 3);
|
||||
}
|
||||
|
||||
var nodeLinkData = {
|
||||
nodes: [{ name: "A", data: 100 }, { name: "B", data: 200 }, { name: "C", data: 300 }],
|
||||
links: [{ source: 0, target: 1 }, { source: 0, target: 2 }, { source: 1, target: 2 }]
|
||||
};
|
||||
|
||||
QUnit.test("Test nodes and links data input on *non-directed* graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
testSampleDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test nodes and links data input on *directed* graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
testSampleNonDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
var vertexEdgeData = {
|
||||
vertices: [{ name: "A", data: 100 }, { name: "B", data: 200 }, { name: "C", data: 300 }],
|
||||
edges: [{ source: "A", target: "B" }, { source: "A", target: "C" }, { source: "B", target: "C" }]
|
||||
};
|
||||
|
||||
QUnit.test("Test vertex and edge data input on *non-directed* graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, vertexEdgeData);
|
||||
testSampleDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test vertex and edge data input on *directed* graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, vertexEdgeData);
|
||||
testSampleNonDirectedGraph(assert, graph);
|
||||
});
|
||||
|
||||
QUnit.test("Test vertex eachEdge", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
assert.ok(typeof graph.vertices.A.eachEdge === "function");
|
||||
assert.deepEqual(
|
||||
graph.vertices.A.eachEdge(function(e) {
|
||||
return e.target;
|
||||
}),
|
||||
["B", "C"]
|
||||
);
|
||||
assert.ok(graph.vertices.A.eachEdge({ target: "B" }).length === 1);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph eachVertex", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.ok(typeof graph.eachVertex === "function");
|
||||
assert.deepEqual(
|
||||
graph.eachVertex(function(v) {
|
||||
return { n: v.name, d: v.degree };
|
||||
}),
|
||||
[{ n: "A", d: 2 }, { n: "B", d: 1 }, { n: "C", d: 0 }]
|
||||
);
|
||||
assert.ok(graph.eachVertex({ degree: 2 })[0] === graph.vertices.A);
|
||||
});
|
||||
|
||||
QUnit.test("Test createVertex", function(assert) {
|
||||
var graph = new GRAPH.Graph();
|
||||
var vert1 = graph.createVertex("A", { blah: 1 });
|
||||
assert.ok(vert1 instanceof GRAPH.Vertex);
|
||||
assert.ok(vert1 === graph.vertices.A);
|
||||
assert.ok(graph.createVertex("A", { blah: 1 }) === vert1);
|
||||
});
|
||||
|
||||
QUnit.test("Test createEdge", function(assert) {
|
||||
var graph, A, B, edge;
|
||||
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "B");
|
||||
assert.ok(edge instanceof GRAPH.Edge);
|
||||
assert.ok(A.degree === 1);
|
||||
assert.ok(B.degree === 1);
|
||||
assert.ok(A.edges.B);
|
||||
assert.ok(B.edges.A);
|
||||
assert.ok(graph.numEdges === 2);
|
||||
|
||||
// bad target
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "C");
|
||||
assert.ok(edge === null);
|
||||
assert.ok(A.degree === 0);
|
||||
assert.ok(B.degree === 0);
|
||||
assert.ok(!A.edges.B);
|
||||
assert.ok(!B.edges.A);
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// bad source
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("C", "A");
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// reflexive
|
||||
graph = new GRAPH.Graph();
|
||||
A = graph.createVertex("A");
|
||||
B = graph.createVertex("B");
|
||||
edge = graph.createEdge("A", "A");
|
||||
assert.ok(graph.numEdges === 0);
|
||||
|
||||
// reflexive (allowed)
|
||||
graph = new GRAPH.Graph(false, {}, { allowReflexiveEdges: true });
|
||||
A = graph.createVertex("A");
|
||||
edge = graph.createEdge("A", "A");
|
||||
// reflexive edges shouldn't mirror
|
||||
assert.ok(graph.numEdges === 1);
|
||||
assert.ok(A.edges.A);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.edges", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData);
|
||||
assert.ok(graph.edges().length === 6);
|
||||
assert.deepEqual(
|
||||
graph.edges(function(e) {
|
||||
return e.source;
|
||||
}),
|
||||
["A", "A", "B", "B", "C", "C"]
|
||||
);
|
||||
assert.deepEqual(graph.edges({ source: "A" }), [graph.vertices.A.edges.B, graph.vertices.A.edges.C]);
|
||||
|
||||
graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.ok(graph.edges().length === 3);
|
||||
assert.deepEqual(
|
||||
graph.edges(function(e) {
|
||||
return e.source;
|
||||
}),
|
||||
["A", "A", "B"]
|
||||
);
|
||||
assert.deepEqual(graph.edges({ source: "A" }), [graph.vertices.A.edges.B, graph.vertices.A.edges.C]);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.adjacent", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.A), [graph.vertices.B, graph.vertices.C]);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.B), [graph.vertices.C]);
|
||||
assert.deepEqual(graph.adjacent(graph.vertices.C), []);
|
||||
});
|
||||
|
||||
QUnit.test("Test graph.eachAdjacent", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData);
|
||||
assert.deepEqual(
|
||||
graph.eachAdjacent(graph.vertices.A, function(v, e) {
|
||||
return v;
|
||||
}),
|
||||
[graph.vertices.B, graph.vertices.C]
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ breadth first search
|
||||
QUnit.test("Empty BreadthFirstSearch", function(assert) {
|
||||
var search = new GRAPH.BreadthFirstSearch();
|
||||
assert.ok(search instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(search.graph === undefined);
|
||||
assert.ok(typeof search.processFns === "object");
|
||||
assert.ok(typeof search.processFns.vertexEarly === "function");
|
||||
assert.ok(typeof search.processFns.edge === "function");
|
||||
assert.ok(typeof search.processFns.vertexLate === "function");
|
||||
assert.ok(typeof search._cache === "object");
|
||||
});
|
||||
|
||||
QUnit.test("BreadthFirstSearch on undirected graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, nodeLinkData),
|
||||
bfs = new GRAPH.BreadthFirstSearch(graph);
|
||||
assert.ok(bfs instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(bfs.graph === graph);
|
||||
|
||||
var search = bfs.search("A"),
|
||||
tree = bfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true },
|
||||
edges: [{ source: "A", target: "B" }, { source: "A", target: "C" }]
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function(v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 0, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(bfs.search("B").edges, [{ source: "B", target: "A" }, { source: "B", target: "C" }]);
|
||||
assert.deepEqual(bfs.search("C").edges, [{ source: "C", target: "A" }, { source: "C", target: "B" }]);
|
||||
assert.ok(typeof bfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(bfs._cache), ["A", "B", "C"]);
|
||||
});
|
||||
|
||||
QUnit.test("BreadthFirstSearch on directed graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, nodeLinkData),
|
||||
bfs = new GRAPH.BreadthFirstSearch(graph);
|
||||
assert.ok(bfs instanceof GRAPH.BreadthFirstSearch);
|
||||
assert.ok(bfs.graph === graph);
|
||||
|
||||
var search = bfs.search("A"),
|
||||
tree = bfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true },
|
||||
edges: [{ source: "A", target: "B" }, { source: "A", target: "C" }]
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function(v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 0, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(bfs.search("B").edges, [{ source: "B", target: "C" }]);
|
||||
assert.deepEqual(bfs.search("C").edges, []);
|
||||
assert.ok(typeof bfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(bfs._cache), ["A", "B", "C"]);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ depth first search
|
||||
var DFSData = {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }, { name: "F" }],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
// confound it
|
||||
{ source: "A", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" },
|
||||
// confound it
|
||||
{ source: "F", target: "A" }
|
||||
]
|
||||
};
|
||||
|
||||
QUnit.test("Empty DepthFirstSearch", function(assert) {
|
||||
var search = new GRAPH.DepthFirstSearch();
|
||||
assert.ok(search instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(search.graph === undefined);
|
||||
assert.ok(typeof search.processFns === "object");
|
||||
assert.ok(typeof search.processFns.vertexEarly === "function");
|
||||
assert.ok(typeof search.processFns.edge === "function");
|
||||
assert.ok(typeof search.processFns.vertexLate === "function");
|
||||
assert.ok(typeof search._cache === "object");
|
||||
});
|
||||
|
||||
QUnit.test("DepthFirstSearch on undirected graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, DFSData),
|
||||
dfs = new GRAPH.DepthFirstSearch(graph);
|
||||
assert.ok(dfs instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(dfs.graph === graph);
|
||||
|
||||
var search = dfs.search("A"),
|
||||
tree = dfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true, D: true, E: true, F: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" }
|
||||
],
|
||||
entryTimes: { A: 0, B: 1, C: 2, D: 3, E: 7, F: 8 },
|
||||
exitTimes: { A: 11, B: 6, C: 5, D: 4, E: 10, F: 9 }
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function(v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 1, 1, 0, 1, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(dfs.search("B").edges, [
|
||||
{ source: "B", target: "A" },
|
||||
{ source: "A", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" }
|
||||
]);
|
||||
|
||||
assert.ok(typeof dfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(dfs._cache), ["A", "B"]);
|
||||
});
|
||||
|
||||
QUnit.test("DepthFirstSearch on directed graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(true, DFSData),
|
||||
dfs = new GRAPH.DepthFirstSearch(graph);
|
||||
assert.ok(dfs instanceof GRAPH.DepthFirstSearch);
|
||||
assert.ok(dfs.graph === graph);
|
||||
|
||||
var search = dfs.search("A"),
|
||||
tree = dfs.searchTree("A");
|
||||
assert.deepEqual(search, {
|
||||
discovered: { A: true, B: true, C: true, D: true, E: true, F: true },
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "B", target: "C" },
|
||||
{ source: "C", target: "D" },
|
||||
{ source: "A", target: "E" },
|
||||
{ source: "E", target: "F" }
|
||||
],
|
||||
entryTimes: { A: 0, B: 1, C: 2, D: 3, E: 7, F: 8 },
|
||||
exitTimes: { A: 11, B: 6, C: 5, D: 4, E: 10, F: 9 }
|
||||
});
|
||||
assert.ok(tree instanceof GRAPH.Graph);
|
||||
assert.deepEqual(tree.vertices.A.toJSON(), graph.vertices.A.toJSON());
|
||||
assert.deepEqual(
|
||||
tree.eachVertex(function(v) {
|
||||
return v.degree;
|
||||
}),
|
||||
[2, 1, 1, 0, 1, 0]
|
||||
);
|
||||
|
||||
assert.deepEqual(dfs.search("B").edges, [{ source: "B", target: "C" }, { source: "C", target: "D" }]);
|
||||
|
||||
assert.ok(typeof dfs._cache.A === "object");
|
||||
assert.deepEqual(Object.keys(dfs._cache), ["A", "B"]);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ components
|
||||
//*/
|
||||
QUnit.test("weakComponents on undirected graph", function(assert) {
|
||||
var graph = new GRAPH.Graph(false, {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }],
|
||||
edges: [{ source: "A", target: "B" }, { source: "C", target: "D" }]
|
||||
});
|
||||
assert.equal(graph.numEdges, 4);
|
||||
var components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
});
|
||||
|
||||
QUnit.test("weakComponents on directed graph", function(assert) {
|
||||
var graph, components;
|
||||
graph = new GRAPH.Graph(true, {
|
||||
vertices: [{ name: "A" }, { name: "B" }, { name: "C" }, { name: "D" }, { name: "E" }],
|
||||
edges: [{ source: "A", target: "B" }, { source: "D", target: "C" }]
|
||||
});
|
||||
assert.equal(graph.numEdges, 2);
|
||||
|
||||
components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
|
||||
graph = new GRAPH.Graph(true, {
|
||||
vertices: [
|
||||
{ name: "A", data: 100 },
|
||||
{ name: "B", data: 200 },
|
||||
{ name: "C", data: 30 },
|
||||
{ name: "D", data: 40 },
|
||||
{ name: "E", data: 500 },
|
||||
{ name: "F", data: 600 },
|
||||
{ name: "G", data: 7 }
|
||||
],
|
||||
edges: [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "D", target: "C" },
|
||||
{ source: "E", target: "A" },
|
||||
{ source: "F", target: "E" }
|
||||
]
|
||||
});
|
||||
components = graph.weakComponents();
|
||||
assert.equal(components.length, 3);
|
||||
// data retained
|
||||
assert.equal(components[0].vertices[0].data, 100);
|
||||
|
||||
assert.equal(components[0].vertices.length, 4);
|
||||
assert.deepEqual(components[0].edges, [
|
||||
{ source: "A", target: "B" },
|
||||
{ source: "E", target: "A" },
|
||||
{ source: "F", target: "E" }
|
||||
]);
|
||||
|
||||
assert.equal(components[1].vertices.length, 2);
|
||||
assert.deepEqual(components[1].edges, [{ source: "D", target: "C" }]);
|
||||
|
||||
assert.deepEqual(components[2].vertices, [{ name: "G", data: 7 }]);
|
||||
assert.deepEqual(components[2].edges.length, 0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
// This file isn't really testing anything useful yet, it is just testing
|
||||
// (or demonstrating) qunit+backbone interactions.
|
||||
/* global define */
|
||||
define(["qunit/test-app", "mvc/history/hda-model", "mvc/history/hda-li", "jquery"], function(
|
||||
testApp,
|
||||
HDA_MODEL,
|
||||
HDA_BASE,
|
||||
$
|
||||
) {
|
||||
"use strict";
|
||||
HDA_MODEL = HDA_MODEL.default;
|
||||
HDA_BASE = HDA_BASE.default;
|
||||
QUnit.module("HDA base backbone view tests");
|
||||
|
||||
QUnit.test("Base HDA view default construction, initialize", function(assert) {
|
||||
var hda = new HDA_MODEL.HistoryDatasetAssociation({
|
||||
id: "123"
|
||||
}),
|
||||
view = new HDA_BASE.HDAListItemView({ model: hda });
|
||||
|
||||
assert.strictEqual(view.model, hda);
|
||||
|
||||
assert.equal(view.linkTarget, "_blank");
|
||||
assert.equal(view.selectable, false);
|
||||
assert.equal(view.selected, false);
|
||||
assert.equal(view.expanded, false);
|
||||
assert.equal(view.draggable, false);
|
||||
assert.equal(view.id(), "dataset-123");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "mvc/history/hda-model", "jquery", "sinon"], function(testApp, HDA_MODEL, $, sinon) {
|
||||
HDA_MODEL = HDA_MODEL.default;
|
||||
QUnit.module("History Contents Model QUnit.Tests");
|
||||
|
||||
QUnit.test("HDA Constructions with Default Attributes", function(assert) {
|
||||
var hda = new HDA_MODEL.HistoryDatasetAssociation({});
|
||||
assert.equal(hda.get("name"), "(unnamed dataset)");
|
||||
assert.equal(hda.get("state"), "new");
|
||||
});
|
||||
|
||||
QUnit.test("HDA Construction with Supplied Attributes", function(assert) {
|
||||
var hda = new HDA_MODEL.HistoryDatasetAssociation({
|
||||
history_content_type: "dataset",
|
||||
name: "my dataset",
|
||||
state: "ok"
|
||||
});
|
||||
assert.equal(hda.get("name"), "my dataset");
|
||||
assert.equal(hda.get("state"), "ok");
|
||||
});
|
||||
|
||||
QUnit.test("HDA Deletion", function(assert) {
|
||||
var hda = new HDA_MODEL.HistoryDatasetAssociation({
|
||||
history_content_type: "dataset",
|
||||
id: "hda1",
|
||||
history_id: "h1",
|
||||
deleted: false
|
||||
});
|
||||
assert.equal(hda.get("deleted"), false);
|
||||
|
||||
sinon.stub($, "ajax").yieldsTo("success", { deleted: true });
|
||||
hda["delete"]();
|
||||
// to get the url sinon used:
|
||||
//console.debug( $.ajax.lastCall.args[0].url )
|
||||
assert.ok($.ajax.calledWithMatch({ url: "/api/histories/h1/contents/datasets/hda1" }));
|
||||
assert.equal(hda.get("deleted"), true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,294 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "mvc/history/job-dag", "jquery", "qunit/test-data/job-dag-1"], function(
|
||||
testApp,
|
||||
JobDAG,
|
||||
$,
|
||||
testData
|
||||
) {
|
||||
"use strict";
|
||||
JobDAG = JobDAG.default;
|
||||
QUnit.module("mvc/history/job-dag.js tests");
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
QUnit.test("Empty JobDAG construction", function(assert) {
|
||||
var dag = new JobDAG();
|
||||
assert.ok(dag instanceof JobDAG);
|
||||
|
||||
// default options
|
||||
assert.deepEqual(dag.filters, []);
|
||||
assert.deepEqual(dag.options, {
|
||||
excludeSetMetadata: false
|
||||
});
|
||||
|
||||
// test (empty) instance vars
|
||||
assert.deepEqual(dag._jobsData, []);
|
||||
assert.deepEqual(dag._historyContentsMap, {});
|
||||
assert.deepEqual(dag._toolMap, {});
|
||||
assert.equal(dag.noInputJobs.length, 0);
|
||||
assert.equal(dag.noOutputJobs.length, 0);
|
||||
|
||||
// logging
|
||||
assert.equal(typeof dag.debug, "function");
|
||||
assert.equal(typeof dag.info, "function");
|
||||
assert.equal(typeof dag.warn, "function");
|
||||
assert.equal(typeof dag.error, "function");
|
||||
});
|
||||
|
||||
QUnit.test("Empty JobDAG construction - changing options", function(assert) {
|
||||
var dag;
|
||||
dag = new JobDAG({
|
||||
excludeSetMetadata: true
|
||||
});
|
||||
|
||||
// excludeSetMetadata
|
||||
assert.deepEqual(dag.options, {
|
||||
excludeSetMetadata: true
|
||||
});
|
||||
assert.equal(dag.filters.length, 1);
|
||||
assert.equal(typeof dag.filters[0], "function");
|
||||
|
||||
// filters
|
||||
function testFilter(job, index, jobData) {
|
||||
return true;
|
||||
}
|
||||
dag = new JobDAG({
|
||||
filters: [testFilter]
|
||||
});
|
||||
assert.equal(dag.filters[0], testFilter);
|
||||
});
|
||||
|
||||
QUnit.test("JobDAG construction with history and jobs", function(assert) {
|
||||
assert.equal(testData.jobs1.length, 3);
|
||||
assert.equal(testData.historyContents1.length, 3);
|
||||
|
||||
var history = testData.historyContents1,
|
||||
jobs = testData.jobs1,
|
||||
dag;
|
||||
dag = new JobDAG({
|
||||
historyContents: history,
|
||||
tools: testData.tools,
|
||||
jobs: jobs
|
||||
});
|
||||
|
||||
assert.deepEqual(dag._outputIdToJobMap, {
|
||||
"8c959c9304a2bc4b": "8a81cf6f989c4467",
|
||||
"132016f833b57406": "6505e875ddb66fd2",
|
||||
"846fb0a2a64137c0": "77f74776fd03cbc5"
|
||||
});
|
||||
assert.deepEqual(dag._jobsData, [
|
||||
{
|
||||
job: _.findWhere(jobs, { id: "8a81cf6f989c4467" }),
|
||||
inputs: {},
|
||||
outputs: {
|
||||
"8c959c9304a2bc4b": {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b",
|
||||
name: "output0",
|
||||
content: _.findWhere(history, { id: "8c959c9304a2bc4b" })
|
||||
}
|
||||
},
|
||||
tool: {}
|
||||
},
|
||||
{
|
||||
job: _.findWhere(jobs, { id: "6505e875ddb66fd2" }),
|
||||
inputs: {
|
||||
"8c959c9304a2bc4b": {
|
||||
src: "hda",
|
||||
id: "8c959c9304a2bc4b",
|
||||
name: "input",
|
||||
content: _.findWhere(history, { id: "8c959c9304a2bc4b" })
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
"132016f833b57406": {
|
||||
src: "hda",
|
||||
id: "132016f833b57406",
|
||||
name: "out_file1",
|
||||
content: _.findWhere(history, { id: "132016f833b57406" })
|
||||
}
|
||||
},
|
||||
tool: {}
|
||||
},
|
||||
{
|
||||
job: _.findWhere(jobs, { id: "77f74776fd03cbc5" }),
|
||||
inputs: {
|
||||
"132016f833b57406": {
|
||||
src: "hda",
|
||||
id: "132016f833b57406",
|
||||
name: "input",
|
||||
content: _.findWhere(history, { id: "132016f833b57406" })
|
||||
}
|
||||
},
|
||||
outputs: {
|
||||
"846fb0a2a64137c0": {
|
||||
src: "hda",
|
||||
id: "846fb0a2a64137c0",
|
||||
name: "out_file1",
|
||||
content: _.findWhere(history, { id: "846fb0a2a64137c0" })
|
||||
}
|
||||
},
|
||||
tool: {}
|
||||
}
|
||||
]);
|
||||
|
||||
var jobsDataMap = dag._jobsDataMap();
|
||||
assert.deepEqual(dag.toNodesAndLinks(), {
|
||||
nodes: [
|
||||
{ name: "8a81cf6f989c4467", data: jobsDataMap["8a81cf6f989c4467"] },
|
||||
{ name: "6505e875ddb66fd2", data: jobsDataMap["6505e875ddb66fd2"] },
|
||||
{ name: "77f74776fd03cbc5", data: jobsDataMap["77f74776fd03cbc5"] }
|
||||
],
|
||||
links: [
|
||||
{ source: 0, target: 1, data: { dataset: "8c959c9304a2bc4b" } },
|
||||
{ source: 1, target: 2, data: { dataset: "132016f833b57406" } }
|
||||
]
|
||||
});
|
||||
|
||||
assert.deepEqual(dag.toVerticesAndEdges(), {
|
||||
vertices: [
|
||||
{ name: "8a81cf6f989c4467", data: jobsDataMap["8a81cf6f989c4467"] },
|
||||
{ name: "6505e875ddb66fd2", data: jobsDataMap["6505e875ddb66fd2"] },
|
||||
{ name: "77f74776fd03cbc5", data: jobsDataMap["77f74776fd03cbc5"] }
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: "8a81cf6f989c4467",
|
||||
target: "6505e875ddb66fd2",
|
||||
data: { dataset: "8c959c9304a2bc4b" }
|
||||
},
|
||||
{
|
||||
source: "6505e875ddb66fd2",
|
||||
target: "77f74776fd03cbc5",
|
||||
data: { dataset: "132016f833b57406" }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// test cloning
|
||||
});
|
||||
|
||||
QUnit.test("JobDAG removal of __SET_METADATA__ jobs", function(assert) {
|
||||
assert.equal(testData.jobs2.length, 3);
|
||||
assert.equal(testData.historyContents2.length, 2);
|
||||
|
||||
var history = testData.historyContents2,
|
||||
jobs = testData.jobs2,
|
||||
dag;
|
||||
dag = new JobDAG({
|
||||
historyContents: history,
|
||||
tools: testData.tools,
|
||||
jobs: jobs,
|
||||
excludeSetMetadata: true
|
||||
});
|
||||
|
||||
var jobsDataMap = dag._jobsDataMap();
|
||||
assert.deepEqual(dag.toNodesAndLinks(), {
|
||||
nodes: [
|
||||
{ name: "bf60fd5f5f7f44bf", data: jobsDataMap["bf60fd5f5f7f44bf"] },
|
||||
{ name: "90240358ebde1489", data: jobsDataMap["90240358ebde1489"] }
|
||||
],
|
||||
links: [{ source: 0, target: 1, data: { dataset: "eca0af6fb47bf90c" } }]
|
||||
});
|
||||
});
|
||||
|
||||
//TODO: test filtering out errored jobs
|
||||
QUnit.test("JobDAG construction with history and jobs", function(assert) {
|
||||
assert.equal(testData.jobs3.length, 5);
|
||||
assert.equal(testData.historyContents3.length, 5);
|
||||
|
||||
var history = testData.historyContents3,
|
||||
jobs = testData.jobs3,
|
||||
dag;
|
||||
dag = new JobDAG({
|
||||
historyContents: history,
|
||||
tools: testData.tools,
|
||||
jobs: jobs
|
||||
});
|
||||
|
||||
var jobsDataMap = dag._jobsDataMap();
|
||||
assert.deepEqual(dag.toVerticesAndEdges(), {
|
||||
vertices: [
|
||||
{ name: "8c959c9304a2bc4b", data: jobsDataMap["8c959c9304a2bc4b"] },
|
||||
{ name: "132016f833b57406", data: jobsDataMap["132016f833b57406"] },
|
||||
{ name: "846fb0a2a64137c0", data: jobsDataMap["846fb0a2a64137c0"] },
|
||||
{ name: "eca0af6fb47bf90c", data: jobsDataMap["eca0af6fb47bf90c"] },
|
||||
{ name: "6fc9fbb81c497f69", data: jobsDataMap["6fc9fbb81c497f69"] }
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: "8c959c9304a2bc4b",
|
||||
target: "846fb0a2a64137c0",
|
||||
data: { dataset: "6fb17d0cc6e8fae5" }
|
||||
},
|
||||
{
|
||||
source: "132016f833b57406",
|
||||
target: "eca0af6fb47bf90c",
|
||||
data: { dataset: "5114a2a207b7caff" }
|
||||
},
|
||||
{
|
||||
source: "eca0af6fb47bf90c",
|
||||
target: "6fc9fbb81c497f69",
|
||||
data: { dataset: "b8a0d6158b9961df" }
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
var components = dag.weakComponents();
|
||||
assert.deepEqual(components, [
|
||||
{
|
||||
vertices: [
|
||||
{ name: "8c959c9304a2bc4b", data: jobsDataMap["8c959c9304a2bc4b"] },
|
||||
{ name: "846fb0a2a64137c0", data: jobsDataMap["846fb0a2a64137c0"] }
|
||||
],
|
||||
edges: [{ source: "8c959c9304a2bc4b", target: "846fb0a2a64137c0" }]
|
||||
},
|
||||
{
|
||||
vertices: [
|
||||
{ name: "132016f833b57406", data: jobsDataMap["132016f833b57406"] },
|
||||
{ name: "eca0af6fb47bf90c", data: jobsDataMap["eca0af6fb47bf90c"] },
|
||||
{ name: "6fc9fbb81c497f69", data: jobsDataMap["6fc9fbb81c497f69"] }
|
||||
],
|
||||
edges: [
|
||||
{ source: "132016f833b57406", target: "eca0af6fb47bf90c" },
|
||||
{ source: "eca0af6fb47bf90c", target: "6fc9fbb81c497f69" }
|
||||
]
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
//TODO: test filtering out errored jobs
|
||||
QUnit.test("JobDAG construction with copied history contents", function(assert) {
|
||||
assert.equal(testData.jobs4.length, 1);
|
||||
assert.equal(testData.historyContents4.length, 3);
|
||||
|
||||
var history = testData.historyContents4,
|
||||
jobs = testData.jobs4,
|
||||
dag;
|
||||
dag = new JobDAG({
|
||||
historyContents: history,
|
||||
tools: testData.tools,
|
||||
jobs: jobs
|
||||
});
|
||||
|
||||
var jobsDataMap = dag._jobsDataMap();
|
||||
assert.deepEqual(dag.toVerticesAndEdges(), {
|
||||
vertices: [
|
||||
{ name: "92b83968e0b52980", data: jobsDataMap["92b83968e0b52980"] },
|
||||
{ name: "copy-422eef6b1b545329", data: _.findWhere(history, { id: "422eef6b1b545329" }) },
|
||||
{ name: "copy-c86c1b73aa7102dd", data: _.findWhere(history, { id: "c86c1b73aa7102dd" }) }
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
source: "copy-422eef6b1b545329",
|
||||
target: "92b83968e0b52980",
|
||||
data: { dataset: "422eef6b1b545329" }
|
||||
},
|
||||
{
|
||||
source: "copy-c86c1b73aa7102dd",
|
||||
target: "92b83968e0b52980",
|
||||
data: { dataset: "c86c1b73aa7102dd" }
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
/* global define */
|
||||
define(
|
||||
[
|
||||
"qunit/test-app",
|
||||
"mvc/collection/list-of-pairs-collection-creator",
|
||||
"qunit/test-data/paired-collection-creator.data",
|
||||
"jquery",
|
||||
"sinon"
|
||||
],
|
||||
function(testApp, PAIRED_COLLECTION_CREATOR, DATA, $, sinon) {
|
||||
"use strict";
|
||||
PAIRED_COLLECTION_CREATOR = PAIRED_COLLECTION_CREATOR.default;
|
||||
var PCC = PAIRED_COLLECTION_CREATOR.PairedCollectionCreator;
|
||||
|
||||
QUnit.module("Galaxy client app tests");
|
||||
|
||||
QUnit.test("Collection creation", function(assert) {
|
||||
var pcc = new PCC({
|
||||
datasets: DATA._1,
|
||||
historyId: "fakeHistoryId"
|
||||
}),
|
||||
server = sinon.fakeServer.create();
|
||||
|
||||
var requestJSON;
|
||||
server.respondWith("POST", "/api/histories/fakeHistoryId/contents/dataset_collections", function(request) {
|
||||
requestJSON = JSON.parse(request.requestBody);
|
||||
request.respond(
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify({
|
||||
fakeResponse: "yes"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
//console.debug( 'requestBody:', JSON.stringify( requestJSON, null, ' ' ) );
|
||||
pcc.createList("Heres a collection");
|
||||
server.respond();
|
||||
assert.deepEqual(requestJSON, DATA._1requestJSON);
|
||||
});
|
||||
|
||||
QUnit.test("Creator base/empty construction/initializiation defaults", function(assert) {
|
||||
var pcc = new PCC([]);
|
||||
assert.ok(pcc instanceof PCC);
|
||||
assert.deepEqual(pcc.filters, pcc.commonFilters[pcc.DEFAULT_FILTERS]);
|
||||
assert.ok(pcc.automaticallyPair);
|
||||
assert.equal(pcc.matchPercentage, 0.9);
|
||||
assert.equal(pcc.strategy, "autopairLCS");
|
||||
});
|
||||
|
||||
QUnit.test("Creator construction/initializiation with datasets", function(assert) {
|
||||
var pcc = new PCC({
|
||||
datasets: DATA._1
|
||||
});
|
||||
//pcc.initialList.forEach( function( dataset, i ){
|
||||
// console.log( i + ':\n' + JSON.stringify( dataset ) );
|
||||
//});
|
||||
// pcc maintains the original list - which, in this case, is already sorted
|
||||
assert.deepEqual(pcc.initialList, DATA._1);
|
||||
// datasets 1 has no ids, so the pcc will create them
|
||||
assert.ok(
|
||||
_.every(pcc.initialList, function(dataset) {
|
||||
return dataset.id;
|
||||
})
|
||||
);
|
||||
// datasets 1 is very easy to auto pair
|
||||
assert.equal(pcc.unpaired.length, 0);
|
||||
assert.equal(pcc.paired.length, pcc.initialList.length / 2);
|
||||
});
|
||||
|
||||
QUnit.test("Try easy autopairing with simple exact matching", function(assert) {
|
||||
var pcc = new PCC({
|
||||
datasets: DATA._1,
|
||||
strategy: "simple",
|
||||
twoPassAutopairing: false
|
||||
});
|
||||
assert.equal(pcc.unpaired.length, 0);
|
||||
assert.equal(pcc.paired.length, pcc.initialList.length / 2);
|
||||
});
|
||||
|
||||
QUnit.test("Try easy autopairing with LCS", function(assert) {
|
||||
var pcc = new PCC({
|
||||
datasets: DATA._1,
|
||||
strategy: "lcs",
|
||||
twoPassAutopairing: false
|
||||
});
|
||||
assert.equal(pcc.unpaired.length, 0);
|
||||
assert.equal(pcc.paired.length, pcc.initialList.length / 2);
|
||||
});
|
||||
|
||||
QUnit.test("Try easy autopairing with Levenshtein", function(assert) {
|
||||
var pcc = new PCC({
|
||||
datasets: DATA._1,
|
||||
strategy: "levenshtein",
|
||||
twoPassAutopairing: false
|
||||
});
|
||||
assert.equal(pcc.unpaired.length, 0);
|
||||
assert.equal(pcc.paired.length, pcc.initialList.length / 2);
|
||||
});
|
||||
|
||||
//TODO:
|
||||
// filters: clearing, setting via popover, regex
|
||||
// partition: maximize paired, maximize unpaired, split evenly
|
||||
// pairing: manually pairing and unpairing
|
||||
// misc: renaming pairs, removing file extensions
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,124 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "layout/masthead", "galaxy"], function(testApp, Masthead, Galaxy) {
|
||||
"use strict";
|
||||
Masthead = Masthead.default;
|
||||
QUnit.module("Masthead test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
var self = this;
|
||||
this.masthead = new Masthead.View({
|
||||
brand: "brand",
|
||||
use_remote_user: "use_remote_user",
|
||||
remote_user_logout_href: "remote_user_logout_href",
|
||||
lims_doc_url: "lims_doc_url",
|
||||
biostar_url: "biostar_url",
|
||||
biostar_url_redirect: "biostar_url_redirect",
|
||||
support_url: "support_url",
|
||||
search_url: "search_url",
|
||||
mailing_lists: "mailing_lists",
|
||||
screencasts_url: "screencasts_url",
|
||||
wiki_url: "wiki_url",
|
||||
citation_url: "citation_url",
|
||||
terms_url: "terms_url",
|
||||
logo_url: "logo_url",
|
||||
logo_src: "../../../static/images/galaxyIcon_noText.png",
|
||||
is_admin_user: "is_admin_user",
|
||||
active_view: "analysis",
|
||||
ftp_upload_dir: "ftp_upload_dir",
|
||||
ftp_upload_site: "ftp_upload_site",
|
||||
datatypes_disable_auto: true,
|
||||
allow_user_creation: true,
|
||||
enable_cloud_launch: true,
|
||||
user_requests: true
|
||||
});
|
||||
$("body").append(this.masthead.render().$el);
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("tabs", function(assert) {
|
||||
var tab = this.masthead.collection.findWhere({ id: "analysis" });
|
||||
var $tab = $("#analysis").find(".dropdown");
|
||||
var $toggle = $tab.find(".dropdown-toggle");
|
||||
var $note = $tab.find(".dropdown-note");
|
||||
var $menu = $tab.find("ul");
|
||||
assert.ok(tab && $tab.length == 1, "Found analysis tab");
|
||||
tab.set("title", "Analyze");
|
||||
assert.ok($toggle.html() == "Analyze", "Correct title");
|
||||
assert.ok(tab.get("target") == "_parent", "Correct initial target");
|
||||
tab.set("target", "_target");
|
||||
assert.ok($toggle.attr("target") == "_target", "Correct test target");
|
||||
assert.ok($tab.css("visibility") == "visible", "Tab visible");
|
||||
tab.set("visible", false);
|
||||
assert.ok($tab.css("visibility") == "hidden", "Tab hidden");
|
||||
tab.set("visible", true);
|
||||
assert.ok($tab.css("visibility") == "visible", "Tab visible, again");
|
||||
assert.ok($toggle.attr("href") == Galaxy.root, "Correct initial url");
|
||||
tab.set("url", "_url");
|
||||
assert.ok($toggle.attr("href") == "/_url", "Correct test url");
|
||||
tab.set("url", "http://_url");
|
||||
assert.ok($toggle.attr("href") == "http://_url", "Correct http url");
|
||||
tab.set("tooltip", "_tooltip");
|
||||
$toggle.trigger("mouseover");
|
||||
assert.ok($(".tooltip-inner").html() == "_tooltip", "Correct tooltip");
|
||||
tab.set("tooltip", null);
|
||||
$toggle.trigger("mouseover");
|
||||
assert.ok($(".tooltip-inner").length == 0, "Tooltip removed");
|
||||
tab.set("tooltip", "_tooltip_new");
|
||||
$toggle.trigger("mouseover");
|
||||
assert.ok($(".tooltip-inner").html() == "_tooltip_new", "Correct new tooltip");
|
||||
tab.set("cls", "_cls");
|
||||
assert.ok($toggle.hasClass("_cls"), "Correct extra class");
|
||||
tab.set("cls", "_cls_new");
|
||||
assert.ok($toggle.hasClass("_cls_new") && !$toggle.hasClass("_cls"), "Correct new extra class");
|
||||
assert.ok($note.html() == "", "Correct empty note");
|
||||
tab.set({ note: "_note", show_note: true });
|
||||
assert.ok($note.html() == "_note", "Correct new note");
|
||||
tab.set("toggle", true);
|
||||
assert.ok($toggle.hasClass("toggle"), "Toggled");
|
||||
tab.set("toggle", false);
|
||||
assert.ok(!$toggle.hasClass("toggle"), "Untoggled");
|
||||
tab.set("disabled", true);
|
||||
assert.ok($tab.hasClass("disabled"), "Correctly disabled");
|
||||
tab.set("disabled", false);
|
||||
assert.ok(!$tab.hasClass("disabled"), "Correctly enabled");
|
||||
assert.ok($tab.hasClass("active"), "Highlighted");
|
||||
tab.set("active", false);
|
||||
assert.ok(!$tab.hasClass("active"), "Not highlighted");
|
||||
tab.set("active", true);
|
||||
assert.ok($tab.hasClass("active"), "Highlighted, again");
|
||||
tab.set("menu", [{ title: "_menu_title", url: "_menu_url", target: "_menu_target" }]);
|
||||
assert.ok($menu.hasClass("dropdown-menu"), "Menu has correct class");
|
||||
assert.ok($menu.css("display") == "none", "Menu hidden");
|
||||
$toggle.trigger("click");
|
||||
assert.ok($menu.css("display") == "block", "Menu shown");
|
||||
var $item = $menu.find("a");
|
||||
assert.ok($item.length == 1, "Added one menu item");
|
||||
assert.ok($item.html() == "_menu_title", "Menu item has correct title");
|
||||
assert.ok($item.attr("href") == "/_menu_url", "Menu item has correct url");
|
||||
assert.ok($item.attr("target") == "_menu_target", "Menu item has correct target");
|
||||
tab.set("menu", null);
|
||||
$item = $menu.find("a");
|
||||
assert.ok($item.length == 0, "All menu items removed");
|
||||
tab.set("menu", [
|
||||
{ title: "_menu_title_0", url: "_menu_url_0", target: "_menu_target_0" },
|
||||
{ title: "_menu_title_1", url: "_menu_url_1", target: "_menu_target_1" }
|
||||
]);
|
||||
$item = $menu.find("a");
|
||||
assert.ok($item.length == 2, "Two menu items added");
|
||||
tab.set("show_menu", false);
|
||||
assert.ok($menu.css("display", "none"), "Menu manually hidden");
|
||||
tab.set("show_menu", true);
|
||||
assert.ok($menu.css("display", "block"), "Menu manually shown, again");
|
||||
var tab = this.masthead.collection.findWhere({ id: "enable-scratchbook" });
|
||||
var $tab = $("#enable-scratchbook").find(".dropdown");
|
||||
assert.ok(tab && $tab.length == 1, "Found tab to enable scratchbook");
|
||||
var $toggle = $tab.find(".dropdown-toggle");
|
||||
assert.ok(!$toggle.hasClass("toggle"), "Untoggled before click");
|
||||
$toggle.trigger("click");
|
||||
assert.ok($toggle.hasClass("toggle"), "Toggled after click");
|
||||
assert.ok(Galaxy.frame.active, "Scratchbook is active");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,370 @@
|
||||
// This file isn't really testing anything useful yet, it is just testing
|
||||
// (or demonstrating) qunit+backbone interactions.
|
||||
/* global define */
|
||||
define(["qunit/test-app", "utils/metrics-logger", "jquery", "sinon"], function(testApp, metrics, $, sinon) {
|
||||
"use strict";
|
||||
metrics = metrics.default;
|
||||
|
||||
var MockConsole = function() {
|
||||
var self = this;
|
||||
self.lastMessage = null;
|
||||
["log", "debug", "info", "warn", "error"].forEach(function(fnName) {
|
||||
self[fnName] = function() {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
self.lastMessage = { level: fnName, args: args };
|
||||
};
|
||||
});
|
||||
return self;
|
||||
};
|
||||
|
||||
(window.bootstrapped = {}).user = {
|
||||
id: "test"
|
||||
};
|
||||
|
||||
QUnit.module("Metrics logger tests");
|
||||
// ======================================================================== MetricsLogger
|
||||
QUnit.test("logger construction/initializiation defaults", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({});
|
||||
assert.equal(logger.consoleLogger, null);
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger.options.consoleLevel, metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger.options.defaultNamespace, "Galaxy");
|
||||
assert.equal(logger.options.clientPrefix, "client.");
|
||||
assert.equal(logger.options.postSize, 1000);
|
||||
assert.equal(logger.options.maxCacheSize, 3000);
|
||||
assert.equal(logger.options.addTime, true);
|
||||
assert.equal(logger.options.postUrl, "/api/metrics");
|
||||
assert.equal(logger.options.getPingData, undefined);
|
||||
assert.equal(logger.options.onServerResponse, undefined);
|
||||
|
||||
assert.equal(logger._postSize, 1000);
|
||||
assert.equal(logger.cache.constructor, metrics.LoggingCache);
|
||||
});
|
||||
|
||||
QUnit.test("_parseLevel", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({});
|
||||
assert.equal(logger._parseLevel("all"), metrics.MetricsLogger.ALL);
|
||||
assert.equal(logger._parseLevel("debug"), metrics.MetricsLogger.DEBUG);
|
||||
assert.equal(logger._parseLevel("info"), metrics.MetricsLogger.INFO);
|
||||
assert.equal(logger._parseLevel("warn"), metrics.MetricsLogger.WARN);
|
||||
assert.equal(logger._parseLevel("error"), metrics.MetricsLogger.ERROR);
|
||||
assert.equal(logger._parseLevel("metric"), metrics.MetricsLogger.METRIC);
|
||||
assert.equal(logger._parseLevel("none"), metrics.MetricsLogger.NONE);
|
||||
assert.equal(logger._parseLevel(15), 15);
|
||||
|
||||
assert.throws(
|
||||
function() {
|
||||
logger._parseLevel(undefined);
|
||||
},
|
||||
/Unknown log level/,
|
||||
"Unknown log level throws error"
|
||||
);
|
||||
assert.throws(
|
||||
function() {
|
||||
logger._parseLevel("nope");
|
||||
},
|
||||
/Unknown log level/,
|
||||
"Unknown log level throws error"
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Emit to cache
|
||||
QUnit.test("emit to cache at level", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric"
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.METRIC);
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 1);
|
||||
|
||||
var cached = logger.cache.get(1)[0];
|
||||
//console.debug( 'cached:', JSON.stringify( cached ) );
|
||||
assert.equal(cached.level, metrics.MetricsLogger.METRIC);
|
||||
assert.equal(cached.namespace, "client.test");
|
||||
assert.equal(cached.args.length, 3);
|
||||
assert.equal(cached.args[2].three, 3);
|
||||
assert.ok(typeof cached.time === "string");
|
||||
assert.ok(cached.time === new Date(cached.time).toISOString());
|
||||
});
|
||||
|
||||
QUnit.test("emit to cache below does not cache", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric"
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
logger.emit("error", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 0);
|
||||
});
|
||||
|
||||
QUnit.test("emit to cache (silently) drops non-parsable", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric"
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
logger.emit("metric", "test", [{ window: window }]);
|
||||
assert.equal(logger.cache.length(), 0);
|
||||
});
|
||||
|
||||
function metricsFromRequestBody(request) {
|
||||
// assumes 'metrics' is only entry in requestBody
|
||||
return JSON.parse(decodeURIComponent(request.requestBody.replace("metrics=", "")));
|
||||
}
|
||||
|
||||
QUnit.test("_postCache success", function(assert) {
|
||||
var callback = sinon.spy(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
onServerResponse: function(response) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
var server = sinon.fakeServer.create(),
|
||||
metricsOnServer;
|
||||
server.respondWith("POST", "/api/metrics", function(request) {
|
||||
metricsOnServer = metricsFromRequestBody(request);
|
||||
//console.debug( 'requestBody:', request.requestBody );
|
||||
//console.debug( 'metricsOnServer:', JSON.stringify( metricsOnServer, null, ' ' ) );
|
||||
request.respond(
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify({
|
||||
fakeResponse: "yes"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
logger._postCache();
|
||||
server.respond();
|
||||
|
||||
assert.ok(callback.calledOnce, "onServerResponse was called");
|
||||
assert.equal(logger.cache.length(), 0, "should have emptied cache (on success)");
|
||||
assert.equal(logger._postSize, 1000, "_postSize still at default");
|
||||
|
||||
// metrics were in proper form on server
|
||||
assert.equal(metricsOnServer.length, 1);
|
||||
var metric = metricsOnServer[0];
|
||||
assert.equal(metric.level, metrics.MetricsLogger.METRIC);
|
||||
assert.equal(metric.namespace, "client.test");
|
||||
assert.equal(metric.args.length, 3);
|
||||
assert.equal(metric.args[2].three, 3);
|
||||
assert.ok(typeof metric.time === "string");
|
||||
assert.ok(metric.time === new Date(metric.time).toISOString());
|
||||
|
||||
server.restore();
|
||||
});
|
||||
|
||||
QUnit.test("_postCache failure", function(assert) {
|
||||
var callback = sinon.spy(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
logLevel: "metric",
|
||||
onServerResponse: function(response) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
var server = sinon.fakeServer.create();
|
||||
server.respondWith("POST", "/api/metrics", function(request) {
|
||||
request.respond(
|
||||
500,
|
||||
{ "Content-Type": "application/json" },
|
||||
JSON.stringify({
|
||||
err_msg: "NoooOPE!"
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
logger.emit("metric", "test", [1, 2, { three: 3 }]);
|
||||
logger._postCache();
|
||||
server.respond();
|
||||
//TODO: is the following what we want?
|
||||
assert.ok(!callback.calledOnce, "onServerResponse was NOT called");
|
||||
assert.equal(logger.cache.length(), 1, "should NOT have emptied cache");
|
||||
assert.equal(logger._postSize, logger.options.maxCacheSize, "_postSize changed to max");
|
||||
|
||||
server.restore();
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Emit to console
|
||||
QUnit.test("emit to console at level", function(assert) {
|
||||
var mockConsole = new MockConsole(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
consoleLevel: "debug",
|
||||
consoleLogger: mockConsole
|
||||
});
|
||||
assert.equal(logger.options.consoleLevel, metrics.MetricsLogger.DEBUG);
|
||||
assert.equal(logger.consoleLogger.constructor, MockConsole);
|
||||
|
||||
logger.emit("debug", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(logger.cache.length(), 1);
|
||||
//console.debug( JSON.stringify( mockConsole.lastMessage ) );
|
||||
assert.equal(mockConsole.lastMessage.level, "debug");
|
||||
assert.equal(mockConsole.lastMessage.args.length, 4);
|
||||
assert.equal(mockConsole.lastMessage.args[0], "test");
|
||||
assert.equal(mockConsole.lastMessage.args[3].three, 3);
|
||||
});
|
||||
|
||||
QUnit.test("emit to console below does not output", function(assert) {
|
||||
var mockConsole = new MockConsole(),
|
||||
logger = new metrics.MetricsLogger({
|
||||
consoleLevel: "error",
|
||||
consoleLogger: mockConsole
|
||||
});
|
||||
logger.emit("debug", "test", [1, 2, { three: 3 }]);
|
||||
assert.equal(mockConsole.lastMessage, null);
|
||||
});
|
||||
|
||||
// ------------------------------------------------------------------------ Shortcuts
|
||||
QUnit.test("logger shortcuts emit to default namespace properly", function(assert) {
|
||||
var logger = new metrics.MetricsLogger({
|
||||
logLevel: "all"
|
||||
});
|
||||
logger.cache.empty();
|
||||
|
||||
assert.equal(logger.options.logLevel, metrics.MetricsLogger.ALL);
|
||||
logger.log(0);
|
||||
logger.debug(1);
|
||||
logger.info(2);
|
||||
logger.warn(3);
|
||||
logger.error(4);
|
||||
logger.metric(5);
|
||||
|
||||
assert.equal(logger.cache.length(), 6);
|
||||
var cached = logger.cache.remove(6),
|
||||
entry;
|
||||
|
||||
cached.forEach(function(entry) {
|
||||
assert.ok(entry.namespace === logger.options.clientPrefix + logger.options.defaultNamespace);
|
||||
assert.ok(jQuery.type(entry.args) === "array");
|
||||
assert.ok(typeof entry.time === "string");
|
||||
});
|
||||
|
||||
// log is different
|
||||
entry = cached[0];
|
||||
assert.ok(entry.level === 1);
|
||||
assert.ok(entry.args[0] === 0);
|
||||
|
||||
["debug", "info", "warn", "error", "metric"].forEach(function(level, i) {
|
||||
entry = cached[i + 1];
|
||||
assert.ok(entry.level === logger._parseLevel(level));
|
||||
assert.ok(entry.args[0] === i + 1);
|
||||
});
|
||||
});
|
||||
|
||||
// ======================================================================== LoggingCache
|
||||
QUnit.test("cache construction/initializiation defaults", function(assert) {
|
||||
// use empty to prevent tests stepping on one another due to persistence
|
||||
var cache = new metrics.LoggingCache({ key: "logs-test" }).empty();
|
||||
assert.equal(cache.maxSize, 5000);
|
||||
assert.equal(window.localStorage.getItem("logs-test"), "[]");
|
||||
});
|
||||
|
||||
QUnit.test("cache construction/initializiation failure", function(assert) {
|
||||
////TODO: doesn't work - readonly
|
||||
//window.localStorage = null;
|
||||
//console.debug( 'localStorage:', window.localStorage );
|
||||
var oldFn = metrics.LoggingCache.prototype._hasStorage;
|
||||
metrics.LoggingCache.prototype._hasStorage = function() {
|
||||
return false;
|
||||
};
|
||||
assert.throws(
|
||||
function() {
|
||||
return new metrics.LoggingCache({ key: "logs-test" });
|
||||
},
|
||||
/LoggingCache needs localStorage/,
|
||||
"lack of localStorage throws error"
|
||||
);
|
||||
metrics.LoggingCache.prototype._hasStorage = oldFn;
|
||||
|
||||
assert.throws(
|
||||
function() {
|
||||
return new metrics.LoggingCache();
|
||||
},
|
||||
/LoggingCache needs key for localStorage/,
|
||||
"lack of key throws error"
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("cache construction/initializiation setting max cache size", function(assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5
|
||||
}).empty();
|
||||
assert.equal(cache.maxSize, 5);
|
||||
});
|
||||
|
||||
QUnit.test("cache plays well with no data", function(assert) {
|
||||
var cache = new metrics.LoggingCache({ key: "logs-test" }).empty();
|
||||
|
||||
assert.equal(cache.length(), 0);
|
||||
var get = cache.get(10);
|
||||
assert.ok(jQuery.type(get) === "array" && get.length === 0);
|
||||
var remove = cache.remove(10);
|
||||
assert.ok(jQuery.type(remove) === "array" && remove.length === 0);
|
||||
assert.equal(cache.length(), 0);
|
||||
});
|
||||
|
||||
QUnit.test("cache add properly adds and removes data", function(assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5
|
||||
}).empty();
|
||||
|
||||
var entry1 = [{ one: 1 }, "two"];
|
||||
cache.add(entry1);
|
||||
|
||||
assert.equal(cache.length(), 1);
|
||||
assert.equal(JSON.stringify(cache.get(1)[0]), JSON.stringify(entry1));
|
||||
|
||||
var entry2 = { blah: { one: 1 }, bler: ["three", { two: 2 }] };
|
||||
cache.add(entry2);
|
||||
assert.equal(cache.length(), 2);
|
||||
assert.equal(cache.stringify(2), "[" + JSON.stringify(entry1) + "," + JSON.stringify(entry2) + "]");
|
||||
|
||||
// FIFO
|
||||
var returned = cache.remove(1);
|
||||
assert.equal(cache.length(), 1);
|
||||
assert.ok(jQuery.type(returned) === "array" && returned.length === 1);
|
||||
var returned0 = returned[0];
|
||||
assert.ok(jQuery.type(returned0) === "array" && JSON.stringify(returned0) === JSON.stringify(entry1));
|
||||
});
|
||||
|
||||
QUnit.test("cache past max loses oldest", function(assert) {
|
||||
var cache = new metrics.LoggingCache({
|
||||
key: "logs-test",
|
||||
maxSize: 5
|
||||
}).empty();
|
||||
|
||||
for (var i = 0; i < 10; i += 1) {
|
||||
cache.add({ index: i });
|
||||
}
|
||||
assert.equal(cache.length(), 5);
|
||||
var get = cache.get(5);
|
||||
assert.ok(get[0].index === 5);
|
||||
assert.ok(get[1].index === 6);
|
||||
assert.ok(get[2].index === 7);
|
||||
assert.ok(get[3].index === 8);
|
||||
assert.ok(get[4].index === 9);
|
||||
});
|
||||
|
||||
QUnit.test("cache is properly persistent", function(assert) {
|
||||
var cache1 = new metrics.LoggingCache({ key: "logs-test" }).empty(),
|
||||
entry = [{ one: 1 }, "two"];
|
||||
cache1.add(entry);
|
||||
assert.equal(cache1.length(), 1);
|
||||
|
||||
var cache2 = new metrics.LoggingCache({ key: "logs-test" });
|
||||
assert.equal(cache2.length(), 1, "old key gets previously stored");
|
||||
assert.equal(JSON.stringify(cache2.get(1)[0]), JSON.stringify(entry));
|
||||
|
||||
var cache3 = new metrics.LoggingCache({ key: "logs-bler" });
|
||||
assert.equal(cache3.length(), 0, "new key causes new storage");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
/* global define */
|
||||
|
||||
define(["qunit/test-app", "mvc/ui/ui-modal", "sinon"], function(testApp, GalaxyModal, sinon) {
|
||||
"use strict";
|
||||
GalaxyModal = GalaxyModal.default;
|
||||
QUnit.module("Modal dialog test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
this.clock = sinon.useFakeTimers();
|
||||
var self = this;
|
||||
this.app = new GalaxyModal.View({
|
||||
title: "Test title",
|
||||
body: "Test body",
|
||||
buttons: {
|
||||
Ok: function() {},
|
||||
Cancel: function() {
|
||||
self.app.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
this.clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("test dialog attributes", function(assert) {
|
||||
assert.ok(this.app.$header.find(".title").html() == "Test title", "Modal header has correct title.");
|
||||
assert.ok(this.app.$body.html() == "Test body", "Modal header has correct body.");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog visibility", function(assert) {
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal is initially visible");
|
||||
this.app.hide();
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden manually");
|
||||
this.app.show();
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown manually");
|
||||
this.app.getButton("Ok").trigger("click");
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal still visible after clicking Ok");
|
||||
this.app.getButton("Cancel").trigger("click");
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden after clicking Cancel");
|
||||
this.app.show();
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal manually shown again");
|
||||
assert.ok(!this.app.$header.hasClass("no-separator"), "Title separator tagged as visible.");
|
||||
this.app.show({ title_separator: false });
|
||||
assert.ok(this.app.$header.hasClass("no-separator"), "Title separator tagged as hidden.");
|
||||
assert.ok(this.app.$backdrop.hasClass("in"), "Backdrop tagged as shown.");
|
||||
this.app.show({ backdrop: false });
|
||||
assert.ok(!this.app.$backdrop.hasClass("in"), "Backdrop tagged as hidden.");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog closing events", function(assert) {
|
||||
this.app.$backdrop.trigger("click");
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown after backdrop click");
|
||||
this.app.show({ closing_events: true });
|
||||
assert.ok(this.app.$el.css("display") == "block", "Modal shown with closing events");
|
||||
this.app.$backdrop.trigger("click");
|
||||
this.clock.tick(WAIT_FADE);
|
||||
assert.ok(this.app.$el.css("display") == "none", "Modal hidden after backdrop click");
|
||||
});
|
||||
|
||||
QUnit.test("test dialog rendering", function(assert) {
|
||||
var before = this.app.$el.html();
|
||||
this.app.render();
|
||||
assert.ok(before == this.app.$el.html(), "Re-rendering successful");
|
||||
this.app.options.title = "New Title";
|
||||
this.app.render();
|
||||
assert.ok(this.app.$header.find(".title").html() == "New Title", "Modal header has correct new title.");
|
||||
});
|
||||
|
||||
QUnit.test("test button states", function(assert) {
|
||||
assert.ok(this.app.getButton("Ok").html() === "Ok", "Ok has correct label");
|
||||
assert.ok(!this.app.getButton("Ok").prop("disabled"), "Ok is active");
|
||||
assert.ok(!this.app.getButton("Cancel").prop("disabled"), "Cancel is active");
|
||||
this.app.disableButton("Ok");
|
||||
assert.ok(this.app.getButton("Ok").prop("disabled"), "Ok is disabled");
|
||||
assert.ok(!this.app.getButton("Cancel").prop("disabled"), "Cancel is still active");
|
||||
this.app.disableButton("Cancel");
|
||||
assert.ok(this.app.getButton("Cancel").prop("disabled"), "Cancel is also disabled");
|
||||
assert.ok(this.app.getButton("Ok").prop("disabled"), "Ok is still disabled");
|
||||
this.app.enableButton("Ok");
|
||||
assert.ok(this.app.getButton("Cancel").prop("disabled"), "Cancel is still disabled");
|
||||
assert.ok(!this.app.getButton("Ok").prop("disabled"), "Ok is active again");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
/* global define */
|
||||
|
||||
define(["qunit/test-app", "layout/page", "layout/panel"], function(testApp, Page, Panel) {
|
||||
"use strict";
|
||||
Page = Page.default;
|
||||
Panel = Panel.default;
|
||||
QUnit.module("Page test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
$("body").append((this.$container = $("<div/>").css("display", "none")));
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
function _check(assert, page, sidePanels) {
|
||||
assert.ok(page.$("#center").length == 1, "Center panel found.");
|
||||
_.each(sidePanels, function(panelVisible, panelId) {
|
||||
assert.ok(
|
||||
page.$("#" + panelId).css("display") == panelVisible,
|
||||
(panelVisible ? "" : "No") + " " + panelId + " panel found."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QUnit.test("test center/right", function(assert) {
|
||||
this.$container.empty();
|
||||
var page = new Page.View({
|
||||
Right: Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.setElement($("<div/>"));
|
||||
this.model = new Backbone.Model({});
|
||||
}
|
||||
})
|
||||
}).render();
|
||||
_check(assert, page, { left: "none", right: "block" });
|
||||
});
|
||||
QUnit.test("test center", function(assert) {
|
||||
this.$container.empty();
|
||||
var page = new Page.View({}).render();
|
||||
_check(assert, page, { left: "none", right: "none" });
|
||||
});
|
||||
QUnit.test("test left/center", function(assert) {
|
||||
this.$container.empty();
|
||||
var page = new Page.View({
|
||||
Left: Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.setElement($("<div/>"));
|
||||
this.model = new Backbone.Model({});
|
||||
}
|
||||
})
|
||||
}).render();
|
||||
_check(assert, page, { left: "block", right: "none" });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "mvc/ui/ui-misc", "mvc/ui/ui-popover"], function(testApp, Ui, Popover) {
|
||||
"use strict";
|
||||
Ui = Ui.default;
|
||||
Popover = Popover.default;
|
||||
QUnit.module("Popover test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
var self = this;
|
||||
this.button = new Ui.Button({
|
||||
title: "Test button",
|
||||
onclick: function() {
|
||||
self.popover.show();
|
||||
}
|
||||
});
|
||||
this.$parent = $("<div/>").append(this.button.$el);
|
||||
this.popover = new Popover.View({
|
||||
title: "Test Title",
|
||||
body: "Test Body",
|
||||
placement: "bottom",
|
||||
container: this.button.$el
|
||||
});
|
||||
$("body").append(this.$parent);
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("test popover visibility", function(assert) {
|
||||
assert.ok(this.popover.$el.css("display") == "none", "Popover is hidden.");
|
||||
this.button.$el.trigger("click");
|
||||
assert.ok(this.popover.$el.css("display") == "block", "Popover is shown.");
|
||||
assert.ok(this.popover.$el.hasClass("bottom"), "Popover at bottom.");
|
||||
this.popover.hide();
|
||||
assert.ok(this.popover.$el.css("display") == "none", "Popover is hidden manually.");
|
||||
assert.ok(this.popover.$title.html() == "Test Title", "Initial title correct.");
|
||||
this.popover.title("New Title");
|
||||
assert.ok(this.popover.$title.html() == "New Title", "New title correct.");
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,87 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "mvc/upload/upload-view"], function(testApp, GalaxyUpload) {
|
||||
"use strict";
|
||||
GalaxyUpload = GalaxyUpload.default;
|
||||
QUnit.module("Upload dialog test", {
|
||||
beforeEach: function() {
|
||||
testApp.create();
|
||||
this.app = new GalaxyUpload();
|
||||
},
|
||||
afterEach: function() {
|
||||
testApp.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("test initial dialog state", function(assert) {
|
||||
$(this.app.ui_button.$el).trigger("click");
|
||||
assert.ok(this.app.default_view.collection.length == 0, "Invalid initial upload item collection.");
|
||||
assert.ok($("#btn-start").hasClass("disabled"), "Start button should be disabled.");
|
||||
assert.ok($("#btn-stop").hasClass("disabled"), "Stop button should be disabled.");
|
||||
assert.ok($("#btn-reset").hasClass("disabled"), "Reset button should be disabled.");
|
||||
});
|
||||
|
||||
QUnit.test("test adding/removing paste/fetch upload item", function(assert) {
|
||||
$(this.app.ui_button.$el).trigger("click");
|
||||
$("#btn-new").trigger("click");
|
||||
assert.ok(!$("#btn-start").hasClass("disabled"), "Start button should be enabled.");
|
||||
assert.ok($("#btn-stop").hasClass("disabled"), "Stop button should (still) be disabled.");
|
||||
assert.ok(!$("#btn-reset").hasClass("disabled"), "Reset button should be enabled.");
|
||||
assert.ok(
|
||||
this.app.default_view.collection.length == 1,
|
||||
"Invalid upload item collection length after adding item."
|
||||
);
|
||||
assert.ok(
|
||||
$("#btn-new")
|
||||
.find("i")
|
||||
.hasClass("fa-edit"),
|
||||
"Paste/fetch icon changed"
|
||||
);
|
||||
assert.ok($("#btn-start").hasClass("btn-primary"), "Start button should be enabled/highlighted.");
|
||||
assert.ok(
|
||||
$("#upload-row-0")
|
||||
.find(".upload-symbol")
|
||||
.hasClass("fa-trash-o"),
|
||||
"Should show regular trash icon."
|
||||
);
|
||||
$("#upload-row-0")
|
||||
.find(".upload-settings")
|
||||
.trigger("click");
|
||||
assert.ok(
|
||||
$("#upload-row-0")
|
||||
.find(".upload-settings-cover")
|
||||
.css("display") == "none",
|
||||
"Settings should be enabled."
|
||||
);
|
||||
$("#upload-row-0")
|
||||
.find(".popover-close")
|
||||
.trigger("click");
|
||||
$("#btn-start").trigger("click");
|
||||
assert.ok(
|
||||
$("#upload-row-0")
|
||||
.find(".upload-symbol")
|
||||
.hasClass("fa-exclamation-triangle"),
|
||||
"Upload attempt should have failed."
|
||||
);
|
||||
assert.ok(
|
||||
$("#upload-row-0")
|
||||
.find(".upload-settings")
|
||||
.trigger("click")
|
||||
);
|
||||
assert.ok(
|
||||
$("#upload-row-0")
|
||||
.find(".upload-settings-cover")
|
||||
.css("display") == "block",
|
||||
"Settings should be disabled."
|
||||
);
|
||||
$("#upload-row-0")
|
||||
.find(".upload-symbol")
|
||||
.trigger("click");
|
||||
assert.ok(this.app.default_view.collection.length == 0, "Removing item from collection failed.");
|
||||
});
|
||||
|
||||
QUnit.test("test ftp popup", function(assert) {
|
||||
$(this.app.ui_button.$el).trigger("click");
|
||||
$("#btn-ftp").trigger("click");
|
||||
assert.ok($(".upload-ftp").length == 1, "Should show ftp popover.");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
/* global define */
|
||||
define(["qunit/test-app", "utils/utils"], function(testApp, Utils) {
|
||||
"use strict";
|
||||
Utils = Utils.default;
|
||||
QUnit.module("Utils test", {});
|
||||
|
||||
QUnit.test("isEmpty", function(assert) {
|
||||
assert.ok(Utils.isEmpty([]), "Empty array");
|
||||
assert.ok(Utils.isEmpty(["data", undefined]), "Array contains `undefined`");
|
||||
assert.ok(Utils.isEmpty(["data", null]), "Array contains `null`");
|
||||
assert.ok(Utils.isEmpty(["data", "__null__"]), "Array contains `__null__`");
|
||||
assert.ok(Utils.isEmpty(["data", "__undefined__"]), "Array contains `__undefined__`");
|
||||
assert.ok(Utils.isEmpty(null), "Array is null");
|
||||
assert.ok(Utils.isEmpty("__null__"), "Array is __null__");
|
||||
assert.ok(Utils.isEmpty("__undefined__"), "Array is __undefined__");
|
||||
assert.ok(!Utils.isEmpty(["data"]), "Array contains `data`");
|
||||
assert.ok(!Utils.isEmpty(1), "Value is int");
|
||||
assert.ok(!Utils.isEmpty(0), "Value is zero");
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1855,3 +1855,8 @@ div.toolTitleNoSection
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* For Vue */
|
||||
[v-cloak] {
|
||||
display:none;
|
||||
}
|
||||
|
||||
+5
-3
@@ -16,8 +16,9 @@ var paths = {
|
||||
node_modules: './node_modules',
|
||||
scripts: [
|
||||
'galaxy/scripts/**/*.js',
|
||||
'!galaxy/scripts/apps/**/*.js',
|
||||
'!galaxy/scripts/libs/**/*.js'
|
||||
'!galaxy/scripts/qunit/**/*',
|
||||
'!galaxy/scripts/apps/**/*',
|
||||
'!galaxy/scripts/libs/**/*'
|
||||
],
|
||||
lib_locs: {
|
||||
// This is a stepping stone towards having all this staged
|
||||
@@ -25,7 +26,7 @@ var paths = {
|
||||
// not be necessary.
|
||||
'backbone': [ 'backbone.js', 'backbone.js' ],
|
||||
'd3': [ 'd3.js', 'd3.js' ],
|
||||
'bib2json': [ 'Parser.js', 'bibtex.js' ],
|
||||
'bibtex-parse-js': [ 'bibtexParse.js', 'bibtexParse.js' ],
|
||||
'jquery': ['dist/jquery.js', 'jquery/jquery.js'],
|
||||
'jquery.complexify': [ 'jquery.complexify.js', 'jquery/jquery.complexify.js' ],
|
||||
'jquery.cookie': [ 'jquery.cookie.js', 'jquery/jquery.cookie.js' ],
|
||||
@@ -34,6 +35,7 @@ var paths = {
|
||||
'raven-js': ['dist/raven.js', 'raven.js'],
|
||||
'requirejs': [ 'require.js', 'require.js' ],
|
||||
'underscore': [ 'underscore.js', 'underscore.js' ],
|
||||
'vue': [ 'dist/vue.js', 'vue.js' ]
|
||||
},
|
||||
libs: ['galaxy/scripts/libs/**/*.js']
|
||||
};
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
var webpackConfig = require('./webpack.config');
|
||||
|
||||
// CommonsChunkPlugin not compatible with karma.
|
||||
// https://github.com/webpack-contrib/karma-webpack/issues/24
|
||||
webpackConfig.plugins.splice(0, 1);
|
||||
|
||||
// karma.conf.js
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
basepath: '.',
|
||||
files: [
|
||||
// Broken into uncommented working tests and commented out broken tests,
|
||||
// this can be replaced with a glob when they all just work.
|
||||
|
||||
// Working tests:
|
||||
'galaxy/scripts/qunit/tests/list-of-pairs-collection-creator.js',
|
||||
'galaxy/scripts/qunit/tests/galaxy-app-base.js',
|
||||
'galaxy/scripts/qunit/tests/graph.js',
|
||||
'galaxy/scripts/qunit/tests/hda-base.js',
|
||||
'galaxy/scripts/qunit/tests/history_contents_model_tests.js',
|
||||
'galaxy/scripts/qunit/tests/job-dag.js',
|
||||
'galaxy/scripts/qunit/tests/metrics-logger.js',
|
||||
'galaxy/scripts/qunit/tests/popover_tests.js',
|
||||
'galaxy/scripts/qunit/tests/utils_test.js',
|
||||
'galaxy/scripts/qunit/tests/page_tests.js',
|
||||
'galaxy/scripts/qunit/tests/workflow_editor_tests.js',
|
||||
|
||||
// The following tests don't work for state reasons:
|
||||
|
||||
// Error: Following test works on its own or with rest but not with
|
||||
// list-of-pairs-collection-creator in the same suite. Not as much isolation
|
||||
// as seperate page setup of previous runner.
|
||||
// 'galaxy/scripts/qunit/tests/ui_tests.js',
|
||||
// Error: things displayed wrong I guess cause assertions fail on CSS stuff
|
||||
// 'galaxy/scripts/qunit/tests/modal_tests.js',
|
||||
// 'galaxy/scripts/qunit/tests/upload_dialog_tests.js',
|
||||
// Error: Cannot find module "libs/bibtexParse"
|
||||
// 'galaxy/scripts/qunit/tests/form_tests.js',
|
||||
// 'galaxy/scripts/qunit/tests/masthead_tests.js',
|
||||
|
||||
// Non-test assets that will be served by web server.
|
||||
// CSS needed by tests.
|
||||
'galaxy/scripts/qunit/assets/*.css',
|
||||
],
|
||||
|
||||
plugins: [
|
||||
'karma-webpack',
|
||||
'karma-qunit',
|
||||
'karma-polyfill',
|
||||
'karma-phantomjs-launcher',
|
||||
],
|
||||
polyfill: [ 'Object.assign' ],
|
||||
browsers: [ 'PhantomJS' ],
|
||||
// logLevel: config.LOG_DEBUG,
|
||||
|
||||
// Tried to do some awesome babel, ES6 stuff in here but I was encountering
|
||||
// problems so I simplified - might be worth adding it back in though now
|
||||
// that we have a working setup.
|
||||
preprocessors: {
|
||||
// add webpack as preprocessor
|
||||
'galaxy/scripts/qunit/tests/*.js': ['webpack'],
|
||||
},
|
||||
|
||||
frameworks: ['polyfill', 'qunit'],
|
||||
|
||||
webpack: webpackConfig,
|
||||
webpackMiddleware: { noInfo: false }
|
||||
|
||||
});
|
||||
};
|
||||
+19
-2
@@ -12,17 +12,21 @@
|
||||
"license": "AFL-3.0",
|
||||
"dependencies": {
|
||||
"amdi18n-loader": "^0.6.1",
|
||||
"axios": "^0.17.0",
|
||||
"backbone": "1.3",
|
||||
"bib2json": "^0.0.1",
|
||||
"bibtex-parse-js": "^0.0.24",
|
||||
"d3": "3",
|
||||
"jquery": "2",
|
||||
"jquery-migrate": "~1.4",
|
||||
"jquery-mousewheel": "^3.1.13",
|
||||
"jquery.complexify": "^0.5.2",
|
||||
"jquery.cookie": "^1.4.1",
|
||||
"latex-parser": "^0.6.2",
|
||||
"latex-to-unicode-converter": "^0.5.0",
|
||||
"raven-js": "^3.17.0",
|
||||
"requirejs": "2",
|
||||
"underscore": "^1.8.3"
|
||||
"underscore": "^1.8.3",
|
||||
"vue": "^2.5.3"
|
||||
},
|
||||
"scripts": {
|
||||
"watch": "gulp stage-libs && concurrently \"yarn run webpack-watch\" \"yarn run gulp watch\" \"yarn run style-watch\"",
|
||||
@@ -33,6 +37,7 @@
|
||||
"webpack-dev-watch": "webpack -d --watch",
|
||||
"style": "grunt style",
|
||||
"style-watch": "grunt watch-style",
|
||||
"test": "karma start --verbose --single-run --no-auto-watch karma.config.js",
|
||||
"gulp": "gulp",
|
||||
"build-toolshed": "grunt --app=toolshed",
|
||||
"jshint": "jshint --exclude='galaxy/scripts/libs/**' galaxy/scripts/**/*.js",
|
||||
@@ -44,6 +49,7 @@
|
||||
"babel-loader": "^7.1.1",
|
||||
"babel-preset-env": "^1.3.2",
|
||||
"concurrently": "^3.4.0",
|
||||
"css-loader": "^0.28.7",
|
||||
"del": "^3.0.0",
|
||||
"expose-loader": "^0.7.3",
|
||||
"grunt": "^0.4.5",
|
||||
@@ -66,7 +72,18 @@
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"gulp-watch": "^4.3.11",
|
||||
"jshint": "^2.9.4",
|
||||
"karma": "^1.7.1",
|
||||
"karma-phantomjs-launcher": "^1.0.4",
|
||||
"karma-polyfill": "^1.0.0",
|
||||
"karma-qunit": "^1.2.1",
|
||||
"karma-webpack": "^2.0.6",
|
||||
"phantomjs-polyfill": "0.0.2",
|
||||
"phantomjs-prebuilt": "^2.1.7",
|
||||
"prettier": "^1.7.4",
|
||||
"qunitjs": "^2.4.1",
|
||||
"sinon": "^4.1.2",
|
||||
"vue-loader": "^13.5.0",
|
||||
"vue-template-compiler": "^2.5.3",
|
||||
"webpack": "^3.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ var commonLibs = [
|
||||
"libs/farbtastic",
|
||||
"libs/bootstrap",
|
||||
"libs/bootstrap-tour",
|
||||
"libs/vue",
|
||||
// mvc
|
||||
"libs/underscore",
|
||||
"libs/backbone",
|
||||
@@ -42,14 +43,19 @@ module.exports = {
|
||||
libs: commonLibs,
|
||||
login: "./galaxy/scripts/apps/login.js",
|
||||
analysis: "./galaxy/scripts/apps/analysis.js",
|
||||
admin: "./galaxy/scripts/apps/admin.js"
|
||||
admin: "./galaxy/scripts/apps/admin.js",
|
||||
workflow: "./galaxy/scripts/apps/workflow.js",
|
||||
masthead: "./galaxy/scripts/apps/masthead.js",
|
||||
viz: "./galaxy/scripts/apps/viz.js",
|
||||
library: "./galaxy/scripts/apps/library.js",
|
||||
adminToolshed: "./galaxy/scripts/apps/admin-toolshed.js"
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "../", "static/scripts/bundled"),
|
||||
filename: "[name].bundled.js"
|
||||
},
|
||||
resolve: {
|
||||
modules: [scriptsBase],
|
||||
modules: [scriptsBase, "node_modules"],
|
||||
alias: {
|
||||
//TODO: correct our imports and remove these rules
|
||||
// Backbone looks for these in the same root directory
|
||||
@@ -76,9 +82,16 @@ module.exports = {
|
||||
options: "$"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
}
|
||||
]
|
||||
},
|
||||
node: {
|
||||
setImmediate: false
|
||||
},
|
||||
resolveLoader: {
|
||||
alias: {
|
||||
// since we support both requirejs i18n and non-requirejs and both use a similar syntax,
|
||||
|
||||
+2644
-85
File diff suppressed because it is too large
Load Diff
@@ -146,6 +146,7 @@
|
||||
<datatype extension="toolshed.gz" type="galaxy.datatypes.binary:Binary" mimetype="multipart/x-gzip" subclass="true" />
|
||||
<datatype extension="h5" type="galaxy.datatypes.binary:H5" mimetype="application/octet-stream" display_in_upload="true"/>
|
||||
<datatype extension="mz5" type="galaxy.datatypes.binary:H5" subclass="true" mimetype="application/octet-stream" display_in_upload="true"/>
|
||||
<datatype extension="cool" type="galaxy.datatypes.binary:Cool" subclass="true" mimetype="application/octet-stream" display_in_upload="true"/>
|
||||
<datatype extension="html" type="galaxy.datatypes.text:Html" mimetype="text/html"/>
|
||||
<datatype extension="interval" type="galaxy.datatypes.interval:Interval" display_in_upload="true" description="File must start with definition line in the following format (columns may be in any order)." >
|
||||
<converter file="interval_to_bed_converter.xml" target_datatype="bed"/>
|
||||
@@ -677,6 +678,7 @@
|
||||
<sniffer type="galaxy.datatypes.binary:MzSQlite"/>
|
||||
<sniffer type="galaxy.datatypes.binary:IdpDB"/>
|
||||
<sniffer type="galaxy.datatypes.binary:SQlite"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Cool"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Biom2"/>
|
||||
<sniffer type="galaxy.datatypes.binary:H5"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Bam"/>
|
||||
|
||||
@@ -25,7 +25,6 @@ from galaxy.util import FILENAME_VALID_CHARS, nice_size, sqlite, which
|
||||
from galaxy.util.checkers import is_bz2, is_gzip
|
||||
from . import data, dataproviders
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# Currently these supported binary data types must be manually set on upload
|
||||
@@ -890,6 +889,60 @@ class Biom2(H5):
|
||||
return "Biom2 (HDF5) file (%s)" % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
class Cool(H5):
|
||||
"""
|
||||
Class describing the cool format (https://github.com/mirnylab/cooler)
|
||||
"""
|
||||
|
||||
file_ext = "cool"
|
||||
|
||||
def sniff(self, filename):
|
||||
"""
|
||||
>>> from galaxy.datatypes.sniff import get_test_fname
|
||||
>>> fname = get_test_fname( 'matrix.cool' )
|
||||
>>> Cool().sniff( fname )
|
||||
True
|
||||
>>> fname = get_test_fname( 'test.mz5' )
|
||||
>>> Cool().sniff( fname )
|
||||
False
|
||||
>>> fname = get_test_fname( 'wiggle.wig' )
|
||||
>>> Cool().sniff( fname )
|
||||
False
|
||||
>>> fname = get_test_fname( 'biom2_sparse_otu_table_hdf5.biom' )
|
||||
>>> Cool().sniff( fname )
|
||||
False
|
||||
"""
|
||||
|
||||
MAGIC = "HDF5::Cooler"
|
||||
URL = "https://github.com/mirnylab/cooler"
|
||||
|
||||
if super(Cool, self).sniff(filename):
|
||||
keys = ['chroms', 'bins', 'pixels', 'indexes']
|
||||
with h5py.File(filename, 'r') as handle:
|
||||
fmt = handle.attrs.get('format', None)
|
||||
url = handle.attrs.get('format-url', None)
|
||||
if fmt == MAGIC or url == URL:
|
||||
if not all(name in handle.keys() for name in keys):
|
||||
return False
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_peek(self, dataset, is_multi_byte=False):
|
||||
if not dataset.dataset.purged:
|
||||
dataset.peek = "Cool (HDF5) file for storing genomic interaction data."
|
||||
dataset.blurb = nice_size(dataset.get_size())
|
||||
else:
|
||||
dataset.peek = 'file does not exist'
|
||||
dataset.blurb = 'file purged from disk'
|
||||
|
||||
def display_peek(self, dataset):
|
||||
try:
|
||||
return dataset.peek
|
||||
except Exception:
|
||||
return "Cool (HDF5) file (%s)." % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
Binary.register_sniffable_binary_format("cool", "cool", Cool)
|
||||
Binary.register_sniffable_binary_format("biom2", "biom2", Biom2)
|
||||
Binary.register_sniffable_binary_format("h5", "h5", H5)
|
||||
|
||||
|
||||
Binary file not shown.
@@ -228,7 +228,7 @@ class ColumnSetAction(DefaultJobAction):
|
||||
for dataset_assoc in job.output_datasets:
|
||||
if action.output_name == '' or dataset_assoc.name == action.output_name:
|
||||
for k, v in action.action_arguments.items():
|
||||
if v != '':
|
||||
if v:
|
||||
# Try to use both pure integer and 'cX' format.
|
||||
if v[0] == 'c':
|
||||
v = v[1:]
|
||||
|
||||
@@ -8,6 +8,7 @@ from ...metrics import formatting
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
GALAXY_SLOTS_KEY = "galaxy_slots"
|
||||
GALAXY_MEMORY_MB_KEY = "galaxy_memory_mb"
|
||||
START_EPOCH_KEY = "start_epoch"
|
||||
END_EPOCH_KEY = "end_epoch"
|
||||
RUNTIME_SECONDS_KEY = "runtime_seconds"
|
||||
@@ -19,6 +20,8 @@ class CorePluginFormatter(formatting.JobMetricFormatter):
|
||||
value = int(value)
|
||||
if key == GALAXY_SLOTS_KEY:
|
||||
return ("Cores Allocated", "%d" % value)
|
||||
elif key == GALAXY_MEMORY_MB_KEY:
|
||||
return ("Memory Allocated (MB)", "%d" % value)
|
||||
elif key == RUNTIME_SECONDS_KEY:
|
||||
return ("Job Runtime (Wall Clock)", formatting.seconds_to_str(value))
|
||||
else:
|
||||
@@ -40,6 +43,7 @@ class CorePlugin(InstrumentPlugin):
|
||||
def pre_execute_instrument(self, job_directory):
|
||||
commands = []
|
||||
commands.append(self.__record_galaxy_slots_command(job_directory))
|
||||
commands.append(self.__record_galaxy_memory_mb_command(job_directory))
|
||||
commands.append(self.__record_seconds_since_epoch_to_file(job_directory, "start"))
|
||||
return commands
|
||||
|
||||
@@ -50,9 +54,11 @@ class CorePlugin(InstrumentPlugin):
|
||||
|
||||
def job_properties(self, job_id, job_directory):
|
||||
galaxy_slots_file = self.__galaxy_slots_file(job_directory)
|
||||
galaxy_memory_mb_file = self.__galaxy_memory_mb_file(job_directory)
|
||||
|
||||
properties = {}
|
||||
properties[GALAXY_SLOTS_KEY] = self.__read_integer(galaxy_slots_file)
|
||||
properties[GALAXY_MEMORY_MB_KEY] = self.__read_integer(galaxy_memory_mb_file)
|
||||
start = self.__read_seconds_since_epoch(job_directory, "start")
|
||||
end = self.__read_seconds_since_epoch(job_directory, "end")
|
||||
if start is not None and end is not None:
|
||||
@@ -65,6 +71,10 @@ class CorePlugin(InstrumentPlugin):
|
||||
galaxy_slots_file = self.__galaxy_slots_file(job_directory)
|
||||
return '''echo "$GALAXY_SLOTS" > '%s' ''' % galaxy_slots_file
|
||||
|
||||
def __record_galaxy_memory_mb_command(self, job_directory):
|
||||
galaxy_memory_mb_file = self.__galaxy_memory_mb_file(job_directory)
|
||||
return '''echo "$GALAXY_MEMORY_MB" > '%s' ''' % galaxy_memory_mb_file
|
||||
|
||||
def __record_seconds_since_epoch_to_file(self, job_directory, name):
|
||||
path = self._instrument_file_path(job_directory, "epoch_%s" % name)
|
||||
return 'date +"%s" > ' + path
|
||||
@@ -76,6 +86,9 @@ class CorePlugin(InstrumentPlugin):
|
||||
def __galaxy_slots_file(self, job_directory):
|
||||
return self._instrument_file_path(job_directory, "galaxy_slots")
|
||||
|
||||
def __galaxy_memory_mb_file(self, job_directory):
|
||||
return self._instrument_file_path(job_directory, "galaxy_memory_mb")
|
||||
|
||||
def __read_integer(self, path):
|
||||
value = None
|
||||
try:
|
||||
|
||||
@@ -187,14 +187,17 @@ class DatasetCollectionManager(object):
|
||||
changed = self._set_from_dict(trans, dataset_collection_instance, payload)
|
||||
return changed
|
||||
|
||||
def copy(self, trans, parent, source, encoded_source_id):
|
||||
def copy(self, trans, parent, source, encoded_source_id, copy_elements=False):
|
||||
"""
|
||||
PRECONDITION: security checks on ability to add to parent occurred
|
||||
during load.
|
||||
"""
|
||||
assert source == "hdca" # for now
|
||||
source_hdca = self.__get_history_collection_instance(trans, encoded_source_id)
|
||||
new_hdca = source_hdca.copy()
|
||||
copy_kwds = {}
|
||||
if copy_elements:
|
||||
copy_kwds["element_destination"] = parent
|
||||
new_hdca = source_hdca.copy(**copy_kwds)
|
||||
tags_str = self.tag_manager.get_tags_str(source_hdca.tags)
|
||||
self.tag_manager.apply_item_tags(trans.get_user(), new_hdca, tags_str)
|
||||
parent.add_dataset_collection(new_hdca)
|
||||
|
||||
@@ -90,6 +90,18 @@ class ConfigurationController(BaseAPIController):
|
||||
confs = self.app.toolbox.dynamic_confs(include_migrated_tool_conf=True)
|
||||
return map(_tool_conf_to_dict, confs)
|
||||
|
||||
@expose_api
|
||||
@require_admin
|
||||
def decode_id(self, trans, encoded_id, **kwds):
|
||||
"""Decode a given id."""
|
||||
decoded_id = None
|
||||
# Handle the special case for library folders
|
||||
if ((len(encoded_id) % 16 == 1) and encoded_id.startswith('F')):
|
||||
decoded_id = trans.security.decode_id(encoded_id[1:])
|
||||
else:
|
||||
decoded_id = trans.security.decode_id(encoded_id)
|
||||
return {"decoded_id": decoded_id}
|
||||
|
||||
@expose_api
|
||||
@require_admin
|
||||
def tool_lineages(self, trans):
|
||||
|
||||
@@ -252,6 +252,9 @@ class HistoryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
|
||||
copy from history dataset collection (for type 'dataset_collection')
|
||||
'source' = 'hdca'
|
||||
'content' = [the encoded id from the HDCA]
|
||||
'copy_elements' = Copy child HDAs into the target history as well,
|
||||
defaults to False but this is less than ideal and may
|
||||
be changed in future releases.
|
||||
|
||||
create new history dataset collection (for type 'dataset_collection')
|
||||
'source' = 'new_collection' (default 'source' if type is
|
||||
@@ -434,11 +437,13 @@ class HistoryContentsController(BaseAPIController, UsesLibraryMixin, UsesLibrary
|
||||
content = payload.get('content', None)
|
||||
if content is None:
|
||||
raise exceptions.RequestParameterMissingException("'content' id of target to copy is missing")
|
||||
copy_elements = payload.get('copy_elements', False)
|
||||
dataset_collection_instance = service.copy(
|
||||
trans=trans,
|
||||
parent=history,
|
||||
source="hdca",
|
||||
encoded_source_id=content,
|
||||
copy_elements=copy_elements,
|
||||
)
|
||||
else:
|
||||
message = "Invalid 'source' parameter in request %s" % source
|
||||
|
||||
@@ -105,7 +105,8 @@ def paste_app_factory(global_conf, **kwargs):
|
||||
webapp.add_client_route('/admin/repositories', 'admin')
|
||||
webapp.add_client_route('/admin/tool_versions', 'admin')
|
||||
webapp.add_client_route('/admin/quotas', 'admin')
|
||||
webapp.add_client_route('/admin/form/{form_id}', 'admin')
|
||||
webapp.add_client_route('/admin/forms/{form_id}', 'admin')
|
||||
webapp.add_client_route('/admin/api_keys', 'admin')
|
||||
webapp.add_client_route('/tours')
|
||||
webapp.add_client_route('/tours/{tour_id}')
|
||||
webapp.add_client_route('/user')
|
||||
@@ -117,6 +118,7 @@ def paste_app_factory(global_conf, **kwargs):
|
||||
webapp.add_client_route('/pages/list_published')
|
||||
webapp.add_client_route('/pages/create')
|
||||
webapp.add_client_route('/pages/edit')
|
||||
webapp.add_client_route('/histories/citations')
|
||||
webapp.add_client_route('/histories/list')
|
||||
webapp.add_client_route('/histories/list_published')
|
||||
webapp.add_client_route('/histories/list_shared')
|
||||
@@ -340,6 +342,10 @@ def populate_api_routes(webapp, app):
|
||||
"/api/whoami", controller='configuration',
|
||||
action='whoami',
|
||||
conditions=dict(method=["GET"]))
|
||||
webapp.mapper.connect("api_decode",
|
||||
"/api/configuration/decode/{encoded_id}", controller='configuration',
|
||||
action='decode_id',
|
||||
conditions=dict(method=["GET"]))
|
||||
webapp.mapper.resource('datatype',
|
||||
'datatypes',
|
||||
path_prefix='/api',
|
||||
|
||||
@@ -173,12 +173,13 @@ class AdminToolshed(AdminGalaxy):
|
||||
@web.require_admin
|
||||
def browse_toolsheds(self, trans, **kwd):
|
||||
app = {
|
||||
'jscript': "admin.toolshed"
|
||||
'jscript': "adminToolshedApp"
|
||||
}
|
||||
return trans.fill_template('galaxy.panels.mako',
|
||||
config={
|
||||
'title': 'Galaxy Tool Sheds',
|
||||
'app': app})
|
||||
'app': app,
|
||||
'bundle': 'adminToolshed'})
|
||||
|
||||
@web.expose
|
||||
@web.require_admin
|
||||
|
||||
@@ -457,14 +457,6 @@ class HistoryController(BaseUIController, SharableMixin, UsesAnnotations, UsesIt
|
||||
kwargs['dict_format'] = True
|
||||
return self.shared_list_grid(trans, status=status, message=message, **kwargs)
|
||||
|
||||
# ......................................................................... html
|
||||
@web.expose
|
||||
def citations(self, trans):
|
||||
# Get history
|
||||
history = trans.history
|
||||
history_id = trans.security.encode_id(history.id)
|
||||
return trans.fill_template("history/citations.mako", history=history, history_id=history_id)
|
||||
|
||||
@web.expose
|
||||
def as_xml(self, trans, id=None, show_deleted=None, show_hidden=None):
|
||||
"""
|
||||
|
||||
@@ -13,9 +13,10 @@ class Library(BaseUIController):
|
||||
def list(self, trans, **kwd):
|
||||
# define app configuration for generic mako template
|
||||
app = {
|
||||
'jscript' : "galaxy.library"
|
||||
'jscript' : "libraryApp"
|
||||
}
|
||||
return trans.fill_template('galaxy.panels.mako',
|
||||
config={
|
||||
'title': 'Data Libraries',
|
||||
'app': app})
|
||||
'app': app,
|
||||
'bundle': 'library'})
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
Contains the user interface in the Universe class
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from markupsafe import escape
|
||||
from sqlalchemy import false
|
||||
|
||||
from galaxy import (
|
||||
@@ -13,55 +10,35 @@ from galaxy import (
|
||||
)
|
||||
from galaxy.web.base.controller import BaseUIController, UsesFormDefinitionsMixin
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
require_login_template = """
|
||||
<p>
|
||||
This %s has been configured such that only users who are logged in may use it.%s
|
||||
</p>
|
||||
"""
|
||||
|
||||
# FIXME: This controller is using unencoded IDs, but I am not going to address
|
||||
# this now since it is admin-side and should be reimplemented in the API
|
||||
# anyway.
|
||||
|
||||
|
||||
class User(BaseUIController, UsesFormDefinitionsMixin):
|
||||
@web.expose
|
||||
@web.require_login()
|
||||
@web.require_admin
|
||||
def index(self, trans, cntrller, **kwd):
|
||||
return trans.fill_template('webapps/galaxy/user/list_users.mako', action='all_users', cntrller=cntrller)
|
||||
return self.get_all_users(trans)
|
||||
|
||||
@web.expose
|
||||
@web.require_login()
|
||||
@web.require_admin
|
||||
def admin_api_keys(self, trans, cntrller, uid, **kwd):
|
||||
def admin_api_keys(self, trans, uid, **kwd):
|
||||
params = util.Params(kwd)
|
||||
message = escape(util.restore_text(params.get('message', '')))
|
||||
status = params.get('status', 'done')
|
||||
uid = params.get('uid', uid)
|
||||
if params.get('new_api_key_button', False):
|
||||
new_key = trans.app.model.APIKeys()
|
||||
new_key.user_id = uid
|
||||
new_key.key = trans.app.security.get_new_guid()
|
||||
trans.sa_session.add(new_key)
|
||||
trans.sa_session.flush()
|
||||
message = "A new web API key has been generated for (%s)" % escape(new_key.user.email)
|
||||
status = "done"
|
||||
return trans.response.send_redirect(web.url_for(controller='userskeys',
|
||||
action='all_users',
|
||||
cntrller=cntrller,
|
||||
message=message,
|
||||
status=status))
|
||||
new_key = trans.app.model.APIKeys()
|
||||
new_key.user_id = trans.security.decode_id(uid)
|
||||
new_key.key = trans.app.security.get_new_guid()
|
||||
trans.sa_session.add(new_key)
|
||||
trans.sa_session.flush()
|
||||
return self.get_all_users(trans)
|
||||
|
||||
@web.expose
|
||||
@web.require_login()
|
||||
@web.require_admin
|
||||
def all_users(self, trans, cntrller="userskeys", **kwd):
|
||||
params = util.Params(kwd)
|
||||
message = escape(util.restore_text(params.get('message', '')))
|
||||
status = params.get('status', 'done')
|
||||
def all_users(self, trans, **kwd):
|
||||
return self.get_all_users(trans)
|
||||
|
||||
@web.json
|
||||
def get_all_users(self, trans):
|
||||
users = []
|
||||
for user in trans.sa_session.query(trans.app.model.User) \
|
||||
.filter(trans.app.model.User.table.c.deleted == false()) \
|
||||
@@ -71,9 +48,5 @@ class User(BaseUIController, UsesFormDefinitionsMixin):
|
||||
for api_user in trans.sa_session.query(trans.app.model.APIKeys) \
|
||||
.filter(trans.app.model.APIKeys.user_id == uid):
|
||||
userkey = api_user.key
|
||||
users.append({'uid': uid, 'email': user.email, 'key': userkey})
|
||||
return trans.fill_template('webapps/galaxy/user/list_users.mako',
|
||||
cntrller=cntrller,
|
||||
users=users,
|
||||
message=message,
|
||||
status=status)
|
||||
users.append({'uid': trans.security.encode_id(uid), 'email': user.email, 'key': userkey})
|
||||
return users
|
||||
|
||||
@@ -736,7 +736,7 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
"""
|
||||
|
||||
# define app configuration
|
||||
app = {'jscript' : "viz/trackster"}
|
||||
app = {"jscript" : "tracksterApp"}
|
||||
|
||||
# get dataset to add
|
||||
id = kwargs.get("id", None)
|
||||
@@ -780,7 +780,7 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
}
|
||||
|
||||
# fill template
|
||||
return trans.fill_template('galaxy.panels.mako', config={'right_panel': True, 'app': app})
|
||||
return trans.fill_template('galaxy.panels.mako', config={'right_panel': True, 'app': app, 'bundle': 'viz'})
|
||||
|
||||
@web.expose
|
||||
def circster(self, trans, id=None, hda_ldda=None, dataset_id=None, dbkey=None):
|
||||
@@ -836,13 +836,13 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
|
||||
# define app configuration for generic mako template
|
||||
app = {
|
||||
'jscript' : "viz/circster",
|
||||
'jscript' : "circsterApp",
|
||||
'viz_config' : viz_config,
|
||||
'genome' : genome
|
||||
}
|
||||
|
||||
# fill template
|
||||
return trans.fill_template('galaxy.panels.mako', config={'app' : app})
|
||||
return trans.fill_template('galaxy.panels.mako', config={'app' : app, 'bundle': 'viz'})
|
||||
|
||||
@web.expose
|
||||
def sweepster(self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None):
|
||||
|
||||
@@ -204,10 +204,10 @@ class WorkflowRequestMonitor(Monitors, object):
|
||||
sa_session = self.app.model.context
|
||||
workflow_invocation = sa_session.query(model.WorkflowInvocation).get(invocation_id)
|
||||
|
||||
if not workflow_invocation or not workflow_invocation.active:
|
||||
return False
|
||||
|
||||
try:
|
||||
if not workflow_invocation or not workflow_invocation.active:
|
||||
return False
|
||||
|
||||
# This ensures we're only ever working on the 'first' active
|
||||
# workflow invocation in a given history, to force sequential
|
||||
# activation.
|
||||
@@ -220,6 +220,8 @@ class WorkflowRequestMonitor(Monitors, object):
|
||||
# TODO: eventually fail this - or fail it right away?
|
||||
log.exception("Exception raised while attempting to schedule workflow request.")
|
||||
return False
|
||||
finally:
|
||||
sa_session.expunge_all()
|
||||
|
||||
# A workflow was obtained and scheduled...
|
||||
return True
|
||||
|
||||
+26
-66
@@ -19,13 +19,11 @@ cat <<EOF
|
||||
'${0##*/} -data_managers -id data_manager_id' for testing one Data Manager with id 'data_manager_id'
|
||||
'${0##*/} -unit' for running all unit tests (doctests and tests in test/unit)
|
||||
'${0##*/} -unit (test_path)' for running unit tests on specified test path
|
||||
'${0##*/} -qunit' for running qunit JavaScript tests
|
||||
'${0##*/} -qunit testname' for running single JavaScript test with given name
|
||||
'${0##*/} -selenium' for running all selenium web tests (in test/selenium_tests)
|
||||
'${0##*/} -selenium (test_path)' for running specified selenium web tests (use nosetest path)
|
||||
|
||||
This wrapper script largely serves as a point documentation and convenience -
|
||||
most tests shipped with Galaxy can be run with nosetests or qunit directly.
|
||||
most tests shipped with Galaxy can be run with nosetests directly.
|
||||
|
||||
The main test types are as follows:
|
||||
|
||||
@@ -42,7 +40,7 @@ The main test types are as follows:
|
||||
- Unit: These are Python unit tests either defined as doctests or inside of
|
||||
test/unit. These should generally not require a Galaxy instance and should
|
||||
quickly test just a component or a few components of Galaxy's backend code.
|
||||
- QUnit: These are JavaScript unit tests defined in test/qunit.
|
||||
- QUnit: These are JavaScript unit tests defined in client/galaxy/scripts/qunit.
|
||||
- Selenium: These are full stack tests meant to test the Galaxy UI with real
|
||||
browsers and are located in test/selenium_tests.
|
||||
- ToolShed: These are web tests that use the older Python web testing
|
||||
@@ -78,6 +76,13 @@ Run all selenium tests (Under Linux using Docker):
|
||||
Run a specific selenium test (under Linux or Mac OS X after installing geckodriver or chromedriver):
|
||||
./run_tests.sh -selenium test/selenium_tests/test_registration.py:RegistrationTestCase.test_reregister_username_fails
|
||||
|
||||
Run a selenium test against a running server while watching client (fastest iterating on client tests):
|
||||
./run.sh & # run Galaxy on 8080
|
||||
make client-watch & # watch for client changes
|
||||
export GALAXY_TEST_EXTERNAL=http://localhost:8080/ # Target tests at server.
|
||||
. .venv/bin/activate # source the virtualenv so can skip run_tests.sh.
|
||||
nosetests test/selenium_tests/test_workflow_editor.py:WorkflowEditorTestCase.test_data_input
|
||||
|
||||
Note About Selenium Tests:
|
||||
|
||||
If using a local selenium driver such as a Chrome or Firefox based one
|
||||
@@ -253,20 +258,6 @@ exists() {
|
||||
type "$1" >/dev/null 2>/dev/null
|
||||
}
|
||||
|
||||
ensure_grunt_for_qunit() {
|
||||
if ! exists "grunt";
|
||||
then
|
||||
PATH="$PATH:./test/qunit/node_modules/grunt/bin"
|
||||
export PATH
|
||||
if ! exists "grunt";
|
||||
then
|
||||
echo "Grunt not on path, cannot run these tests."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
DOCKER_DEFAULT_IMAGE='galaxy/testing-base:18.01.4'
|
||||
|
||||
test_script="./scripts/functional_tests.py"
|
||||
@@ -275,8 +266,6 @@ xunit_report_file=""
|
||||
structured_data_report_file=""
|
||||
with_framework_test_tools_arg=""
|
||||
|
||||
driver="python"
|
||||
|
||||
if [ "$1" = "--dockerize" ];
|
||||
then
|
||||
shift
|
||||
@@ -502,18 +491,6 @@ do
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
-q|-qunit|--qunit)
|
||||
# Requires grunt installed and dependencies configured see
|
||||
# test/qunit/README.txt for more information.
|
||||
driver="grunt"
|
||||
gruntfile="./test/qunit/Gruntfile.js"
|
||||
if [ $# -gt 1 ]; then
|
||||
qunit_name=$2
|
||||
shift 2
|
||||
else
|
||||
shift 1
|
||||
fi
|
||||
;;
|
||||
--no_cleanup)
|
||||
GALAXY_TEST_NO_CLEANUP=1
|
||||
export GALAXY_TEST_NO_CLEANUP
|
||||
@@ -624,39 +601,22 @@ else
|
||||
extra_args='--exclude="^get" functional'
|
||||
fi
|
||||
|
||||
if [ "$driver" = "python" ]; then
|
||||
if [ -n "$xunit_report_file" ]; then
|
||||
xunit_args="--with-xunit --xunit-file $xunit_report_file"
|
||||
else
|
||||
xunit_args=""
|
||||
fi
|
||||
if [ -n "$structured_data_report_file" ]; then
|
||||
structured_data_args="--with-structureddata --structured-data-file $structured_data_report_file"
|
||||
else
|
||||
structured_data_args=""
|
||||
fi
|
||||
if [ -n "$with_framework_test_tools_arg" ]; then
|
||||
GALAXY_TEST_TOOL_CONF="config/tool_conf.xml.sample,test/functional/tools/samples_tool_conf.xml"
|
||||
export GALAXY_TEST_TOOL_CONF
|
||||
fi
|
||||
python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $xunit_args $structured_data_args $extra_args
|
||||
exit_status=$?
|
||||
echo "Testing complete. HTML report is in \"$report_file\"." 1>&2
|
||||
exit ${exit_status}
|
||||
if [ -n "$xunit_report_file" ]; then
|
||||
xunit_args="--with-xunit --xunit-file $xunit_report_file"
|
||||
else
|
||||
ensure_grunt_for_qunit
|
||||
if [ -n "$watch" ]; then
|
||||
grunt_task="watch"
|
||||
else
|
||||
grunt_task=""
|
||||
fi
|
||||
if [ -n "$qunit_name" ]; then
|
||||
grunt_args="--test=$qunit_name"
|
||||
else
|
||||
grunt_args=""
|
||||
fi
|
||||
# TODO: Exapnd javascript helpers to include setting up
|
||||
# grunt deps in npm, "watch"ing directory, and running casper
|
||||
# functional tests.
|
||||
grunt --gruntfile=$gruntfile $grunt_task $grunt_args
|
||||
xunit_args=""
|
||||
fi
|
||||
if [ -n "$structured_data_report_file" ]; then
|
||||
structured_data_args="--with-structureddata --structured-data-file $structured_data_report_file"
|
||||
else
|
||||
structured_data_args=""
|
||||
fi
|
||||
if [ -n "$with_framework_test_tools_arg" ]; then
|
||||
GALAXY_TEST_TOOL_CONF="config/tool_conf.xml.sample,test/functional/tools/samples_tool_conf.xml"
|
||||
export GALAXY_TEST_TOOL_CONF
|
||||
fi
|
||||
python $test_script $coverage_arg -v --with-nosehtml --html-report-file $report_file $xunit_args $structured_data_args $extra_args
|
||||
exit_status=$?
|
||||
echo "Testing complete. HTML report is in \"$report_file\"." 1>&2
|
||||
exit ${exit_status}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"sources":["mvc/citation/citation-model.js"],"names":["parseBibtex","_","extend","ENTRY_TYPES_","online","data","Citation","Backbone","Model","_baseMvc2","default","LoggableMixin","_logNamespace","defaults","content","initialize","parsed","this","attributes","err","errors","length","reduce","all","current","log","entry","first","entries","logNamespace","Fields","key","rawFields","value","lowerKey","toLowerCase","_fields","entryType","EntryType","undefined","fields","BaseCitationCollection","Collection","urlRoot","Galaxy","root","partial","model","HistoryCitationCollection","url","history_id","ToolCitationCollection"],"mappings":"0OAAYA,yKAMZC,EAAEC,OAAOF,EAAYG,cACjBC,OAPQJ,IAQRK,KAAM,MAGV,IAMIC,EAAWC,SAASC,MAAMN,OAAOO,EAAAC,QAAQC,eAAeT,QACxDU,cAPe,WASfC,UACIC,QAAS,IAGbC,WAAY,WACR,IAAIC,EACJ,IAEIA,EAAShB,EAAYiB,KAAKC,WAAWJ,SACvC,MAAOK,GACL,OAGJ,GAAIH,EAAOI,OAAOC,OAAQ,CAEtB,IAAID,EAASJ,EAAOI,OAAOE,OAAO,SAACC,EAAKC,GAAN,OAAqBD,EAArB,KAA6BC,IAE/DP,KAAKQ,IAAL,yBAAkCL,GAKtC,GAlCJf,KAAAA,WAFJY,KAAAS,MAAAzB,EAAA0B,MAAAX,EAAAY,SAoCYX,KAAKS,MAAO,CA/BpBG,IAAAA,EAAeZ,KAAnBS,MAAAI,OACA,IAAA,IAAAC,KAAAC,EAAA,CACA,IAAAC,EAAAD,EAAAD,GAiCoBG,EAAWH,EAAII,cACnBlB,KAAKmB,QAAQF,GAAYD,KAIrCI,UAAW,WA/BXxB,OAAAA,KAAUa,MAAAT,KAAAS,MAAAY,eAAAC,GAAAC,OAHqD,WAsC3D,OAAOvB,KAAKmB,WAzBRK,EAAAlC,SAAAmC,WAAAxC,OAAAO,EAAAC,QAAAC,eAAAT,QACHU,cApBU,WAuBP+B,QAAAC,OAAAC,KAAA,MACAC,SAAA,EAAkCC,MAAAzC,IAElC0C,EAAAP,EAAkCrB,QAoC1C6B,IAAK,WAjCD,OAAKb,KAAAA,QAAL,cAAAnB,KAAAiC,WAAA,gBAIIC,EAAAV,EAA2BvC,QAEvB+C,IAAA,WACA,OAAAhC,KAAA0B,QAAA,UAAaT,KAAYD,QAAzB,cAEPa,SAAA,eAMDxC,SAAAA,EACH0C,0BAAAA,EAvC8DG,uBAAnEA","file":"../../../scripts/mvc/citation/citation-model.js","sourcesContent":["import * as parseBibtex from \"libs/bibtex\";\nimport baseMVC from \"mvc/base-mvc\";\nimport _l from \"utils/localization\";\n\n/* global Backbone */\n\n_.extend(parseBibtex.ENTRY_TYPES_, {\n online: 998, // Galaxy MOD: Handle @online entries for preprints.\n data: 999 // Galaxy MOD: Handle @data citations coming from figshare.\n});\n\nvar logNamespace = \"citation\";\n//==============================================================================\n/** @class model for tool citations.\n * @name Citation\n * @augments Backbone.Model\n */\nvar Citation = Backbone.Model.extend(baseMVC.LoggableMixin).extend({\n _logNamespace: logNamespace,\n\n defaults: {\n content: \"\"\n },\n\n initialize: function() {\n var parsed;\n try {\n // TODO: to model.parse/.validate\n parsed = parseBibtex(this.attributes.content);\n } catch (err) {\n return;\n }\n // bibtex returns successfully parsed in .entries and any parsing errors in .errors\n if (parsed.errors.length) {\n // the gen. form of these errors seems to be [ line, col, char, error message ]\n var errors = parsed.errors.reduce((all, current) => `${all}; ${current}`);\n // throw new Error( 'Error parsing bibtex: ' + errors );\n this.log(`Error parsing bibtex: ${errors}`);\n }\n\n this._fields = {};\n this.entry = _.first(parsed.entries);\n if (this.entry) {\n var rawFields = this.entry.Fields;\n for (var key in rawFields) {\n var value = rawFields[key];\n var lowerKey = key.toLowerCase();\n this._fields[lowerKey] = value;\n }\n }\n },\n entryType: function() {\n return this.entry ? this.entry.EntryType : undefined;\n },\n fields: function() {\n return this._fields;\n }\n});\n\n//==============================================================================\n/** @class Backbone collection of citations.\n */\nvar BaseCitationCollection = Backbone.Collection.extend(baseMVC.LoggableMixin).extend({\n _logNamespace: logNamespace,\n\n /** root api url */\n urlRoot: `${Galaxy.root}api`,\n partial: true, // Assume some tools in history/workflow may not be properly annotated yet.\n model: Citation\n});\n\nvar HistoryCitationCollection = BaseCitationCollection.extend({\n /** complete api url */\n url: function() {\n return `${this.urlRoot}/histories/${this.history_id}/citations`;\n }\n});\n\nvar ToolCitationCollection = BaseCitationCollection.extend({\n /** complete api url */\n url: function() {\n return `${this.urlRoot}/tools/${this.tool_id}/citations`;\n },\n partial: false // If a tool has citations, assume they are complete.\n});\n\n//==============================================================================\n\nexport default {\n Citation: Citation,\n HistoryCitationCollection: HistoryCitationCollection,\n ToolCitationCollection: ToolCitationCollection\n};\n"]}
|
||||
{"version":3,"sources":["mvc/citation/citation-model.js"],"names":["bibtexParse","Citation","Backbone","Model","extend","_baseMvc2","default","LoggableMixin","_logNamespace","defaults","content","initialize","parsed","toJSON","this","attributes","err","log","_fields","entry","_","first","rawFields","entryTags","key","value","lowerKey","toLowerCase","entryType","undefined","fields","Collection","partial","model","HistoryCitationCollection","BaseCitationCollection","url","ToolCitationCollection","urlRoot","tool_id"],"mappings":"qKAAYA,oNAWRC,EAAWC,SAASC,MAAMC,OAAOC,EAAAC,QAAQC,eAAeH,QACxDI,cAPe,WASfC,UACIC,QAAS,IAGbC,WAAY,WACR,IAAIC,EACJ,IAEIA,EAASZ,EAAYa,OAAOC,KAAKC,WAAWL,SAC9C,MAAOM,GACLF,KAAKG,IAAI,yBAA2BD,GAKxC,GAFAF,KAAKI,WACLJ,KAAKK,MAAQC,EAAEC,MAAMT,GACjBE,KAAKK,MAAO,CACZ,IAAIG,EAAYR,KAAKK,MAAMI,UAC3B,IAAK,IAAIC,KAAOF,EAAW,CACvB,IAAIG,EAAQH,EAAUE,GAClBE,EAAWF,EAAIG,cA9BnCb,KAAAI,QAAAQ,GAAAD,KAIAG,UAAA,WAgCQ,OAAOd,KAAKK,MAAQL,KAAKK,MAAMS,eAAYC,GAE/CC,OAAQ,WA9BR7B,OAAAA,KAAWC,WAOXS,EAAYT,SAAA6B,WAAW3B,OAAAC,EAAAC,QAAAC,eAAAH,QACnBI,cAdW,WAiBPI,QAAAA,OAAAA,KAAAA,MACHoB,SAHD,EAIIC,MAAAhC,IAGJiC,EAAAC,EAAA/B,QAEAgC,IAAA,WACI,OAAAtB,KAAIQ,QAAJ,cAA2BC,KAAAA,WAA3B,gBAIIc,EAAKnB,EAALd,QAEPgC,IAAA,WACJ,OA1B8DtB,KAAAwB,QA0B9D,UA1B8DxB,KAAAyB,QA0B9D,cAEGP,SAAA,eAqCJ/B,SAAUA,EA9BdiC,0BAAAA,EACAG,uBAAAA","file":"../../../scripts/mvc/citation/citation-model.js","sourcesContent":["import * as bibtexParse from \"libs/bibtexParse\";\nimport baseMVC from \"mvc/base-mvc\";\n\n/* global Backbone */\n\nvar logNamespace = \"citation\";\n//==============================================================================\n/** @class model for tool citations.\n * @name Citation\n * @augments Backbone.Model\n */\nvar Citation = Backbone.Model.extend(baseMVC.LoggableMixin).extend({\n _logNamespace: logNamespace,\n\n defaults: {\n content: \"\"\n },\n\n initialize: function() {\n var parsed;\n try {\n // TODO: to model.parse/.validate\n parsed = bibtexParse.toJSON(this.attributes.content);\n } catch (err) {\n this.log(\"Error parsing bibtex: \" + err);\n }\n\n this._fields = {};\n this.entry = _.first(parsed);\n if (this.entry) {\n var rawFields = this.entry.entryTags;\n for (var key in rawFields) {\n var value = rawFields[key];\n var lowerKey = key.toLowerCase();\n this._fields[lowerKey] = value;\n }\n }\n },\n entryType: function() {\n return this.entry ? this.entry.entryType : undefined;\n },\n fields: function() {\n return this._fields;\n }\n});\n\n//==============================================================================\n/** @class Backbone collection of citations.\n */\nvar BaseCitationCollection = Backbone.Collection.extend(baseMVC.LoggableMixin).extend({\n _logNamespace: logNamespace,\n\n /** root api url */\n urlRoot: `${Galaxy.root}api`,\n partial: true, // Assume some tools in history/workflow may not be properly annotated yet.\n model: Citation\n});\n\nvar HistoryCitationCollection = BaseCitationCollection.extend({\n /** complete api url */\n url: function() {\n return `${this.urlRoot}/histories/${this.history_id}/citations`;\n }\n});\n\nvar ToolCitationCollection = BaseCitationCollection.extend({\n /** complete api url */\n url: function() {\n return `${this.urlRoot}/tools/${this.tool_id}/citations`;\n },\n partial: false // If a tool has citations, assume they are complete.\n});\n\n//==============================================================================\n\nexport default {\n Citation: Citation,\n HistoryCitationCollection: HistoryCitationCollection,\n ToolCitationCollection: ToolCitationCollection\n};\n"]}
|
||||
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
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["mvc/user/user_api_keys.js"],"names":["mod_toastr","UserAPIKeysView","Backbone","View","extend","initialize","options","timeOut","this","setElement","render","self","url","Galaxy","root","$el","empty","append","_template","fetchUsers","$","getJSON","users","setTimeout","applyVue","_vue2","default","el","methods","generateKey","id","success","_data","error"],"mappings":"8MACYA,6JAERC,EAAkBC,SAASC,KAAKC,QAChCC,WAAY,WACRL,EAAWM,QAAQC,QAAU,IAC7BC,KAAKC,WAAW,UAChBD,KAAKE,UAGTA,OAAQ,WACJ,IAAIC,EAAOH,KACPI,EAAMC,OAAOC,KAAO,sBACxBH,EAAKI,IAAIC,QAAQC,OAAON,EAAKO,aAC7BP,EAAKQ,WAAWP,IAIpBO,WAAY,SAASP,GACjB,IAAID,EAAOH,KACXY,EAAEC,QAAQT,EAAK,SAASU,GAIpBC,WAAW,WACPZ,EAAKa,SAASF,QAM1BE,SAAU,SAASF,GACA,IAAAG,EAAAC,SACXC,GAAI,iBA9BZ1B,MACAI,MAAYiB,GAERM,SAHmCC,YAAA,SAAAC,GAqCvB,IAAInB,EAAOH,KA7BnBG,EAAAA,MACME,IAAOC,OAAOA,KAAA,2BACfE,MAAQC,IAAON,GACnBQ,QAAL,SAAAG,GAXmCtB,EAAA+B,QAAA,qCAcvCpB,EAAAqB,MAAAV,MAAAA,GAEeW,MAAX,WACejC,EAASsB,QAAO,4CAQlCJ,UAzBsC,WAyDnC,MA9BJ,0jBA2DCjB","file":"../../../scripts/mvc/user/user_api_keys.js","sourcesContent":["import Vue from \"libs/vue\";\nimport * as mod_toastr from \"libs/toastr\";\n\nvar UserAPIKeysView = Backbone.View.extend({\n initialize: function() {\n mod_toastr.options.timeOut = 1000;\n this.setElement(\"<div/>\");\n this.render();\n },\n\n render: function() {\n var self = this,\n url = Galaxy.root + \"userskeys/all_users\";\n self.$el.empty().append(self._template());\n self.fetchUsers(url);\n },\n\n /** Load users and their keys */\n fetchUsers: function(url) {\n var self = this;\n $.getJSON(url, function(users) {\n // apply vue model on the dom\n // timeout is used to ensure dom is created first and then\n // vue model is applied with the required data\n setTimeout(function() {\n self.applyVue(users);\n });\n });\n },\n\n /** Create model for the view using vue */\n applyVue: function(users) {\n var form_vue = new Vue({\n el: \"#form-userkeys\",\n data: {\n users: users // data model\n },\n methods: {\n // bind event from view\n generateKey: function(id) {\n var self = this;\n // fetch fresh model\n $.ajax({\n url: Galaxy.root + \"userskeys/admin_api_keys\",\n data: { uid: id },\n success: function(users) {\n mod_toastr.success(\"Successfully generated a user key\");\n // refresh the model\n self._data.users = users;\n },\n error: function() {\n mod_toastr.success(\"Error occured while loading data\");\n }\n });\n }\n }\n });\n },\n\n _template: function() {\n return (\n '<div id=\"form-userkeys\" class=\"toolForm\" v-cloak>' +\n '<div class=\"toolFormTitle\">User Information</div>' +\n '<div v-if=\"users && users.length > 0\">' +\n '<table class=\"grid\">' +\n \"<thead><th>Encoded UID</th><th>Email</th><th>API Key</th><th>Actions</th></thead>\" +\n \"<tbody>\" +\n '<tr v-for=\"user in users\">' +\n \"<td>\" +\n \"{{ user.uid }}\" +\n \"</td>\" +\n \"<td>\" +\n \"{{ user.email }}\" +\n \"</td>\" +\n \"<td>\" +\n \"{{ user.key }}\" +\n \"</td>\" +\n \"<td>\" +\n '<input type=\"button\" value=\"Generate a new key now\" v-on:click=\"generateKey( user.uid )\" />' +\n \"</td>\" +\n \"</tbody>\" +\n \"</table>\" +\n \"</div>\" +\n \"<div v-else>\" +\n \"<div>No informations available</div>\" +\n \"</div>\" +\n '<div style=\"clear: both\"></div>' +\n \"</div>\"\n );\n }\n});\n\nexport default UserAPIKeysView;\n"]}
|
||||
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
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
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
define("layout/panel",["exports","jquery","libs/underscore","libs/backbone"],function(e,t,i,n){"use strict";function a(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}Object.defineProperty(e,"__esModule",{value:!0});var s=function(e){return e&&e.__esModule?e:{default:e}}(t),d=a(i),l=a(n),o=160,r=800,h=l.View.extend({initialize:function(e){this.view=e.view,this.hidden=!1,this.saved_size=null,this.hiddenByTool=!1},$center:function(){return this.$el.siblings("#center")},$toggleButton:function(){return this.$(".unified-panel-footer > .panel-collapse")},render:function(){var e=this,t=this.view,i=this.view.model.attributes||{};this.$el.html(this._templatePanel(this.id)),d.each(i.buttons,function(t){e.$(".panel-header-buttons").append(t.$el)}),this.$el.addClass(i.cls),this.$(".panel-header-text").html(d.escape(i.title)),this.$(".unified-panel-body").append(t.$el),t.render()},_templatePanel:function(){return[this._templateHeader(),this._templateBody(),this._templateFooter()].join("")},_templateHeader:function(e){return['<div class="unified-panel-header" unselectable="on">','<div class="unified-panel-header-inner">','<div class="panel-header-buttons" style="float: right"/>','<div class="panel-header-text"/>',"</div>","</div>"].join("")},_templateBody:function(e){return'<div class="unified-panel-body"/>'},_templateFooter:function(e){return['<div class="unified-panel-footer">','<div class="panel-collapse ',d.escape(this.id),'"/>','<div class="drag"/>',"</div>"].join("")},events:{"mousedown .unified-panel-footer > .drag":"_mousedownDragHandler","click .unified-panel-footer > .panel-collapse":"toggle"},_mousedownDragHandler:function(e){function t(e){var t=e.pageX-a;a=e.pageX;var s=i.$el.width(),d=n?s+t:s-t;d=Math.min(r,Math.max(o,d)),i.resize(d)}var i=this,n="left"===this.id,a=e.pageX;(0,s.default)("#dd-helper").show().on("mousemove",t).one("mouseup",function(e){(0,s.default)(this).hide().off("mousemove",t)})},resize:function(e){return this.$el.css("width",e),this.$center().css(this.id,e),this},show:function(){if(this.hidden){var e=this,t={},i=this.id;return t[i]=0,e.$el.css(i,-this.saved_size).show().animate(t,"fast",function(){e.resize(e.saved_size)}),e.hidden=!1,e.$toggleButton().removeClass("hidden"),this}},hide:function(){if(!this.hidden){var e={},t=this.id;return this.saved_size=this.$el.width(),e[t]=-this.saved_size,this.$el.animate(e,"fast"),this.$center().css(t,0),this.hidden=!0,this.$toggleButton().addClass("hidden"),this}},toggle:function(e){return this.hidden?this.show():this.hide(),this.hiddenByTool=!1,this},handle_minwidth_hint:function(e){return this.$center().width()-(this.hidden?this.saved_size:0)<e?this.hidden||(this.toggle(),this.hiddenByTool=!0):this.hiddenByTool&&(this.toggle(),this.hiddenByTool=!1),self},force_panel:function(e){return"show"==e?this.show():"hide"==e?this.hide():self},toString:function(){return"SidePanel("+this.id+")"}}),u=h.extend({id:"left"}),c=h.extend({id:"right"}),f=l.View.extend({initialize:function(e){this.setElement((0,s.default)(this.template())),this.$frame=this.$(".center-frame"),this.$panel=this.$(".center-panel"),this.$frame.on("load",d.bind(this._iframeChangeHandler,this))},_iframeChangeHandler:function(e){var t=e.currentTarget,i=t.contentWindow&&t.contentWindow.location;i&&i.host&&((0,s.default)(t).show(),this.$panel.empty().hide(),Galaxy.trigger("center-frame:load",{fullpath:i.pathname+i.search+i.hash,pathname:i.pathname,search:i.search,hash:i.hash}))},display:function(e){var t=this.$frame[0].contentWindow||{},i=t.onbeforeunload&&t.onbeforeunload();i&&!confirm(i)||(t.onbeforeunload=void 0,this.$frame.attr("src","about:blank").hide(),this.$panel.empty().scrollTop(0).append(e.$el).show(),Galaxy.trigger("center-panel:load",e))},template:function(){return'<div class="center-container"><iframe id="galaxy_main" name="galaxy_main" frameborder="0" class="center-frame" /><div class="center-panel" /></div>'},toString:function(){return"CenterPanel"}});e.default={SidePanel:h,LeftPanel:u,RightPanel:c,CenterPanel:f}});
|
||||
define("layout/panel",["exports","jquery","libs/underscore","libs/backbone"],function(e,t,i,n){"use strict";function a(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}Object.defineProperty(e,"__esModule",{value:!0});var s=function(e){return e&&e.__esModule?e:{default:e}}(t),d=a(i),l=a(n),o=160,r=800,h=l.View.extend({initialize:function(e){this.view=e.view,this.hidden=!1,this.saved_size=null,this.hiddenByTool=!1},$center:function(){return this.$el.siblings("#center")},$toggleButton:function(){return this.$(".unified-panel-footer > .panel-collapse")},render:function(){var e=this,t=this.view,i=this.view.model.attributes||{};this.$el.html(this._templatePanel(this.id)),d.each(i.buttons,function(t){e.$(".panel-header-buttons").append(t.$el)}),this.$el.addClass(i.cls),this.$(".panel-header-text").html(d.escape(i.title)),this.$(".unified-panel-body").append(t.$el),t.render()},_templatePanel:function(){return[this._templateHeader(),this._templateBody(),this._templateFooter()].join("")},_templateHeader:function(e){return['<div class="unified-panel-header" unselectable="on">','<div class="unified-panel-header-inner">','<div class="panel-header-buttons" style="float: right"/>','<div class="panel-header-text"/>',"</div>","</div>"].join("")},_templateBody:function(e){return'<div class="unified-panel-body"/>'},_templateFooter:function(e){return['<div class="unified-panel-footer">','<div class="panel-collapse ',d.escape(this.id),'"/>','<div class="drag"/>',"</div>"].join("")},events:{"mousedown .unified-panel-footer > .drag":"_mousedownDragHandler","click .unified-panel-footer > .panel-collapse":"toggle"},_mousedownDragHandler:function(e){function t(e){var t=e.pageX-a;a=e.pageX;var s=i.$el.width(),d=n?s+t:s-t;d=Math.min(r,Math.max(o,d)),i.resize(d)}var i=this,n="left"===this.id,a=e.pageX;(0,s.default)("#dd-helper").show().on("mousemove",t).one("mouseup",function(e){(0,s.default)(this).hide().off("mousemove",t)})},resize:function(e){return this.$el.css("width",e),this.$center().css(this.id,e),this},show:function(){if(this.hidden){var e=this,t={},i=this.id;return t[i]=0,e.$el.css(i,-this.saved_size).show().animate(t,"fast",function(){e.resize(e.saved_size)}),e.hidden=!1,e.$toggleButton().removeClass("hidden"),this}},hide:function(){if(!this.hidden){var e={},t=this.id;return this.saved_size=this.$el.width(),e[t]=-this.saved_size,this.$el.animate(e,"fast"),this.$center().css(t,0),this.hidden=!0,this.$toggleButton().addClass("hidden"),this}},toggle:function(e){return this.hidden?this.show():this.hide(),this.hiddenByTool=!1,this},handle_minwidth_hint:function(e){return this.$center().width()-(this.hidden?this.saved_size:0)<e?this.hidden||(this.toggle(),this.hiddenByTool=!0):this.hiddenByTool&&(this.toggle(),this.hiddenByTool=!1),self},force_panel:function(e){return"show"==e?this.show():"hide"==e?this.hide():self},toString:function(){return"SidePanel("+this.id+")"}}),u=h.extend({id:"left"}),c=h.extend({id:"right"}),f=l.View.extend({initialize:function(e){this.setElement((0,s.default)(this.template())),this.$frame=this.$(".center-frame"),this.$panel=this.$(".center-panel"),this.$frame.on("load",d.bind(this._iframeChangeHandler,this))},_iframeChangeHandler:function(e){var t=e.currentTarget,i=t.contentWindow&&t.contentWindow.location;i&&i.host&&((0,s.default)(t).show(),this.$panel.empty().hide(),Galaxy.trigger("center-frame:load",{fullpath:i.pathname+i.search+i.hash,pathname:i.pathname,search:i.search,hash:i.hash}))},display:function(e){var t=this.$frame[0].contentWindow||{},i=t.onbeforeunload&&t.onbeforeunload();i&&!confirm(i)||(t.onbeforeunload=void 0,this.$frame.attr("src","about:blank").hide(),this.$panel.empty().scrollTop(0).append(e.$el||e).show(),Galaxy.trigger("center-panel:load",e))},template:function(){return'<div class="center-container"><iframe id="galaxy_main" name="galaxy_main" frameborder="0" class="center-frame" /><div class="center-panel" /></div>'},toString:function(){return"CenterPanel"}});e.default={SidePanel:h,LeftPanel:u,RightPanel:c,CenterPanel:f}});
|
||||
//# sourceMappingURL=../../maps/layout/panel.js.map
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user