mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge remote-tracking branch 'upstream/dev' into authnz
This commit is contained in:
@@ -32,6 +32,9 @@ export { default as HDAModel } from "mvc/history/hda-model";
|
||||
export { default as LegacyGridView } from "legacy/grid/grid-view";
|
||||
export { create_chart, create_histogram } from "reports/run_stats";
|
||||
export { default as ToolshedGroups } from "toolshed/toolshed.groups";
|
||||
export { default as IES } from "galaxy.interactive_environments";
|
||||
|
||||
export { Toast } from "ui/toast"; // TODO: remove when external consumers are updated/gone (IES right now)
|
||||
|
||||
export function adminToolshed(options) {
|
||||
new AdminToolshed.GalaxyApp(options);
|
||||
|
||||
@@ -153,11 +153,9 @@ describe("DataDialog.vue", () => {
|
||||
emitted = wrapper.emitted();
|
||||
expect(wrapper.classes()).contain("data-dialog-modal");
|
||||
expect(wrapper.find(".fa-spinner").text()).to.equals("");
|
||||
expect(wrapper.find(".btn-secondary").text()).to.equals("Clear");
|
||||
expect(wrapper.find(".btn-primary").text()).to.equals("Ok");
|
||||
expect(wrapper.contains(".fa-spinner")).to.equals(true);
|
||||
return Vue.nextTick().then(() => {
|
||||
expect(wrapper.findAll(".fa-copy").length).to.equals(2);
|
||||
expect(wrapper.findAll(".fa-folder").length).to.equals(2);
|
||||
expect(wrapper.findAll(".fa-file-o").length).to.equals(2);
|
||||
});
|
||||
});
|
||||
@@ -169,11 +167,9 @@ describe("DataDialog.vue", () => {
|
||||
emitted = wrapper.emitted();
|
||||
expect(wrapper.classes()).contain("data-dialog-modal");
|
||||
expect(wrapper.find(".fa-spinner").text()).to.equals("");
|
||||
expect(wrapper.find(".btn-secondary").text()).to.equals("Clear");
|
||||
expect(wrapper.find(".btn-primary").text()).to.equals("Ok");
|
||||
expect(wrapper.contains(".fa-spinner")).to.equals(true);
|
||||
return Vue.nextTick().then(() => {
|
||||
expect(wrapper.findAll(".fa-copy").length).to.equals(2);
|
||||
expect(wrapper.findAll(".fa-folder").length).to.equals(2);
|
||||
expect(wrapper.findAll(".fa-file-o").length).to.equals(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -20,7 +20,14 @@
|
||||
<div class="fa fa-caret-left mr-1" />
|
||||
Back
|
||||
</b-btn>
|
||||
<b-btn size="sm" class="float-right ml-1" variant="primary" @click="finalize" :disabled="!hasValue">
|
||||
<b-btn
|
||||
v-if="multiple"
|
||||
size="sm"
|
||||
class="float-right ml-1"
|
||||
variant="primary"
|
||||
@click="finalize"
|
||||
:disabled="!hasValue"
|
||||
>
|
||||
Ok
|
||||
</b-btn>
|
||||
<b-btn size="sm" class="float-right" @click="modalShow = false"> Cancel </b-btn>
|
||||
@@ -117,6 +124,8 @@ export default {
|
||||
} else {
|
||||
this.finalize();
|
||||
}
|
||||
} else {
|
||||
this.load(record.url);
|
||||
}
|
||||
},
|
||||
/** Called when selection is complete, values are formatted and parsed to external callback **/
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<b-input-group>
|
||||
<b-input v-model="filter" placeholder="Type to Search" />
|
||||
<b-input-group-append>
|
||||
<b-btn :disabled="!filter" @click="filter = ''">Clear</b-btn>
|
||||
<b-btn :disabled="!filter" @click="filter = ''"><i class="fa fa-times"/></b-btn>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</template>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
@filtered="filtered"
|
||||
>
|
||||
<template slot="label" slot-scope="data">
|
||||
<i v-if="data.item.isDataset" class="fa fa-file-o" /> <i v-else class="fa fa-copy" />
|
||||
<i v-if="data.item.isDataset" class="fa fa-file-o" /> <i v-else class="fa fa-folder" />
|
||||
{{ data.value ? data.value : "-" }}
|
||||
</template>
|
||||
<template slot="details" slot-scope="data">
|
||||
@@ -21,17 +21,6 @@
|
||||
<template slot="time" slot-scope="data">
|
||||
{{ data.value ? data.value : "-" }}
|
||||
</template>
|
||||
<template slot="arrow" slot-scope="data">
|
||||
<b-button
|
||||
variant="link"
|
||||
size="sm"
|
||||
class="py-0"
|
||||
v-if="!data.item.isDataset"
|
||||
@click.stop="load(data.item.url)"
|
||||
>
|
||||
View
|
||||
</b-button>
|
||||
</template>
|
||||
</b-table>
|
||||
<div v-if="nItems === 0">
|
||||
<div v-if="filter">
|
||||
@@ -77,11 +66,6 @@ export default {
|
||||
},
|
||||
time: {
|
||||
sortable: true
|
||||
},
|
||||
arrow: {
|
||||
label: "",
|
||||
sortable: false,
|
||||
class: "text-right"
|
||||
}
|
||||
},
|
||||
nItems: 0,
|
||||
@@ -105,10 +89,6 @@ export default {
|
||||
/** Collects selected datasets in value array **/
|
||||
clicked: function(record) {
|
||||
this.$emit("clicked", record);
|
||||
},
|
||||
/** Performs server request to retrieve data records **/
|
||||
load: function(url) {
|
||||
this.$emit("load", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<span id="item-url-text" style="display: none">
|
||||
{{ item_url_parts[0] }}<span id="item-identifier">{{ item_url_parts[1] }}</span>
|
||||
</span>
|
||||
<a href="#" id="edit-identifier"><img :src="pencil_url"/></a>
|
||||
<a href="javascript:void(0)" id="edit-identifier"><img :src="pencil_url" alt="Edit Share Url"/></a>
|
||||
</blockquote>
|
||||
<div v-if="item.published">
|
||||
<p>
|
||||
@@ -170,7 +170,8 @@ export default {
|
||||
return this.item.published ? "accessible via link and published" : "accessible via link";
|
||||
},
|
||||
item_url() {
|
||||
return `${window.location.protocol}//${window.location.hostname}:${window.location.port}${getAppRoot()}${
|
||||
const port = window.location.port ? `:${window.location.port}` : "";
|
||||
return `${window.location.protocol}//${window.location.hostname}${port}${getAppRoot()}${
|
||||
this.item.username_and_slug
|
||||
}`;
|
||||
},
|
||||
@@ -263,7 +264,7 @@ export default {
|
||||
.catch(error => (this.err_msg = error.response.data.err_msg));
|
||||
},
|
||||
createSlugHandler: function() {
|
||||
var on_start = function(text_elt) {
|
||||
const on_start = function(text_elt) {
|
||||
// Replace URL with URL text.
|
||||
$("#item-url").hide();
|
||||
$("#item-url-text").show();
|
||||
@@ -279,14 +280,14 @@ export default {
|
||||
);
|
||||
});
|
||||
};
|
||||
var on_finish = function(text_elt) {
|
||||
const on_finish = function(text_elt) {
|
||||
// Replace URL text with URL.
|
||||
$("#item-url-text").hide();
|
||||
$("#item-url").show();
|
||||
|
||||
// Set URL to new value.
|
||||
var new_url = $("#item-url-text").text();
|
||||
var item_url_obj = $("#item-url");
|
||||
const new_url = $("#item-url-text").text();
|
||||
const item_url_obj = $("#item-url");
|
||||
item_url_obj.attr("href", new_url);
|
||||
item_url_obj.text(new_url);
|
||||
};
|
||||
|
||||
@@ -43,8 +43,6 @@ const makoClickHandler = (options, vm) =>
|
||||
const { tagClickFn = "none", clickUrl } = options;
|
||||
|
||||
switch (tagClickFn) {
|
||||
// I made this match the existing behavior, but I am not clear on
|
||||
// the reason why this link redirects to a raw json page
|
||||
case "community_tag_click":
|
||||
if (undefined !== clickUrl) {
|
||||
const suffix = tag.value ? `:${tag.value}` : "";
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2 class="mb-3">
|
||||
<span id="jobs-title">Jobs</span>
|
||||
</h2>
|
||||
<b-alert v-if="this.message !== ''" :variant="galaxyKwdToBootstrap(status)" show>
|
||||
{{ message }}
|
||||
</b-alert>
|
||||
<b-alert variant="info" show>
|
||||
<p>
|
||||
Unfinished and recently finished jobs are displayed on this page. The 'cutoff' input box will do two
|
||||
things -- it will limit the display of unfinished jobs to only those jobs that have not had their job
|
||||
state updated recently, and it will limit the recently finished jobs list to only displaying jobs that
|
||||
have finished since the cutoff.
|
||||
</p>
|
||||
If any jobs are displayed, you may choose to stop them. Your stop message will be displayed to the user as:
|
||||
"This job was stopped by an administrator: <strong><YOUR MESSAGE></strong> For more information or
|
||||
help, report this error".
|
||||
</b-alert>
|
||||
<b-alert v-if="loading" variant="info" show>
|
||||
Waiting for data
|
||||
</b-alert>
|
||||
<div v-else>
|
||||
<b-container class="mb-3">
|
||||
<b-row>
|
||||
<b-col md="6">
|
||||
<b-form name="jobs" @submit.prevent="onRefresh">
|
||||
<b-form-group
|
||||
id="cutoff"
|
||||
label="Update Jobs"
|
||||
label-for="cutoff-seconds"
|
||||
description="Cutoff in seconds"
|
||||
>
|
||||
<b-input-group>
|
||||
<b-form-input id="cutoff" type="number" placeholder="180" v-model="cutoff">
|
||||
</b-form-input>
|
||||
<b-input-group-append>
|
||||
<b-btn type="submit">Refresh</b-btn>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
</b-form>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-form-group label="Administrative Job Lock" label-for="prevent-job-dispatching">
|
||||
<b-form-checkbox id="prevent-job-dispatching" v-model="jobLock" switch>
|
||||
Job dispatching is currently
|
||||
<strong>{{ jobLockDisplay ? "locked" : "unlocked" }}</strong>
|
||||
</b-form-checkbox>
|
||||
</b-form-group>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<b-row>
|
||||
<b-col md="6">
|
||||
<b-form-group
|
||||
label="Filter Jobs"
|
||||
label-for="filter-regex"
|
||||
description="Search for strings or regular expressions"
|
||||
>
|
||||
<b-input-group id="filter-regex">
|
||||
<b-form-input
|
||||
v-model="filter"
|
||||
placeholder="Type to Search"
|
||||
@keyup.esc.native="filter = ''"
|
||||
/>
|
||||
<b-input-group-append>
|
||||
<b-btn :disabled="!filter" @click="filter = ''">Clear (esc)</b-btn>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
<b-button :pressed.sync="showCommandLine" variant="outline-secondary">
|
||||
{{ showCommandLine ? "Hide" : "Show" }} Command Line
|
||||
</b-button>
|
||||
</b-col>
|
||||
<b-col>
|
||||
<b-card v-if="jobsItemsComputed.length" header="Stop Selected Jobs">
|
||||
<b-form @submit.prevent="onStopJobs">
|
||||
<b-form-group label-for="stop-message" description="will be displayed to the user">
|
||||
<b-input-group>
|
||||
<b-form-input
|
||||
id="stop-message"
|
||||
v-model="stopMessage"
|
||||
placeholder="Stop message"
|
||||
required
|
||||
>
|
||||
</b-form-input>
|
||||
<b-input-group-append>
|
||||
<b-btn type="submit">Submit</b-btn>
|
||||
</b-input-group-append>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
</b-form>
|
||||
</b-card>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
<b-alert v-if="!jobsItemsComputed.length" variant="secondary" show>
|
||||
There are no unfinished jobs to show with current cutoff time.
|
||||
</b-alert>
|
||||
<b-table
|
||||
v-else
|
||||
:fields="jobsFieldsComputed"
|
||||
:items="jobsItemsComputed"
|
||||
v-model="jobsItemsModel"
|
||||
:filter="filter"
|
||||
hover
|
||||
responsive
|
||||
striped
|
||||
caption-top
|
||||
@row-clicked="showRowDetails"
|
||||
:busy="busy"
|
||||
>
|
||||
<template slot="table-caption">
|
||||
Unfinished Jobs: These jobs are unfinished and have had their state updated in the previous
|
||||
{{ cutoffDisplay }} seconds.
|
||||
</template>
|
||||
<!-- Enable cell formatting for the command line column -->
|
||||
<span slot="html" slot-scope="data" v-html="data.value" />
|
||||
<template slot="HEAD_selected">
|
||||
<b-form-checkbox
|
||||
v-model="allSelected"
|
||||
:indeterminate="indeterminate"
|
||||
@change="toggleAll"
|
||||
></b-form-checkbox>
|
||||
</template>
|
||||
<template slot="selected" slot-scope="data">
|
||||
<b-form-checkbox
|
||||
v-model="selectedStopJobIds"
|
||||
:checked="allSelected"
|
||||
:key="data.index"
|
||||
:value="data.item['job_info']['id']"
|
||||
></b-form-checkbox>
|
||||
</template>
|
||||
<template slot="job_info" slot-scope="data">
|
||||
<b-link :href="data.value['info_url']" target="galaxy_main">
|
||||
{{ data.value["id"] }}
|
||||
</b-link>
|
||||
</template>
|
||||
<template slot="row-details" slot-scope="row">
|
||||
<b-card>
|
||||
<h5>Command Line</h5>
|
||||
<pre
|
||||
class="text-white bg-dark"
|
||||
><code class="break-word">{{ row.item.command_line }}</code></pre>
|
||||
</b-card>
|
||||
</template>
|
||||
</b-table>
|
||||
<b-alert v-if="!recentJobsItemsComputed.length" variant="secondary" show>
|
||||
There are no recently finished jobs to show with current cutoff time.
|
||||
</b-alert>
|
||||
<b-table
|
||||
v-else
|
||||
:fields="recentJobsFieldsComputed"
|
||||
:items="recentJobsItemsComputed"
|
||||
:filter="filter"
|
||||
hover
|
||||
responsive
|
||||
striped
|
||||
caption-top
|
||||
@row-clicked="showRowDetails"
|
||||
:busy="busy"
|
||||
>
|
||||
<template slot="table-caption">
|
||||
Recent Jobs: These jobs have completed in the previous {{ cutoffDisplay }} seconds.
|
||||
</template>
|
||||
<!-- Enable cell formatting for the command line column -->
|
||||
<span slot="html" slot-scope="data" v-html="data.value" />
|
||||
<template slot="job_info" slot-scope="data">
|
||||
<b-link :href="data.value['info_url']" target="galaxy_main">
|
||||
{{ data.value["id"] }}
|
||||
</b-link>
|
||||
</template>
|
||||
<template slot="row-details" slot-scope="row">
|
||||
<b-card>
|
||||
<h5>Command Line</h5>
|
||||
<pre
|
||||
class="text-white bg-dark"
|
||||
><code class="break-word">{{ row.item.command_line }}</code></pre>
|
||||
</b-card>
|
||||
</template>
|
||||
</b-table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
jobsItems: [],
|
||||
jobsItemsModel: [],
|
||||
recentJobsItems: [],
|
||||
jobsFields: [
|
||||
{ key: "job_info", label: "Job ID", sortable: true },
|
||||
{ key: "user" },
|
||||
{ key: "tool_id", label: "Tool", tdClass: ["break-word"] },
|
||||
{ key: "state" },
|
||||
{ key: "input_dataset", label: "Inputs" },
|
||||
{ key: "job_runner_name", label: "Job Runner" },
|
||||
{ key: "job_runner_external_id", label: "PID/Cluster ID", sortable: true }
|
||||
],
|
||||
showCommandLine: false,
|
||||
cutoff: 180,
|
||||
cutoffDisplay: 180,
|
||||
jobLock: false,
|
||||
jobLockDisplay: false,
|
||||
selectedStopJobIds: [],
|
||||
allSelected: false,
|
||||
indeterminate: false,
|
||||
stopMessage: "",
|
||||
filter: "",
|
||||
message: "",
|
||||
status: "",
|
||||
loading: true,
|
||||
busy: true
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
jobLock(newVal) {
|
||||
axios
|
||||
.get(`${getAppRoot()}admin/jobs_control?job_lock=${this.jobLock}`)
|
||||
.then(response => {
|
||||
this.jobLock = response.data.job_lock;
|
||||
this.jobLockDisplay = response.data.job_lock;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
},
|
||||
selectedStopJobIds(newVal) {
|
||||
if (newVal.length === 0) {
|
||||
this.indeterminate = false;
|
||||
this.allSelected = false;
|
||||
} else if (newVal.length === this.jobsItemsModel.length) {
|
||||
this.indeterminate = false;
|
||||
this.allSelected = true;
|
||||
} else {
|
||||
this.indeterminate = true;
|
||||
this.allSelected = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update() {
|
||||
this.busy = true;
|
||||
let params = [];
|
||||
params.push(`cutoff=${this.cutoff}`);
|
||||
params.push(`stop_msg=${this.stopMessage}`);
|
||||
params.push(`stop=${this.selectedStopJobIds.join()}`);
|
||||
params = params.join("&");
|
||||
axios
|
||||
.get(`${getAppRoot()}admin/jobs_list?${params}`)
|
||||
.then(response => {
|
||||
this.jobsItems = response.data.jobs;
|
||||
this.recentJobsItems = response.data.recent_jobs;
|
||||
this.cutoffDisplay = response.data.cutoff;
|
||||
this.message = response.data.message;
|
||||
this.status = response.data.status;
|
||||
this.jobLock = response.data.job_lock;
|
||||
this.jobLockDisplay = response.data.job_lock;
|
||||
this.loading = false;
|
||||
this.busy = false;
|
||||
})
|
||||
.catch(error => {
|
||||
this.message = error.response.data.err_msg;
|
||||
this.status = "error";
|
||||
console.log(error.response);
|
||||
});
|
||||
},
|
||||
onRefresh() {
|
||||
this.update();
|
||||
},
|
||||
onStopJobs() {
|
||||
this.update();
|
||||
this.selectedStopJobIds = [];
|
||||
this.stopMessage = "";
|
||||
},
|
||||
showRowDetails(row, index, e) {
|
||||
if (e.target.nodeName != "A") {
|
||||
row._showDetails = !row._showDetails;
|
||||
}
|
||||
},
|
||||
translateState(state) {
|
||||
const translateDict = {
|
||||
ok: "success",
|
||||
error: "danger",
|
||||
new: "primary",
|
||||
queued: "secondary",
|
||||
running: "info",
|
||||
upload: "dark"
|
||||
};
|
||||
return translateDict[state] || "primary";
|
||||
},
|
||||
computeItems(items) {
|
||||
return items.map(job => {
|
||||
return {
|
||||
...job,
|
||||
_showDetails: false,
|
||||
_cellVariants: { state: this.translateState(job.state) }
|
||||
};
|
||||
});
|
||||
},
|
||||
computeFields(fields) {
|
||||
const f = Array.from(fields).slice(0);
|
||||
if (this.showCommandLine) {
|
||||
f.splice(6, 0, {
|
||||
key: "command_line",
|
||||
tdClass: ["text-white", "bg-dark", "break-word"]
|
||||
});
|
||||
}
|
||||
return f;
|
||||
},
|
||||
toggleAll(checked) {
|
||||
this.selectedStopJobIds = checked
|
||||
? this.jobsItemsModel.reduce((acc, j) => [...acc, j["job_info"]["id"]], [])
|
||||
: [];
|
||||
},
|
||||
galaxyKwdToBootstrap(status) {
|
||||
let variant = "info";
|
||||
if (status !== "") {
|
||||
variant = status;
|
||||
}
|
||||
const galaxyKwdToBoostrapDict = {
|
||||
done: "success",
|
||||
info: "info",
|
||||
warning: "warning",
|
||||
error: "danger"
|
||||
};
|
||||
if (variant in galaxyKwdToBoostrapDict) {
|
||||
return galaxyKwdToBoostrapDict[variant];
|
||||
} else {
|
||||
return variant;
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
jobsItemsComputed() {
|
||||
return this.computeItems(this.jobsItems);
|
||||
},
|
||||
recentJobsItemsComputed() {
|
||||
return this.computeItems(this.recentJobsItems);
|
||||
},
|
||||
jobsFieldsComputed() {
|
||||
const f = this.jobsFields.slice(0);
|
||||
f.splice(0, 0, { key: "selected", label: "" });
|
||||
f.splice(2, 0, { key: "update_time", label: "Last Update", sortable: true });
|
||||
return this.computeFields(f);
|
||||
},
|
||||
recentJobsFieldsComputed() {
|
||||
const f = this.jobsFields.slice(0);
|
||||
f.splice(2, 0, { key: "update_time", label: "Finished", sortable: true });
|
||||
return this.computeFields(f);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.update();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Can not be scoped because of command line tdClass */
|
||||
.break-word {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
}
|
||||
</style>
|
||||
@@ -7,6 +7,7 @@ import QueryStringParsing from "utils/query-string-parsing";
|
||||
import Router from "layout/router";
|
||||
import DataTables from "components/admin/DataTables.vue";
|
||||
import DataTypes from "components/admin/DataTypes.vue";
|
||||
import Jobs from "components/admin/Jobs.vue";
|
||||
import DataManagerView from "components/admin/DataManager/DataManagerView.vue";
|
||||
import DataManagerRouter from "components/admin/DataManager/DataManagerRouter.vue";
|
||||
import Register from "components/login/Register.vue";
|
||||
@@ -33,6 +34,7 @@ export const getAdminRouter = (Galaxy, options) => {
|
||||
"(/)admin(/)form(/)(:form_id)": "show_form",
|
||||
"(/)admin/data_tables": "show_data_tables",
|
||||
"(/)admin/data_types": "show_data_types",
|
||||
"(/)admin/jobs": "show_jobs",
|
||||
"(/)admin/data_manager*path": "show_data_manager",
|
||||
"*notFound": "not_found"
|
||||
},
|
||||
@@ -115,6 +117,10 @@ export const getAdminRouter = (Galaxy, options) => {
|
||||
this._display_vue_helper(DataTypes);
|
||||
},
|
||||
|
||||
show_jobs: function() {
|
||||
this._display_vue_helper(Jobs);
|
||||
},
|
||||
|
||||
show_error_stack: function() {
|
||||
this._display_vue_helper(ErrorStack);
|
||||
},
|
||||
|
||||
@@ -39,6 +39,7 @@ var AdminPanel = Backbone.View.extend({
|
||||
{
|
||||
title: _l("Manage jobs"),
|
||||
url: "admin/jobs",
|
||||
target: "__use_router__",
|
||||
id: "admin-link-jobs"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* global $ */
|
||||
/* global toastr */
|
||||
// TODO: this file is transpiled and used directly without bundling; fix imports when that is no longer the case.
|
||||
import $ from "jquery";
|
||||
import { Toast } from "ui/toast";
|
||||
|
||||
/**
|
||||
* Internal function to remove content from the main area and add the notebook.
|
||||
* Not idempotent
|
||||
@@ -35,7 +35,7 @@ export function make_spin_state(
|
||||
sleep_step,
|
||||
log_attempts
|
||||
) {
|
||||
var s = {
|
||||
return {
|
||||
type: typeof type !== "undefined" ? type : "GIE spin",
|
||||
ajax_timeout: typeof ajax_timeout_init !== "undefined" ? ajax_timeout_init : 2000,
|
||||
ajax_timeout_max: typeof ajax_timeout_max !== "undefined" ? ajax_timeout_max : 16000,
|
||||
@@ -46,7 +46,6 @@ export function make_spin_state(
|
||||
log_attempts: typeof log_attempts !== "undefined" ? log_attempts : true,
|
||||
count: 0
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Log/display an error when spinning fails. */
|
||||
@@ -54,8 +53,8 @@ export function spin_error(console_msg, user_msg, clear) {
|
||||
console.log(console_msg);
|
||||
if (clear) clear_main_area();
|
||||
if (typeof user_msg == "string") {
|
||||
toastr.clear();
|
||||
toastr.error(user_msg, "Error", {
|
||||
Toast.clear();
|
||||
Toast.error(user_msg, "Error", {
|
||||
closeButton: true,
|
||||
timeOut: 0,
|
||||
extendedTimeOut: 0,
|
||||
@@ -112,7 +111,7 @@ export function spin(url, bool_response, success_callback, timeout_callback, err
|
||||
}
|
||||
}
|
||||
};
|
||||
if (bool_response) ajax_params["dataType"] = "json";
|
||||
if (bool_response) ajax_params.dataType = "json";
|
||||
$.ajax(ajax_params);
|
||||
};
|
||||
console.log(`Setting up new spinner for ${spin_state.type} on ${url}`);
|
||||
@@ -131,7 +130,7 @@ function spin_until(url, bool_response, messages, success_callback, spin_state)
|
||||
var message_once = (message, spin_state) => {
|
||||
if (spin_state.count == 1) {
|
||||
display_spinner();
|
||||
toastr.info(message, null, {
|
||||
Toast.info(message, null, {
|
||||
closeButton: true,
|
||||
timeOut: 0,
|
||||
extendedTimeOut: 0,
|
||||
@@ -141,22 +140,22 @@ function spin_until(url, bool_response, messages, success_callback, spin_state)
|
||||
};
|
||||
var wrapped_success = data => {
|
||||
if (!bool_response || (bool_response && data == true)) {
|
||||
console.log(messages["success"]);
|
||||
console.log(messages.success);
|
||||
clear_main_area();
|
||||
toastr.clear();
|
||||
Toast.clear();
|
||||
success_callback();
|
||||
} else if (bool_response && data == false) {
|
||||
message_once(messages["not_ready"], spin_state);
|
||||
message_once(messages.not_ready, spin_state);
|
||||
return false; // keep spinning
|
||||
} else {
|
||||
spin_error(`Invalid response to ${spin_state.type} request`, messages["invalid_response"], true);
|
||||
spin_error(`Invalid response to ${spin_state.type} request`, messages.invalid_response, true);
|
||||
}
|
||||
return true; // stop spinning
|
||||
};
|
||||
var timeout_error = (jqxhr, status, error) => {
|
||||
message_once(messages["waiting"], spin_state);
|
||||
message_once(messages.waiting, spin_state);
|
||||
if (spin_state.count == warn_at) {
|
||||
toastr.warning(messages["wait_warn"], "Warning", {
|
||||
Toast.warning(messages.wait_warn, "Warning", {
|
||||
closeButton: true,
|
||||
timeOut: 0,
|
||||
extendedTimeOut: 0,
|
||||
@@ -235,7 +234,7 @@ export function keepAlive(notebookAccessURL) {
|
||||
if (request_count > 30) {
|
||||
window.clearInterval(interval);
|
||||
clear_main_area();
|
||||
toastr.error("Could not connect to IE, contact your administrator", "Error", {
|
||||
Toast.error("Could not connect to IE, contact your administrator", "Error", {
|
||||
closeButton: true,
|
||||
timeOut: 20000,
|
||||
tapToDismiss: false
|
||||
@@ -245,3 +244,15 @@ export function keepAlive(notebookAccessURL) {
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
export default {
|
||||
append_notebook,
|
||||
clear_main_area,
|
||||
display_spinner,
|
||||
make_spin_state,
|
||||
spin_error,
|
||||
spin,
|
||||
test_ie_availability,
|
||||
load_when_ready,
|
||||
keepAlive
|
||||
};
|
||||
|
||||
@@ -442,7 +442,8 @@ export var HistoryContents = _super.extend(BASE_MVC.LoggableMixin).extend({
|
||||
data: JSON.stringify({
|
||||
content: id,
|
||||
source: contentType,
|
||||
type: type
|
||||
type: type,
|
||||
copy_elements: true
|
||||
})
|
||||
})
|
||||
.done(response => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -202,56 +202,58 @@ var FolderView = Backbone.View.extend({
|
||||
|
||||
templateFolderPermissions: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<div class="library_style_container">',
|
||||
"<div>",
|
||||
'<a href="#/folders/<%= folder.get("parent_id") %>">',
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Go back to the parent folder" class="btn btn-secondary primary-button" type="button">',
|
||||
'<span class="fa fa-caret-left fa-lg"/>',
|
||||
" Parent folder",
|
||||
"</button>",
|
||||
"</a>",
|
||||
"</div>",
|
||||
"<h1>",
|
||||
'Folder: <%= _.escape(folder.get("name")) %>',
|
||||
"</h1>",
|
||||
'<div class="alert alert-warning">',
|
||||
"<% if (is_admin) { %>",
|
||||
"You are logged in as an <strong>administrator</strong> therefore you can manage any folder on this Galaxy instance. Please make sure you understand the consequences.",
|
||||
"<% } else { %>",
|
||||
"You can assign any number of roles to any of the following permission types. However please read carefully the implications of such actions.",
|
||||
"<% }%>",
|
||||
"</div>",
|
||||
'<div class="dataset_table">',
|
||||
"<h2>Folder permissions</h2>",
|
||||
"<h4>",
|
||||
"Roles that can manage permissions on this folder",
|
||||
"</h4>",
|
||||
'<div id="manage_perm" class="manage_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can manage permissions on this folder.",
|
||||
"</div>",
|
||||
"<h4>",
|
||||
"Roles that can add items to this folder",
|
||||
"</h4>",
|
||||
'<div id="add_perm" class="add_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can add items to this folder (folders and datasets).",
|
||||
"</div>",
|
||||
"<h4>",
|
||||
"Roles that can modify this folder",
|
||||
"</h4>",
|
||||
'<div id="modify_perm" class="modify_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can modify this folder (name, etc.).",
|
||||
"</div>",
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Save modifications" class="btn btn-secondary toolbtn_save_permissions primary-button" type="button">',
|
||||
'<span class="fa fa-floppy-o"/>',
|
||||
" Save",
|
||||
"</button>",
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("")
|
||||
`<div class="library_style_container">
|
||||
<div>
|
||||
<a href="#/folders/<%= folder.get("parent_id") %>">
|
||||
<button data-toggle="tooltip" data-placement="top" title="Go back to the parent folder"
|
||||
class="btn btn-secondary primary-button" type="button">
|
||||
<span class="fa fa-caret-left fa-lg"/>
|
||||
Parent folder
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<h1>
|
||||
Folder: <%= _.escape(folder.get("name")) %>
|
||||
</h1>
|
||||
<div class="alert alert-warning">
|
||||
<% if (is_admin) { %>
|
||||
You are logged in as an <strong>administrator</strong> therefore you can manage any
|
||||
folder on this Galaxy instance. Please make sure you understand the consequences.
|
||||
<% } else { %>
|
||||
You can assign any number of roles to any of the following permission types.
|
||||
However please read carefully the implications of such actions.
|
||||
<% }%>
|
||||
</div>
|
||||
<div class="dataset_table">
|
||||
<h2>Folder permissions</h2>
|
||||
<h4>
|
||||
Roles that can manage permissions on this folder
|
||||
</h4>
|
||||
<div id="manage_perm" class="manage_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can manage permissions on this folder.
|
||||
</div>
|
||||
<h4>
|
||||
Roles that can add items to this folder
|
||||
</h4>
|
||||
<div id="add_perm" class="add_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can add items to this folder (folders and datasets).
|
||||
</div>
|
||||
<h4>
|
||||
Roles that can modify this folder
|
||||
</h4>
|
||||
<div id="modify_perm" class="modify_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can modify this folder (name, etc.).
|
||||
</div>
|
||||
<button data-toggle="tooltip" data-placement="top" title="Save modifications"
|
||||
class="btn btn-secondary toolbtn_save_permissions primary-button" type="button">
|
||||
<span class="fa fa-floppy-o"/>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -329,29 +329,11 @@ var FolderListView = Backbone.View.extend({
|
||||
},
|
||||
|
||||
makeDarkRow: function($row) {
|
||||
$row.removeClass("light").addClass("dark");
|
||||
$row.find("a")
|
||||
.removeClass("light")
|
||||
.addClass("dark");
|
||||
$row.find(".fa-file-o")
|
||||
.removeClass("fa-file-o")
|
||||
.addClass("fa-file");
|
||||
$row.find(".fa-folder-o")
|
||||
.removeClass("fa-folder-o")
|
||||
.addClass("fa-folder");
|
||||
$row.addClass("table-primary");
|
||||
},
|
||||
|
||||
makeWhiteRow: function($row) {
|
||||
$row.removeClass("dark").addClass("light");
|
||||
$row.find("a")
|
||||
.removeClass("dark")
|
||||
.addClass("light");
|
||||
$row.find(".fa-file")
|
||||
.removeClass("fa-file")
|
||||
.addClass("fa-file-o");
|
||||
$row.find(".fa-folder")
|
||||
.removeClass("fa-folder")
|
||||
.addClass("fa-folder-o");
|
||||
$row.removeClass("table-primary");
|
||||
},
|
||||
|
||||
renderSortIcon: function() {
|
||||
@@ -365,54 +347,186 @@ var FolderListView = Backbone.View.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the new folder inline
|
||||
*/
|
||||
createFolderInline: function() {
|
||||
if (this.$el.find("tr.new-row").length) {
|
||||
this.$el.find("tr.new-row textarea")[0].focus();
|
||||
} else {
|
||||
const template = this.templateNewFolder();
|
||||
this.$el.find("#first_folder_item").after(template);
|
||||
|
||||
this.$el.find("tr.new-row textarea")[0].focus();
|
||||
|
||||
this.$el.find("tr.new-row .save_folder_btn").click(() => {
|
||||
this.createNewFolder(
|
||||
this.$el.find("tr.new-row textarea")[0].value,
|
||||
this.$el.find("tr.new-row textarea")[1].value
|
||||
);
|
||||
});
|
||||
|
||||
this.$el.find("tr.new-row .cancel_folder_btn").click(() => {
|
||||
this.$el.find("tr.new-row").remove();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the new library using the API asynchronously.
|
||||
*/
|
||||
createNewFolder: function(name, description) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
const folderDetails = {
|
||||
name,
|
||||
description
|
||||
};
|
||||
if (folderDetails.name !== "") {
|
||||
var folder = new mod_library_model.FolderAsModel();
|
||||
var url_items = Backbone.history.fragment.split("/");
|
||||
var current_folder_id;
|
||||
if (url_items.indexOf("page") > -1) {
|
||||
current_folder_id = url_items[url_items.length - 3];
|
||||
} else {
|
||||
current_folder_id = url_items[url_items.length - 1];
|
||||
}
|
||||
folder.url = folder.urlRoot + current_folder_id;
|
||||
|
||||
folder.save(folderDetails, {
|
||||
success: folder => {
|
||||
Toast.success("Folder created.");
|
||||
folder.set({ type: "folder" });
|
||||
this.$el.find("tr.new-row").remove();
|
||||
Galaxy.libraries.folderListView.collection.add(folder);
|
||||
|
||||
$(`tr[data-id="${folder.attributes.id}"`)
|
||||
.addClass("table-success")
|
||||
.on("mouseover click", function() {
|
||||
$(this).removeClass("table-success");
|
||||
});
|
||||
},
|
||||
error: (model, response) => {
|
||||
Galaxy.modal.hide();
|
||||
if (typeof response.responseJSON !== "undefined") {
|
||||
Toast.error(response.responseJSON.err_msg);
|
||||
} else {
|
||||
Toast.error("An error occurred.");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Toast.error("Folder's name is missing.");
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
templateNewFolder: function() {
|
||||
return _.template(
|
||||
`<tr class="new-row">
|
||||
<td class="mid">
|
||||
<span title="Folder" class="fa fa-folder-o"></span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<textarea name="input_folder_name" rows="4" class="form-control input_folder_name" placeholder="name" ></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_folder_description" placeholder="description" ></textarea>
|
||||
</td>
|
||||
<td>folder</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td class="right-center">
|
||||
<button data-toggle="tooltip" data-placement="left" title="Save changes"
|
||||
class="btn btn-secondary btn-sm save_folder_btn" type="button">
|
||||
<span class="fa fa-floppy-o"></span> Save
|
||||
</button>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Discard changes"
|
||||
class="btn btn-secondary btn-sm cancel_folder_btn" type="button">
|
||||
<span class="fa fa-times"></span> Cancel
|
||||
</button>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
},
|
||||
|
||||
templateFolder: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<ol class="breadcrumb">',
|
||||
'<li class="breadcrumb-item"><a title="Return to the list of libraries" href="#">Libraries</a></li>',
|
||||
"<% _.each(path, function(path_item) { %>",
|
||||
"<% if (path_item[0] != id) { %>",
|
||||
'<li class="breadcrumb-item"><a title="Return to this folder" href="#/folders/<%- path_item[0] %>"><%- path_item[1] %></a> </li> ',
|
||||
"<% } else { %>",
|
||||
'<li class="breadcrumb-item active"><span title="You are in this folder"><%- path_item[1] %></span></li>',
|
||||
"<% } %>",
|
||||
"<% }); %>",
|
||||
"</ol>",
|
||||
`<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item">
|
||||
<a title="Return to the list of libraries" href="#">Libraries</a>
|
||||
</li>
|
||||
<% _.each(path, function(path_item) { %>
|
||||
<% if (path_item[0] != id) { %>
|
||||
<li class="breadcrumb-item">
|
||||
<a title="Return to this folder" href="#/folders/<%- path_item[0] %>">
|
||||
<%- path_item[1] %>
|
||||
</a>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li class="breadcrumb-item active">
|
||||
<span title="You are in this folder">
|
||||
<%- path_item[1] %>
|
||||
</span>
|
||||
</li>
|
||||
<% } %>
|
||||
<% }); %>
|
||||
</ol>
|
||||
|
||||
// FOLDER CONTENT
|
||||
'<table data-library-id="<%- parent_library_id %>" class="grid table table-sm">',
|
||||
"<thead>",
|
||||
'<th class="button_heading"></th>',
|
||||
'<th class="mid" style="width: 20px; " title="Check to select all datasets"><input id="select-all-checkboxes" style="margin: 0;" type="checkbox"></th>',
|
||||
'<th><a class="sort-folder-name" title="Click to reverse order" href="#">name</a> <span title="Sorted alphabetically" class="sort-icon-name fa fa-sort-alpha-<%- order %>"></span></th>',
|
||||
'<th style="width:20%;"><a class="sort-folder-description" title="Click to reverse order" href="#">description</a> <span title="Sorted alphabetically" class="sort-icon-description fa"></span></th>',
|
||||
'<th style="width:5%;"><a class="sort-folder-file_ext" title="Click to reverse order" href="#">data type</a> <span title="Sorted alphabetically" class="sort-icon-file_ext fa"></span></th>',
|
||||
'<th style="width:10%;">size</th>',
|
||||
'<th style="width:160px;">time updated (UTC)</th>',
|
||||
'<th style="width:5%;"><a class="sort-folder-state" title="Click to reverse order" href="#">state</a> <span title="Sorted alphabetically" class="sort-icon-state fa"></span></th>',
|
||||
'<th style="width:150px;"></th> ',
|
||||
"</thead>",
|
||||
'<tbody id="folder_list_body">',
|
||||
'<tr id="first_folder_item">',
|
||||
"<td>",
|
||||
'<a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>" title="Go to parent folder" class="btn_open_folder btn btn-secondary btn-sm">..<a>',
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"<td></td>",
|
||||
"</tr>",
|
||||
"</tbody>",
|
||||
"</table>",
|
||||
'<div class="empty-folder-message" style="display:none;">',
|
||||
"This folder is either empty or you do not have proper access permissions to see the contents. If you expected something to show up",
|
||||
' please consult the <a href="https://galaxyproject.org/data-libraries/#permissions" target="_blank">library security wikipage</a>.',
|
||||
"</div>"
|
||||
].join("")
|
||||
<!-- FOLDER CONTENT -->
|
||||
<table data-library-id="<%- parent_library_id %>" class="grid table table-hover table-sm">
|
||||
<thead>
|
||||
<th class="button_heading"></th>
|
||||
<th class="mid" style="width: 20px;"
|
||||
title="Check to select all datasets">
|
||||
<input id="select-all-checkboxes" style="margin: 0;" type="checkbox">
|
||||
</th>
|
||||
<th>
|
||||
<a class="sort-folder-name" title="Click to reverse order" href="#">Name</a>
|
||||
<span title="Sorted alphabetically"
|
||||
class="sort-icon-name fa fa-sort-alpha-<%- order %>"></span>
|
||||
</th>
|
||||
<th style="width:20%;">
|
||||
<a class="sort-folder-description" title="Click to reverse order" href="#">Description</a>
|
||||
<span title="Sorted alphabetically" class="sort-icon-description fa"></span>
|
||||
</th>
|
||||
<th style="width:5%;">
|
||||
<a class="sort-folder-file_ext" title="Click to reverse order" href="#">Data Type</a>
|
||||
<span title="Sorted alphabetically" class="sort-icon-file_ext fa"></span>
|
||||
</th>
|
||||
<th style="width:10%;">Size</th>
|
||||
<th style="width:160px;">Time Updated (UTC)</th>
|
||||
<th style="width:5%;">
|
||||
<a class="sort-folder-state" title="Click to reverse order" href="#">State</a>
|
||||
<span title="Sorted alphabetically" class="sort-icon-state fa"></span>
|
||||
</th>
|
||||
<th style="width:160px;"></th>
|
||||
</thead>
|
||||
<tbody id="folder_list_body">
|
||||
<tr id="first_folder_item">
|
||||
<td>
|
||||
<a href="#<% if (upper_folder_id !== 0){ print("folders/" + upper_folder_id)} %>"
|
||||
title="Go to parent folder" class="btn_open_folder btn btn-secondary btn-sm">..<a>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="empty-folder-message" style="display:none;">
|
||||
This folder is either empty or you do not have proper access permissions to see the contents.
|
||||
If you expected something to show up please consult the
|
||||
<a href="https://galaxyproject.org/data-libraries/#permissions" target="_blank">
|
||||
library security wikipage
|
||||
</a>.
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -241,169 +241,205 @@ var FolderRowView = Backbone.View.extend({
|
||||
|
||||
templateRowFolder: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<tr class="folder_row light library-row" data-id="<%- content_item.id %>">',
|
||||
'<td class="mid">',
|
||||
'<span title="Folder" class="fa fa-folder-o"/>',
|
||||
"</td>",
|
||||
'<td class="mid"><input style="margin: 0;" type="checkbox"></td>',
|
||||
"<% if(!edit_mode) { %>",
|
||||
"<td>",
|
||||
'<a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%- content_item.get("description") %>',
|
||||
"</td>",
|
||||
"<% } else if(edit_mode){ %>",
|
||||
'<td><textarea rows="4" class="form-control input_folder_name" placeholder="name" ><%- content_item.get("name") %></textarea></td>',
|
||||
'<td><textarea rows="4" class="form-control input_folder_description" placeholder="description" ><%- content_item.get("description") %></textarea></td>',
|
||||
"<% } %>",
|
||||
"<td>folder</td>",
|
||||
"<td></td>",
|
||||
"<td>",
|
||||
'<%= _.escape(content_item.get("update_time")) %>',
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
"<td>",
|
||||
"<% if(edit_mode) { %>", // start edit mode
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Save changes" class="primary-button btn-sm save_folder_btn" type="button" style="<% if(button_config.save_folder_btn === false) { print("display:none;") } %>">',
|
||||
'<span class="fa fa-floppy-o"/> Save',
|
||||
"</button>",
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Discard changes" class="primary-button btn-sm cancel_folder_btn" type="button" style="<% if(button_config.cancel_folder_btn === false) { print("display:none;") } %>">',
|
||||
'<span class="fa fa-times"/> Cancel',
|
||||
"</button>",
|
||||
"<% } else if (!edit_mode){%>", // start no edit mode
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Modify \'<%- content_item.get("name") %>\'" class="primary-button btn-sm edit_folder_btn" type="button" style="<% if(button_config.edit_folder_btn === false) { print("display:none;") } %>">',
|
||||
'<span class="fa fa-pencil"/> Edit',
|
||||
"</button>",
|
||||
'<a href="#/folders/<%- content_item.id %>/permissions">',
|
||||
'<button data-toggle="tooltip" data-placement="top" class="primary-button btn-sm permission_folder_btn" title="Permissions of \'<%- content_item.get("name") %>\'" style="<% if(button_config.permission_folder_btn === false) { print("display:none;") } %>">',
|
||||
'<span class="fa fa-group"/> Manage',
|
||||
"</button>",
|
||||
"</a>",
|
||||
"<% } %>", //end no edit mode
|
||||
"</td>",
|
||||
"</tr>"
|
||||
].join("")
|
||||
`<tr class="folder_row library-row" data-id="<%- content_item.id %>">
|
||||
<td class="mid">
|
||||
<span title="Folder" class="fa fa-folder-o"></span>
|
||||
</td>
|
||||
<td class="mid"><input style="margin: 0;" type="checkbox"></td>
|
||||
<% if(!edit_mode) { %>
|
||||
<td>
|
||||
<a href="#folders/<%- content_item.id %>"><%- content_item.get("name") %></a>
|
||||
</td>
|
||||
<% if( content_item.get("description") ) { %>
|
||||
<% if( content_item.get("description").length> 80 ) { %>
|
||||
<td data-toggle="tooltip" data-placement="auto"
|
||||
title='<%= _.escape(content_item.get("description")) %>'>
|
||||
<%= _.escape(content_item.get("description")).substring(0, 80) + "..." %>
|
||||
</td>
|
||||
<% } else { %>
|
||||
<td><%= _.escape(content_item.get("description"))%></td>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<td></td>
|
||||
<% } %>
|
||||
<% } else if(edit_mode){ %>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_folder_name" placeholder="name" ><%- content_item.get("name") %></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_folder_description" placeholder="description" ><%- content_item.get("description") %></textarea>
|
||||
</td>
|
||||
<% } %>
|
||||
<td>folder</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<%= _.escape(content_item.get("update_time")) %>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="right-center">
|
||||
<% if(edit_mode) { %> <!-- start edit mode -->
|
||||
<button data-toggle="tooltip" data-placement="top" title="Save changes"
|
||||
class="primary-button btn-sm save_folder_btn" type="button"
|
||||
style="<% if(button_config.save_folder_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-floppy-o"></span> Save
|
||||
</button>
|
||||
<button data-toggle="tooltip" data-placement="top" title="Discard changes"
|
||||
class="primary-button btn-sm cancel_folder_btn" type="button"
|
||||
style="<% if(button_config.cancel_folder_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-times"></span> Cancel
|
||||
</button>
|
||||
<% } else if (!edit_mode){%> <!-- start no edit mode -->
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
title="Modify '<%- content_item.get("name") %>'"
|
||||
class="primary-button btn-sm edit_folder_btn" type="button"
|
||||
style="<% if(button_config.edit_folder_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-pencil"></span> Edit
|
||||
</button>
|
||||
<a href="#/folders/<%- content_item.id %>/permissions">
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
class="primary-button btn-sm permission_folder_btn"
|
||||
title="Permissions of '<%- content_item.get("name") %>'"
|
||||
style="<% if(button_config.permission_folder_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-group"></span> Manage
|
||||
</button>
|
||||
</a>
|
||||
<% } %> <!-- end no edit mode -->
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
},
|
||||
|
||||
templateRowFile: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<tr class="dataset_row light library-row" data-id="<%- content_item.id %>">',
|
||||
'<td class="mid">',
|
||||
'<span title="Dataset" class="fa fa-file-o"/>',
|
||||
"</td>",
|
||||
'<td class="mid">',
|
||||
'<input style="margin: 0;" type="checkbox">',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>" class="library-dataset">',
|
||||
'<%- content_item.get("name") %>',
|
||||
"<a>",
|
||||
"</td>",
|
||||
'<td><%- content_item.get("message") %></td>',
|
||||
'<td><%= _.escape(content_item.get("file_ext")) %></td>',
|
||||
'<td><%= _.escape(content_item.get("file_size")) %></td>',
|
||||
'<td><%= _.escape(content_item.get("update_time")) %></td>',
|
||||
"<td>",
|
||||
'<% if ( content_item.get("state") !== "ok" ) { %>',
|
||||
'<%= _.escape(content_item.get("state")) %>',
|
||||
"<% } %>",
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<% if (content_item.get("is_unrestricted")) { %>',
|
||||
'<span data-toggle="tooltip" data-placement="top" title="Unrestricted dataset" style="color:grey;" class="fa fa-globe"/>',
|
||||
"<% } %>",
|
||||
'<% if (content_item.get("is_private")) { %>',
|
||||
'<span data-toggle="tooltip" data-placement="top" title="Private dataset" style="color:grey;" class="fa fa-key"/>',
|
||||
"<% } %>",
|
||||
'<% if ((content_item.get("is_unrestricted") === false) && (content_item.get("is_private") === false)) { %>',
|
||||
'<span data-toggle="tooltip" data-placement="top" title="Restricted dataset" style="color:grey;" class="fa fa-shield"/>',
|
||||
"<% } %>",
|
||||
'<% if (content_item.get("can_manage")) { %>',
|
||||
'<a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>/permissions">',
|
||||
'<button data-toggle="tooltip" data-placement="top" class="primary-button btn-sm permissions-dataset-btn" title="Permissions of \'<%- content_item.get("name") %>\'">',
|
||||
'<span class="fa fa-group"/> Manage',
|
||||
"</button>",
|
||||
"</a>",
|
||||
"<% } %>",
|
||||
"</td>",
|
||||
"</tr>"
|
||||
].join("")
|
||||
`<tr class="dataset_row library-row" data-id="<%- content_item.id %>">
|
||||
<td class="mid">
|
||||
<span title="Dataset" class="fa fa-file-o"></span>
|
||||
</td>
|
||||
<td class="mid">
|
||||
<input style="margin: 0;" type="checkbox">
|
||||
</td>
|
||||
<td>
|
||||
<a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>"
|
||||
class="library-dataset">
|
||||
<%- content_item.get("name") %>
|
||||
<a>
|
||||
</td>
|
||||
<td><%- content_item.get("message") %></td>
|
||||
<td><%= _.escape(content_item.get("file_ext")) %></td>
|
||||
<td><%= _.escape(content_item.get("file_size")) %></td>
|
||||
<td><%= _.escape(content_item.get("update_time")) %></td>
|
||||
<td>
|
||||
<% if ( content_item.get("state") !== "ok" ) { %>
|
||||
<%= _.escape(content_item.get("state")) %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td class="right-center">
|
||||
<% if (content_item.get("is_unrestricted")) { %>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Unrestricted dataset"
|
||||
class="fa fa-globe"></span>
|
||||
<% } %>
|
||||
<% if (content_item.get("is_private")) { %>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Private dataset"
|
||||
class="fa fa-key"></span>
|
||||
<% } %>
|
||||
<% if ((content_item.get("is_unrestricted") === false) && (content_item.get("is_private") === false)) { %>
|
||||
<span data-toggle="tooltip" data-placement="top" title="Restricted dataset"
|
||||
class="fa fa-shield"></span>
|
||||
<% } %>
|
||||
<% if (content_item.get("can_manage")) { %>
|
||||
<a href="#folders/<%- content_item.get("folder_id") %>/datasets/<%- content_item.id %>/permissions">
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
class="primary-button btn-sm permissions-dataset-btn"
|
||||
title="Permissions of '<%- content_item.get("name") %>'">
|
||||
<span class="fa fa-group"></span> Manage
|
||||
</button>
|
||||
</a>
|
||||
<% } %>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
},
|
||||
|
||||
templateRowDeletedFile: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<tr class="active deleted_dataset library-row" data-id="<%- content_item.id %>">',
|
||||
'<td class="mid">',
|
||||
'<span title="Dataset" class="fa fa-file-o"/>',
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
'<td style="color:grey;">',
|
||||
'<%- content_item.get("name") %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%- content_item.get("message") %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%= _.escape(content_item.get("file_ext")) %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%= _.escape(content_item.get("file_size")) %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%= _.escape(content_item.get("update_time")) %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<% if ( content_item.get("state") !== "ok" ) { %>',
|
||||
'<%= _.escape(content_item.get("state")) %>',
|
||||
"<% } %>",
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban"/>',
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Undelete \'<%- content_item.get("name") %>\'" class="primary-button btn-sm undelete_dataset_btn" type="button" style="margin-left:1em;">',
|
||||
'<span class="fa fa-unlock"/> Undelete',
|
||||
"</button>",
|
||||
"</td>",
|
||||
"</tr>"
|
||||
].join("")
|
||||
`<tr class="active deleted_dataset library-row" data-id="<%- content_item.id %>">
|
||||
<td class="mid">
|
||||
<span title="Dataset" class="fa fa-file-o"></span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td style="color:grey;">
|
||||
<%- content_item.get("name") %>
|
||||
</td>
|
||||
<td>
|
||||
<%- content_item.get("message") %>
|
||||
</td>
|
||||
<td>
|
||||
<%= _.escape(content_item.get("file_ext")) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= _.escape(content_item.get("file_size")) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= _.escape(content_item.get("update_time")) %>
|
||||
</td>
|
||||
<td>
|
||||
<% if ( content_item.get("state") !== "ok" ) { %>
|
||||
<%= _.escape(content_item.get("state")) %>
|
||||
<% } %>
|
||||
</td>
|
||||
<td class="right-center">
|
||||
<span data-toggle="tooltip" data-placement="top"
|
||||
title="Marked deleted" class="fa fa-ban"></span>
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
title="Undelete '<%- content_item.get("name") %>'"
|
||||
class="primary-button btn-sm undelete_dataset_btn" type="button" style="margin-left:1em;">
|
||||
<span class="fa fa-unlock"></span> Undelete
|
||||
</button>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
},
|
||||
|
||||
templateRowDeletedFolder: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<tr class="active deleted_folder light library-row" data-id="<%- content_item.id %>">',
|
||||
'<td class="mid">',
|
||||
'<span title="Folder" class="fa fa-folder-o"/>',
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
'<td style="color:grey;">',
|
||||
'<%- content_item.get("name") %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
'<%- content_item.get("description") %>',
|
||||
"</td>",
|
||||
"<td>",
|
||||
"folder",
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
"<td>",
|
||||
'<%= _.escape(content_item.get("update_time")) %>',
|
||||
"</td>",
|
||||
"<td></td>",
|
||||
"<td>",
|
||||
'<span data-toggle="tooltip" data-placement="top" title="Marked deleted" style="color:grey;" class="fa fa-ban"/>',
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Undelete \'<%- content_item.get("name") %>\'" class="primary-button btn-sm undelete_folder_btn" type="button" style="margin-left:1em;">',
|
||||
'<span class="fa fa-unlock"/> Undelete',
|
||||
"</button>",
|
||||
"</td>",
|
||||
"</tr>"
|
||||
].join("")
|
||||
`<tr class="active deleted_folder library-row" data-id="<%- content_item.id %>">
|
||||
<td class="mid">
|
||||
<span title="Folder" class="fa fa-folder-o"></span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td style="color:grey;">
|
||||
<%- content_item.get("name") %>
|
||||
</td>
|
||||
<% if( content_item.get("description") ) { %>
|
||||
<% if( content_item.get("description").length> 80 ) { %>
|
||||
<td data-toggle="tooltip" data-placement="bottom"
|
||||
title='<%= _.escape(content_item.get("description")) %>'>
|
||||
<%= _.escape(content_item.get("description")).substring(0, 80) + "..." %>
|
||||
</td>
|
||||
<% } else { %>
|
||||
<td><%= _.escape(content_item.get("description"))%></td>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<td></td>
|
||||
<% } %>
|
||||
<td>
|
||||
folder
|
||||
</td>
|
||||
<td></td>
|
||||
<td>
|
||||
<%= _.escape(content_item.get("update_time")) %>
|
||||
</td>
|
||||
<td></td>
|
||||
<td class="right-center">
|
||||
<span data-toggle="tooltip" data-placement="top"
|
||||
title="Marked deleted" class="fa fa-ban"></span>
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
title="Undelete '<%- content_item.get("name") %>'"
|
||||
class="primary-button btn-sm undelete_folder_btn" type="button" style="margin-left:1em;">
|
||||
<span class="fa fa-unlock"></span> Undelete
|
||||
</button>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -245,55 +245,58 @@ var LibraryView = Backbone.View.extend({
|
||||
|
||||
templateLibraryPermissions: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<div class="library_style_container">',
|
||||
"<div>",
|
||||
'<a href="#">',
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Go back to the list of Libraries" class="btn btn-secondary primary-button" type="button">',
|
||||
'<span class="fa fa-list"/>',
|
||||
" Libraries",
|
||||
"</button>",
|
||||
"</a>",
|
||||
"</div>",
|
||||
"<h1>",
|
||||
'Library: <%= _.escape(library.get("name")) %>',
|
||||
"</h1>",
|
||||
'<div class="alert alert-warning">',
|
||||
"<% if (is_admin) { %>",
|
||||
"You are logged in as an <strong>administrator</strong> therefore you can manage any library on this Galaxy instance. Please make sure you understand the consequences.",
|
||||
"<% } else { %>",
|
||||
"You can assign any number of roles to any of the following permission types. However please read carefully the implications of such actions.",
|
||||
"<% }%>",
|
||||
"</div>",
|
||||
'<div class="dataset_table">',
|
||||
"<h2>Library permissions</h2>",
|
||||
"<h4>Roles that can access the library</h4>",
|
||||
'<div id="access_perm" class="access_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can access this library. If there are no access roles set on the library it is considered <strong>unrestricted</strong>.",
|
||||
"</div>",
|
||||
"<h4>Roles that can manage permissions on this library</h4>",
|
||||
'<div id="manage_perm" class="manage_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can manage permissions on this library (includes giving access).",
|
||||
"</div>",
|
||||
"<h4>Roles that can add items to this library</h4>",
|
||||
'<div id="add_perm" class="add_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can add items to this library (folders and datasets).",
|
||||
"</div>",
|
||||
"<h4>Roles that can modify this library</h4>",
|
||||
'<div id="modify_perm" class="modify_perm roles-selection"/>',
|
||||
'<div class="alert alert-info roles-selection">',
|
||||
"User with <strong>any</strong> of these roles can modify this library (name, synopsis, etc.).",
|
||||
"</div>",
|
||||
'<button data-toggle="tooltip" data-placement="top" title="Save modifications made on this page" class="btn btn-secondary toolbtn_save_permissions primary-button" type="button">',
|
||||
'<span class="fa fa-floppy-o"/>',
|
||||
" Save",
|
||||
"</button>",
|
||||
"</div>",
|
||||
"</div>"
|
||||
].join("")
|
||||
`<div class="library_style_container">
|
||||
<div>
|
||||
<a href="#">
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
title="Go back to the list of Libraries" class="btn btn-secondary primary-button" type="button">
|
||||
<span class="fa fa-list"></span> Libraries
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
<h1>
|
||||
Library: <%= _.escape(library.get("name")) %>
|
||||
</h1>
|
||||
<div class="alert alert-warning">
|
||||
<% if (is_admin) { %>
|
||||
You are logged in as an <strong>administrator</strong> therefore you can manage any library
|
||||
on this Galaxy instance. Please make sure you understand the consequences.
|
||||
<% } else { %>
|
||||
You can assign any number of roles to any of the following permission types.
|
||||
However please read carefully the implications of such actions.
|
||||
<% }%>
|
||||
</div>
|
||||
<div class="dataset_table">
|
||||
<h2>Library permissions</h2>
|
||||
<h4>Roles that can access the library</h4>
|
||||
<div id="access_perm" class="access_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can access this library.
|
||||
If there are no access roles set on the library it is considered <strong>unrestricted</strong>.
|
||||
</div>
|
||||
<h4>Roles that can manage permissions on this library</h4>
|
||||
<div id="manage_perm" class="manage_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can manage permissions on this library
|
||||
(includes giving access).
|
||||
</div>
|
||||
<h4>Roles that can add items to this library</h4>
|
||||
<div id="add_perm" class="add_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can add items to this library (folders and datasets).
|
||||
</div>
|
||||
<h4>Roles that can modify this library</h4>
|
||||
<div id="modify_perm" class="modify_perm roles-selection"></div>
|
||||
<div class="alert alert-info roles-selection">
|
||||
User with <strong>any</strong> of these roles can modify this library (name, synopsis, etc.).
|
||||
</div>
|
||||
<button data-toggle="tooltip" data-placement="top"
|
||||
title="Save modifications made on this page"
|
||||
class="btn btn-secondary toolbtn_save_permissions primary-button" type="button">
|
||||
<span class="fa fa-floppy-o"></span> Save
|
||||
</button>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -224,45 +224,140 @@ var LibraryListView = Backbone.View.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the new library inline
|
||||
*/
|
||||
createLibraryInline: function() {
|
||||
if (this.$el.find("tr.new-row").length) {
|
||||
this.$el.find("tr.new-row textarea")[0].focus();
|
||||
} else {
|
||||
const template = this.templateNewRow();
|
||||
this.$el
|
||||
.find("#library_list_body")
|
||||
.closest("table")
|
||||
.show();
|
||||
this.$el.find("#library_list_body").prepend(template);
|
||||
|
||||
this.$el.find("tr.new-row textarea")[0].focus();
|
||||
|
||||
this.$el.find("tr.new-row .save_library_btn").click(() => {
|
||||
this.createNewLibrary(
|
||||
this.$el.find("tr.new-row textarea")[0].value,
|
||||
this.$el.find("tr.new-row textarea")[1].value,
|
||||
this.$el.find("tr.new-row textarea")[2].value
|
||||
);
|
||||
});
|
||||
|
||||
this.$el.find("tr.new-row .cancel_library_btn").click(() => {
|
||||
this.$el.find("tr.new-row").remove();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the new library using the API asynchronously.
|
||||
*/
|
||||
createNewLibrary: function(name, description, synopsis) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
const libraryDetails = {
|
||||
name,
|
||||
description,
|
||||
synopsis
|
||||
};
|
||||
if (libraryDetails.name !== "") {
|
||||
var library = new mod_library_model.Library();
|
||||
library.save(libraryDetails, {
|
||||
success: library => {
|
||||
Galaxy.libraries.libraryListView.collection.add(library);
|
||||
this.$el.find("tr.new-row").remove();
|
||||
Galaxy.libraries.libraryListView.render();
|
||||
|
||||
$(`tr[data-id="${library.attributes.id}"`)
|
||||
.addClass("table-success")
|
||||
.on("mouseover click", function() {
|
||||
$(this).removeClass("table-success");
|
||||
});
|
||||
|
||||
Toast.success("Library created.");
|
||||
},
|
||||
error: (model, response) => {
|
||||
if (typeof response.responseJSON !== "undefined") {
|
||||
Toast.error(response.responseJSON.err_msg);
|
||||
} else {
|
||||
Toast.error("An error occurred.");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Toast.error("Library's name is missing.");
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// MMMMMMMMMMMMMMMMMM
|
||||
// === TEMPLATES ====
|
||||
// MMMMMMMMMMMMMMMMMM
|
||||
|
||||
templateNewRow: function() {
|
||||
return _.template(
|
||||
`<tr class="new-row">
|
||||
<td>
|
||||
<textarea name="input_library_name" rows="4" class="form-control input_library_name" placeholder="name" ></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_library_description" placeholder="description"></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_library_synopsis" placeholder="synopsis"></textarea>
|
||||
</td>
|
||||
<td class="right-center">
|
||||
<button data-toggle="tooltip" data-placement="left" title="Save changes"
|
||||
class="btn btn-secondary btn-sm save_library_btn" type="button">
|
||||
<span class="fa fa-floppy-o"></span> Save
|
||||
</button>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Discard changes"
|
||||
class="btn btn-secondary btn-sm cancel_library_btn" type="button">
|
||||
<span class="fa fa-times"></span> Cancel
|
||||
</button>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
},
|
||||
|
||||
templateLibraryList: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<div class="library_container table-responsive">',
|
||||
"<% if(length === 0) { %>",
|
||||
"<% if(search_term.length > 0) { %>",
|
||||
"<div>",
|
||||
"There are no libraries matching your search. Try different keyword.",
|
||||
"</div>",
|
||||
"<% } else{ %>",
|
||||
"<div>",
|
||||
"There are no libraries visible to you here. If you expected some to show up please consult the",
|
||||
' <a href="https://galaxyproject.org/data-libraries/#permissions" target="_blank">library security wikipage</a>.',
|
||||
"</div>",
|
||||
"<% }%>",
|
||||
"<% } else{ %>",
|
||||
'<table class="grid table table-sm">',
|
||||
"<thead>",
|
||||
'<th style="width:30%;">',
|
||||
'<a class="sort-libraries-link" title="Click to reverse order" href="#">',
|
||||
"name",
|
||||
"</a>",
|
||||
'<span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"/>',
|
||||
"</th>",
|
||||
'<th style="width:22%;">description</th>',
|
||||
'<th style="width:22%;">synopsis</th> ',
|
||||
'<th style="width:26%;"></th>',
|
||||
"</thead>",
|
||||
'<tbody id="library_list_body">',
|
||||
// library item views will attach here
|
||||
"</tbody>",
|
||||
"</table>",
|
||||
"<% }%>",
|
||||
"</div>"
|
||||
].join("")
|
||||
`<div class="library_container table-responsive">
|
||||
<table class="grid table table-sm"
|
||||
<% if(length === 0) { %> style="display:none;" <% }%> >
|
||||
<thead>
|
||||
<th style="width:30%;">
|
||||
<a class="sort-libraries-link" title="Click to reverse order" href="#">
|
||||
Name
|
||||
</a>
|
||||
<span title="Sorted alphabetically" class="fa fa-sort-alpha-<%- order %>"></span>
|
||||
</th>
|
||||
<th style="width:22%;">Description</th>
|
||||
<th style="width:22%;">Synopsis</th>
|
||||
<th style="width:26%;"></th>
|
||||
</thead>
|
||||
<tbody id="library_list_body">
|
||||
<!-- library item views will attach here -->
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<% if(length === 0) { %>
|
||||
<% if(search_term.length > 0) { %>
|
||||
<div>
|
||||
There are no libraries matching your search. Try different keyword.
|
||||
</div>
|
||||
<% } else{ %>
|
||||
<div>
|
||||
There are no libraries visible to you here. If you expected some to show up please consult the
|
||||
<a href="https://galaxyproject.org/data-libraries/#permissions" target="_blank">library security wikipage</a>.
|
||||
</div>
|
||||
<% }%>
|
||||
<% }%>
|
||||
</div>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -232,52 +232,96 @@ var LibraryRowView = Backbone.View.extend({
|
||||
|
||||
templateRow: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<tr class="<% if(library.get("deleted") === true) { print("active") } %>" style="display:none;" data-id="<%- library.get("id") %>">',
|
||||
"<% if(!edit_mode) { %>",
|
||||
'<% if(library.get("deleted")) { %>',
|
||||
'<td style="color:grey;"><%- library.get("name") %></td>',
|
||||
"<% } else { %>",
|
||||
'<td><a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a></td>',
|
||||
"<% } %>",
|
||||
'<% if(library.get("description")) { %>',
|
||||
'<% if( (library.get("description")).length> 80 ) { %>',
|
||||
'<td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("description")) %>"><%= _.escape(library.get("description")).substring(0, 80) + "..." %></td>',
|
||||
"<% } else { %>",
|
||||
'<td><%= _.escape(library.get("description"))%></td>',
|
||||
"<% } %>",
|
||||
"<% } else { %>",
|
||||
"<td></td>",
|
||||
"<% } %>",
|
||||
'<% if(library.get("synopsis")) { %>',
|
||||
'<% if( (library.get("synopsis")).length> 120 ) { %>',
|
||||
'<td data-toggle="tooltip" data-placement="bottom" title="<%= _.escape(library.get("synopsis")) %>"><%= _.escape(library.get("synopsis")).substring(0, 120) + "..." %></td>',
|
||||
"<% } else { %>",
|
||||
'<td><%= _.escape(library.get("synopsis"))%></td>',
|
||||
"<% } %>",
|
||||
"<% } else { %>",
|
||||
"<td></td>",
|
||||
"<% } %>",
|
||||
"<% } else if(edit_mode){ %>",
|
||||
'<td><textarea rows="4" class="form-control input_library_name" placeholder="name" ><%- library.get("name") %></textarea></td>',
|
||||
'<td><textarea rows="4" class="form-control input_library_description" placeholder="description" ><%- library.get("description") %></textarea></td>',
|
||||
'<td><textarea rows="4" class="form-control input_library_synopsis" placeholder="synopsis" ><%- library.get("synopsis") %></textarea></td>',
|
||||
"<% } %>",
|
||||
'<td class="right-center">',
|
||||
'<% if( (library.get("public")) && (library.get("deleted") === false) ) { %>',
|
||||
'<span data-toggle="tooltip" data-placement="left" title="Unrestricted library" style="color:grey;" class="fa fa-globe fa-lg"> </span>',
|
||||
"<% }%>",
|
||||
'<button data-toggle="tooltip" data-placement="left" title="Modify \'<%- library.get("name") %>\'" class="btn btn-sm edit_library_btn" type="button" style="<% if(button_config.edit_library_btn === false) { print("display:none;") } %>"><span class="fa fa-pencil"></span> Edit</button>',
|
||||
'<a data-toggle="tooltip" data-placement="left" title="Permissions of \'<%- library.get("name") %>\'" href="#library/<%- library.get("id") %>/permissions"><button class="btn btn-sm permission_library_btn" type="button" style="<% if(button_config.permission_library_btn === false) { print("display:none;") } %>"><span class="fa fa-group"></span> Manage</button></a>',
|
||||
'<button data-toggle="tooltip" data-placement="left" title="Save changes" class="btn btn-sm save_library_btn" type="button" style="<% if(button_config.save_library_btn === false) { print("display:none;") } %>"><span class="fa fa-floppy-o"></span> Save</button>',
|
||||
'<button data-toggle="tooltip" data-placement="left" title="Discard changes" class="btn btn-sm cancel_library_btn" type="button" style="<% if(button_config.cancel_library_btn === false) { print("display:none;") } %>"><span class="fa fa-times"></span> Cancel</button>',
|
||||
'<button data-toggle="tooltip" data-placement="left" title="Delete \'<%- library.get("name") %>\'" class="btn btn-sm delete_library_btn" type="button" style="<% if(button_config.delete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-trash-o"></span> Delete</button>',
|
||||
// For deleted libraries
|
||||
'<span data-toggle="tooltip" data-placement="left" title="Marked deleted" style="color:grey; <% if(button_config.undelete_library_btn === false) { print("display:none;") } %>" class="fa fa-ban fa-lg"></span>',
|
||||
'<button data-toggle="tooltip" data-placement="left" title="Undelete \'<%- library.get("name") %>\' " class="btn btn-sm undelete_library_btn" type="button" style="<% if(button_config.undelete_library_btn === false) { print("display:none;") } %>"><span class="fa fa-unlock"></span> Undelete</button>',
|
||||
"</td>",
|
||||
"</tr>"
|
||||
].join("")
|
||||
`<tr class="<% if(library.get("deleted") === true) { print("active") } %>"
|
||||
style="display:none;" data-id="<%- library.get("id") %>">
|
||||
<% if(!edit_mode) { %>
|
||||
<% if(library.get("deleted")) { %>
|
||||
<td style="color:grey;"><%- library.get("name") %></td>
|
||||
<% } else { %>
|
||||
<td>
|
||||
<a href="#folders/<%- library.get("root_folder_id") %>"><%- library.get("name") %></a>
|
||||
</td>
|
||||
<% } %>
|
||||
<% if(library.get("description")) { %>
|
||||
<% if( (library.get("description")).length> 80 ) { %>
|
||||
<td data-toggle="tooltip" data-placement="bottom"
|
||||
title="<%= _.escape(library.get("description")) %>">
|
||||
<%= _.escape(library.get("description")).substring(0, 80) + "..." %>
|
||||
</td>
|
||||
<% } else { %>
|
||||
<td><%= _.escape(library.get("description"))%></td>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<td></td>
|
||||
<% } %>
|
||||
<% if(library.get("synopsis")) { %>
|
||||
<% if( (library.get("synopsis")).length> 120 ) { %>
|
||||
<td data-toggle="tooltip" data-placement="bottom"
|
||||
title="<%= _.escape(library.get("synopsis")) %>">
|
||||
<%= _.escape(library.get("synopsis")).substring(0, 120) + "..." %>
|
||||
</td>
|
||||
<% } else { %>
|
||||
<td><%= _.escape(library.get("synopsis"))%></td>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<td></td>
|
||||
<% } %>
|
||||
<% } else if(edit_mode){ %>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_library_name" placeholder="name" ><%- library.get("name") %></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_library_description" placeholder="description"><%- library.get("description") %></textarea>
|
||||
</td>
|
||||
<td>
|
||||
<textarea rows="4" class="form-control input_library_synopsis" placeholder="synopsis"><%- library.get("synopsis") %></textarea>
|
||||
</td>
|
||||
<% } %>
|
||||
<td class="right-center">
|
||||
<% if( (library.get("public")) && (library.get("deleted") === false) ) { %>
|
||||
<span data-toggle="tooltip" data-placement="left" title="Unrestricted library"
|
||||
class="fa fa-globe fa-lg"></span>
|
||||
<% }%>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Modify '<%- library.get("name") %>'"
|
||||
class="btn btn-secondary btn-sm edit_library_btn" type="button"
|
||||
style="<% if(button_config.edit_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-pencil"></span> Edit
|
||||
</button>
|
||||
<a data-toggle="tooltip" data-placement="left"
|
||||
title="Permissions of '<%- library.get("name") %>'"
|
||||
href="#library/<%- library.get("id") %>/permissions">
|
||||
<button class="btn btn-secondary btn-sm permission_library_btn" type="button"
|
||||
style="<% if(button_config.permission_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-group"></span> Manage
|
||||
</button>
|
||||
</a>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Save changes"
|
||||
class="btn btn-secondary btn-sm save_library_btn" type="button"
|
||||
style="<% if(button_config.save_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-floppy-o"></span> Save
|
||||
</button>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Discard changes"
|
||||
class="btn btn-secondary btn-sm cancel_library_btn" type="button"
|
||||
style="<% if(button_config.cancel_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-times"></span> Cancel
|
||||
</button>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Delete '<%- library.get("name") %>'"
|
||||
class="btn btn-secondary btn-sm delete_library_btn" type="button"
|
||||
style="<% if(button_config.delete_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-trash-o"></span> Delete
|
||||
</button>
|
||||
<!-- For deleted libraries -->
|
||||
<span data-toggle="tooltip" data-placement="left" title="Marked deleted"
|
||||
style="color:grey; <% if(button_config.undelete_library_btn === false) { print("display:none;") } %>"
|
||||
class="fa fa-ban fa-lg">
|
||||
</span>
|
||||
<button data-toggle="tooltip" data-placement="left" title="Undelete '<%- library.get("name") %>' "
|
||||
class="btn btn-secondary btn-sm undelete_library_btn" type="button"
|
||||
style="<% if(button_config.undelete_library_btn === false) { print("display:none;") } %>">
|
||||
<span class="fa fa-unlock"></span> Undelete
|
||||
</button>
|
||||
</td>
|
||||
</tr>`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import _ from "underscore";
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import _l from "utils/localization";
|
||||
import { Toast } from "ui/toast";
|
||||
import mod_library_model from "mvc/library/library-model";
|
||||
import { getGalaxyInstance } from "app";
|
||||
|
||||
/**
|
||||
@@ -18,10 +15,11 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
},
|
||||
|
||||
events: {
|
||||
"click #create_new_library_btn": "createLibraryFromModal",
|
||||
"click #create_new_library_btn": "createLibraryInline",
|
||||
"click #include_deleted_chk": "includeDeletedChecked",
|
||||
"click #exclude_restricted_chk": "excludeRestrictedChecked",
|
||||
"click .page_size_prompt": "showPageSizePrompt",
|
||||
"keydown .page_size": "changePageSize",
|
||||
"blur .page_size": "changePageSize",
|
||||
"keyup .library-search-input": "searchLibraries"
|
||||
},
|
||||
|
||||
@@ -39,7 +37,13 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
is_admin = Galaxy.user.isAdmin();
|
||||
is_anonym = Galaxy.user.isAnonymous();
|
||||
}
|
||||
this.$el.html(toolbar_template({ admin_user: is_admin, anon_user: is_anonym }));
|
||||
this.$el.html(
|
||||
toolbar_template({
|
||||
admin_user: is_admin,
|
||||
anon_user: is_anonym,
|
||||
library_page_size: Galaxy.libraries.preferences.get("library_page_size")
|
||||
})
|
||||
);
|
||||
if (is_admin) {
|
||||
this.$el.find("#include_deleted_chk")[0].checked = Galaxy.libraries.preferences.get("with_deleted");
|
||||
this.$el.find("#exclude_restricted_chk")[0].checked = Galaxy.libraries.preferences.get(
|
||||
@@ -55,7 +59,8 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
const Galaxy = getGalaxyInstance();
|
||||
this.options = _.extend(this.options, options);
|
||||
var paginator_template = this.templatePaginator();
|
||||
this.$el.find(".library-paginator").html(
|
||||
var paginator_text_template = this.templatePaginatorText();
|
||||
this.$el.find(".library-paginator > .paginator").html(
|
||||
paginator_template({
|
||||
show_page: parseInt(this.options.show_page),
|
||||
page_count: parseInt(this.options.page_count),
|
||||
@@ -64,109 +69,39 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
library_page_size: Galaxy.libraries.preferences.get("library_page_size")
|
||||
})
|
||||
);
|
||||
this.$el.find(".library-paginator > .paginator-text").html(
|
||||
paginator_text_template({
|
||||
show_page: parseInt(this.options.show_page),
|
||||
page_count: parseInt(this.options.page_count),
|
||||
total_libraries_count: this.options.total_libraries_count,
|
||||
libraries_shown: this.options.libraries_shown,
|
||||
library_page_size: Galaxy.libraries.preferences.get("library_page_size")
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* User clicked on 'New library' button. Show modal to
|
||||
* satisfy the wish.
|
||||
* Crreate the new library inline
|
||||
*/
|
||||
createLibraryFromModal: function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
createLibraryInline: function() {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
var self = this;
|
||||
this.modal = Galaxy.modal;
|
||||
this.modal.show({
|
||||
closing_events: true,
|
||||
title: _l("Create New Library"),
|
||||
body: this.templateNewLibraryInModal(),
|
||||
buttons: {
|
||||
Create: function() {
|
||||
self.createNewLibrary();
|
||||
},
|
||||
Close: function() {
|
||||
self.modal.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
Galaxy.libraries.libraryListView.createLibraryInline();
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the new library using the API asynchronously.
|
||||
* Change the number of libs shown on page.
|
||||
*/
|
||||
createNewLibrary: function() {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
var libraryDetails = this.serializeNewLibrary();
|
||||
if (this.validateNewLibrary(libraryDetails)) {
|
||||
var library = new mod_library_model.Library();
|
||||
var self = this;
|
||||
library.save(libraryDetails, {
|
||||
success: function(library) {
|
||||
Galaxy.libraries.libraryListView.collection.add(library);
|
||||
self.modal.hide();
|
||||
self.clearLibraryModal();
|
||||
Galaxy.libraries.libraryListView.render();
|
||||
Toast.success("Library created.");
|
||||
},
|
||||
error: function(model, response) {
|
||||
if (typeof response.responseJSON !== "undefined") {
|
||||
Toast.error(response.responseJSON.err_msg);
|
||||
} else {
|
||||
Toast.error("An error occurred.");
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
Toast.error("Library's name is missing.");
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Show user the propmpt to change the number of libs shown on page.
|
||||
*/
|
||||
showPageSizePrompt: function(e) {
|
||||
e.preventDefault();
|
||||
const Galaxy = getGalaxyInstance();
|
||||
var library_page_size = prompt(
|
||||
"How many libraries per page do you want to see?",
|
||||
Galaxy.libraries.preferences.get("library_page_size")
|
||||
);
|
||||
if (library_page_size != null && library_page_size == parseInt(library_page_size)) {
|
||||
changePageSize: function(e) {
|
||||
if (e.type === "focusout" || (e.type === "keydown" && e.keyCode === 13)) {
|
||||
e.preventDefault();
|
||||
const Galaxy = getGalaxyInstance();
|
||||
Galaxy.libraries.preferences.set({
|
||||
library_page_size: parseInt(library_page_size)
|
||||
library_page_size: parseInt(e.target.value)
|
||||
});
|
||||
Galaxy.libraries.libraryListView.render({ show_page: 1 });
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the library modal once it is saved.
|
||||
*/
|
||||
clearLibraryModal: function() {
|
||||
$("input[name='Name']").val("");
|
||||
$("input[name='Description']").val("");
|
||||
$("input[name='Synopsis']").val("");
|
||||
},
|
||||
|
||||
/**
|
||||
* Prepare new library variables to be submitted to API.
|
||||
*/
|
||||
serializeNewLibrary: function() {
|
||||
return {
|
||||
name: $("input[name='Name']").val(),
|
||||
description: $("input[name='Description']").val(),
|
||||
synopsis: $("input[name='Synopsis']").val()
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Check whether entered values are valid.
|
||||
*/
|
||||
validateNewLibrary: function(libraryDetails) {
|
||||
return libraryDetails.name !== "";
|
||||
},
|
||||
|
||||
/**
|
||||
* Include or exclude deleted libraries in the view.
|
||||
*/
|
||||
@@ -212,17 +147,14 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
<a class="btn btn-secondary mr-1" data-toggle="tooltip" data-placement="top" title="Go to first page" href="#">
|
||||
<span class="fa fa-home"/>
|
||||
</a>
|
||||
<a class="library-help-button btn btn-secondary mr-1" data-toggle="tooltip" title="See this screen annotated" href="https://galaxyproject.org/data-libraries/screen/list-of-libraries/" target="_blank">
|
||||
<span class="fa fa-question"/>
|
||||
</a>
|
||||
<% if(admin_user === true) { %>
|
||||
<button data-toggle="tooltip" data-placement="top" title="Create new library" id="create_new_library_btn" class="mr-1 btn btn-secondary" type="button">
|
||||
<span class="fa fa-plus"/>
|
||||
<span class="fa fa-plus" /> Library
|
||||
</button>
|
||||
<% } %>
|
||||
<div class="d-flex align-items-center library-paginator mr-1" />
|
||||
<div class="d-flex align-items-center mr-1" />
|
||||
<form class="form-inline mr-1">
|
||||
<input type="text" class="form-control library-search-input mr-1" placeholder="Great Library" size="15">
|
||||
<input type="text" id="library-filter" class="form-control library-search-input mr-1" placeholder="Search" size="15">
|
||||
<% if(admin_user === true) { %>
|
||||
<div class="form-check mr-1">
|
||||
<input class="form-check-input" id="include_deleted_chk" type="checkbox"/>
|
||||
@@ -236,6 +168,12 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
</form>
|
||||
</div>
|
||||
<div id="libraries_element" />
|
||||
|
||||
<div class="d-flex justify-content-center align-items-center library-paginator mt-2 mb-2">
|
||||
<ul class="pagination paginator mr-1" />
|
||||
<input style="width: initial;" min="0" max="999" class="page_size form-control" type="number" value="<%- library_page_size %>" />
|
||||
<span class="text-muted ml-1 paginator-text" />
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
);
|
||||
@@ -243,53 +181,76 @@ var LibraryToolbarView = Backbone.View.extend({
|
||||
|
||||
templatePaginator: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<ul class="pagination mr-1">',
|
||||
"<% if ( ( show_page - 1 ) > 0 ) { %>",
|
||||
"<% if ( ( show_page - 1 ) > page_count ) { %>", // we are on higher page than total page count
|
||||
'<li class="page-item"><a class="page-link" href="#page/1"><span class="fa fa-angle-double-left"></span></a></li>',
|
||||
'<li class="page-item disabled"><a class="page-link" href="#page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>',
|
||||
"<% } else { %>",
|
||||
'<li class="page-item"><a class="page-link" href="#page/1"><span class="fa fa-angle-double-left"></span></a></li>',
|
||||
'<li class="page-item"><a class="page-link" href="#page/<% print( show_page - 1 ) %>"><% print( show_page - 1 ) %></a></li>',
|
||||
"<% } %>",
|
||||
"<% } else { %>", // we are on the first page
|
||||
'<li class="page-item disabled"><a class="page-link" href="#page/1"><span class="fa fa-angle-double-left"></span></a></li>',
|
||||
'<li class="page-item disabled"><a class="page-link" href="#page/<% print( show_page ) %>"><% print( show_page - 1 ) %></a></li>',
|
||||
"<% } %>",
|
||||
'<li class="page-item active">',
|
||||
'<a class="page-link" href="#page/<% print( show_page ) %>"><% print( show_page ) %></a>',
|
||||
"</li>",
|
||||
"<% if ( ( show_page ) < page_count ) { %>",
|
||||
'<li class="page-item"><a class="page-link" href="#page/<% print( show_page + 1 ) %>"><% print( show_page + 1 ) %></a></li>',
|
||||
'<li class="page-item"><a class="page-link" href="#page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>',
|
||||
"<% } else { %>",
|
||||
'<li class="page-item disabled"><a class="page-link" href="#page/<% print( show_page ) %>"><% print( show_page + 1 ) %></a></li>',
|
||||
'<li class="page-item disabled"><a class="page-link" href="#page/<% print( page_count ) %>"><span class="fa fa-angle-double-right"></span></a></li>',
|
||||
"<% } %>",
|
||||
"</ul>",
|
||||
'<span class="mr-1">',
|
||||
' <%- libraries_shown %> libraries shown <a href="" data-toggle="tooltip" data-placement="top" title="currently <%- library_page_size %> per page" class="page_size_prompt">(change)</a>',
|
||||
"</span>",
|
||||
'<span class="mr-1">',
|
||||
" <%- total_libraries_count %> total",
|
||||
"</span>"
|
||||
].join("")
|
||||
`
|
||||
<% if ( ( show_page - 1 ) > 0 ) { %>
|
||||
<% if ( ( show_page - 1 ) > page_count ) { %> <!-- we are on higher page than total page count -->
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#page/1">
|
||||
<span class="fa fa-angle-double-left"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#page/<% print( show_page ) %>">
|
||||
<% print( show_page - 1 ) %>
|
||||
</a>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#page/1">
|
||||
<span class="fa fa-angle-double-left"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#page/<% print( show_page - 1 ) %>">
|
||||
<% print( show_page - 1 ) %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
<% } else { %> <!-- we are on the first page -->
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#page/1">
|
||||
<span class="fa fa-angle-double-left"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#page/<% print( show_page ) %>">
|
||||
<% print( show_page - 1 ) %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
<li class="page-item active">
|
||||
<a class="page-link" href="#page/<% print( show_page ) %>">
|
||||
<% print( show_page ) %>
|
||||
</a>
|
||||
</li>
|
||||
<% if ( ( show_page ) < page_count ) { %>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#page/<% print( show_page + 1 ) %>">
|
||||
<% print( show_page + 1 ) %>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#page/<% print( page_count ) %>">
|
||||
<span class="fa fa-angle-double-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
<% } else { %>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#page/<% print( show_page ) %>">
|
||||
<% print( show_page + 1 ) %>
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#page/<% print( page_count ) %>">
|
||||
<span class="fa fa-angle-double-right"></span>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
`
|
||||
);
|
||||
},
|
||||
|
||||
templateNewLibraryInModal: function() {
|
||||
return _.template(
|
||||
[
|
||||
'<div id="new_library_modal">',
|
||||
"<form>",
|
||||
'<input type="text" name="Name" value="" placeholder="Name" autofocus>',
|
||||
'<input type="text" name="Description" value="" placeholder="Description">',
|
||||
'<input type="text" name="Synopsis" value="" placeholder="Synopsis">',
|
||||
"</form>",
|
||||
"</div>"
|
||||
].join("")
|
||||
);
|
||||
templatePaginatorText: function() {
|
||||
return _.template(`per page, <%- total_libraries_count %> total`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -75,15 +75,9 @@ export default FormBase.extend({
|
||||
`<b>${options.name}</b> ${options.description} (Galaxy Version ${options.version})`,
|
||||
operations: !options.hide_operations && this._operations(),
|
||||
onchange: function() {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
self.deferred.reset();
|
||||
self.deferred.execute(process => {
|
||||
self.model.get("postchange")(process, self);
|
||||
if (self.model.get("listen_to_history")) {
|
||||
process.then(() => {
|
||||
self.stopListening(Galaxy.currHistoryPanel.collection);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -242,7 +242,10 @@ var View = Backbone.View.extend({
|
||||
toolId: job_def.tool_id
|
||||
});
|
||||
}
|
||||
Galaxy.currHistoryPanel && Galaxy.currHistoryPanel.refreshContents();
|
||||
if (Galaxy.currHistoryPanel) {
|
||||
self.form.stopListening(Galaxy.currHistoryPanel.collection);
|
||||
Galaxy.currHistoryPanel.refreshContents();
|
||||
}
|
||||
},
|
||||
error: function(response) {
|
||||
callback && callback();
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import $ from "jquery";
|
||||
import _ from "underscore";
|
||||
import Backbone from "backbone";
|
||||
var PopupMenu = Backbone.View.extend({
|
||||
const PopupMenu = Backbone.View.extend({
|
||||
//TODO: maybe better as singleton off the Galaxy obj
|
||||
/** Cache the desired button element and options, set up the button click handler
|
||||
* NOTE: attaches this view as HTML/jQ data on the button for later use.
|
||||
@@ -20,11 +20,10 @@ var PopupMenu = Backbone.View.extend({
|
||||
this.$button.data("popupmenu", this);
|
||||
|
||||
// set up button click -> open menu behavior
|
||||
var menu = this;
|
||||
this.$button.click(event => {
|
||||
// if there's already a menu open, remove it
|
||||
$(".popmenu-wrapper").remove();
|
||||
menu._renderAndShow(event);
|
||||
this._renderAndShow(event);
|
||||
return false;
|
||||
});
|
||||
},
|
||||
@@ -51,13 +50,12 @@ var PopupMenu = Backbone.View.extend({
|
||||
|
||||
// set up behavior on each link/anchor elem
|
||||
if (this.options.length) {
|
||||
var menu = this;
|
||||
this.$(".popupmenu-option").each(function(i) {
|
||||
var option = menu.options[i];
|
||||
this.$(".popupmenu-option").each((i, el) => {
|
||||
const option = this.options[i];
|
||||
// if the option has 'func', call that function when the anchor is clicked
|
||||
if (option.func) {
|
||||
$(this).click(event => {
|
||||
option.func.call(menu, event, option);
|
||||
$(el).click(event => {
|
||||
option.func.call(this, event, option);
|
||||
// We must preventDefault otherwise clicking "cancel"
|
||||
// on a purge or something still navigates and causes
|
||||
// the action.
|
||||
@@ -86,9 +84,9 @@ var PopupMenu = Backbone.View.extend({
|
||||
} else if (option.header) {
|
||||
return `<div class="popupmenu-option dropdown-header">${option.html}</div>`;
|
||||
}
|
||||
var href = option.href || "javascript:void(0);";
|
||||
var target = option.target ? `target="${option.target}"` : "";
|
||||
var check = option.checked ? '<span class="fa fa-check mr-1"/>' : "";
|
||||
const href = option.href || "javascript:void(0);";
|
||||
const target = option.target ? `target="${option.target}"` : "";
|
||||
const check = option.checked ? '<span class="fa fa-check mr-1"/>' : "";
|
||||
return `<a class="popupmenu-option dropdown-item" href="${href}" ${target}>${check}${option.html}</a>`;
|
||||
}).join("");
|
||||
},
|
||||
@@ -96,8 +94,8 @@ var PopupMenu = Backbone.View.extend({
|
||||
// get the absolute position/offset for the menu
|
||||
_getShownPosition: function(clickEvent) {
|
||||
// display menu horiz. centered on click...
|
||||
var menuWidth = this.$el.width();
|
||||
var x = clickEvent.pageX - menuWidth / 2;
|
||||
const menuWidth = this.$el.width();
|
||||
let x = clickEvent.pageX - menuWidth / 2;
|
||||
|
||||
// adjust to handle horiz. scroll and window dimensions ( draw entirely on visible screen area )
|
||||
x = Math.min(x, $(document).scrollLeft() + $(window).width() - menuWidth - 5);
|
||||
@@ -111,11 +109,14 @@ var PopupMenu = Backbone.View.extend({
|
||||
// bind an event handler to all available frames so that when anything is clicked
|
||||
// the menu is removed from the DOM and the event handler unbinds itself
|
||||
_setUpCloseBehavior: function() {
|
||||
var menu = this;
|
||||
//TODO: alternately: focus hack, blocking overlay, jquery.blockui
|
||||
|
||||
// function to close popup and unbind itself
|
||||
function closePopup(event) {
|
||||
const closePopup = event => {
|
||||
//do nothing if header item is clicked
|
||||
if (event.target.classList.contains("dropdown-header")) {
|
||||
return;
|
||||
}
|
||||
$(document).off("click.close_popup");
|
||||
try {
|
||||
if (window && window.parent !== window) {
|
||||
@@ -134,19 +135,19 @@ var PopupMenu = Backbone.View.extend({
|
||||
console.debug(err);
|
||||
}
|
||||
}
|
||||
menu.remove();
|
||||
}
|
||||
this.remove();
|
||||
};
|
||||
|
||||
$("html").one("click.close_popup", closePopup);
|
||||
$("html").on("click.close_popup", closePopup);
|
||||
try {
|
||||
if (window && window.parent !== window) {
|
||||
$(window.parent.document)
|
||||
.find("html")
|
||||
.one("click.close_popup", closePopup);
|
||||
.on("click.close_popup", closePopup);
|
||||
} else {
|
||||
$("iframe#galaxy_main")
|
||||
.contents()
|
||||
.one("click.close_popup", closePopup);
|
||||
.on("click.close_popup", closePopup);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof DOMException) {
|
||||
@@ -177,7 +178,7 @@ var PopupMenu = Backbone.View.extend({
|
||||
|
||||
// search for a menu option by its html
|
||||
findIndexByHtml: function(html) {
|
||||
for (var i = 0; i < this.options.length; i++) {
|
||||
for (let i = 0; i < this.options.length; i++) {
|
||||
if (_.has(this.options[i], "html") && this.options[i].html === html) {
|
||||
return i;
|
||||
}
|
||||
@@ -200,134 +201,5 @@ PopupMenu.create = function _create($button, options) {
|
||||
return new PopupMenu($button, options);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// the following class functions are bridges from the original make_popupmenu and make_popup_menus
|
||||
// to the newer backbone.js PopupMenu
|
||||
|
||||
/** Create a PopupMenu from simple map initial_options activated by clicking button_element.
|
||||
* Converts initial_options to object array used by PopupMenu.
|
||||
* @param {jQuery|DOMElement} button_element element which, when clicked, activates menu
|
||||
* @param {Object} initial_options map of key -> values, where
|
||||
* key is option text, value is fn to call when option is clicked
|
||||
* @returns {PopupMenu} the PopupMenu created
|
||||
*/
|
||||
PopupMenu.make_popupmenu = (button_element, initial_options) => {
|
||||
var convertedOptions = [];
|
||||
_.each(initial_options, (optionVal, optionKey) => {
|
||||
var newOption = { html: optionKey };
|
||||
|
||||
// keys with null values indicate: header
|
||||
if (optionVal === null) {
|
||||
// !optionVal? (null only?)
|
||||
newOption.header = true;
|
||||
|
||||
// keys with function values indicate: a menu option
|
||||
} else if ($.type(optionVal) === "function") {
|
||||
newOption.func = optionVal;
|
||||
}
|
||||
//TODO:?? any other special optionVals?
|
||||
// there was no divider option originally
|
||||
convertedOptions.push(newOption);
|
||||
});
|
||||
return new PopupMenu($(button_element), convertedOptions);
|
||||
};
|
||||
|
||||
/** Find all anchors in $parent (using selector) and covert anchors into a PopupMenu options map.
|
||||
* @param {jQuery} $parent the element that contains the links to convert to options
|
||||
* @param {String} selector jq selector string to find links
|
||||
* @returns {Object[]} the options array to initialize a PopupMenu
|
||||
*/
|
||||
//TODO: lose parent and selector, pass in array of links, use map to return options
|
||||
PopupMenu.convertLinksToOptions = ($parent, selector) => {
|
||||
$parent = $($parent);
|
||||
selector = selector || "a";
|
||||
var options = [];
|
||||
$parent.find(selector).each((elem, i) => {
|
||||
var option = {};
|
||||
var $link = $(elem);
|
||||
|
||||
// convert link text to the option text (html) and the href into the option func
|
||||
option.html = $link.text();
|
||||
if ($link.attr("href")) {
|
||||
var linkHref = $link.attr("href");
|
||||
var linkTarget = $link.attr("target");
|
||||
var confirmText = $link.attr("confirm");
|
||||
|
||||
option.func = () => {
|
||||
// if there's a "confirm" attribute, throw up a confirmation dialog, and
|
||||
// if the user cancels - do nothing
|
||||
if (confirmText && !confirm(confirmText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if there's no confirm attribute, or the user accepted the confirm dialog:
|
||||
switch (linkTarget) {
|
||||
// relocate the center panel
|
||||
case "_parent":
|
||||
window.parent.location = linkHref;
|
||||
break;
|
||||
|
||||
// relocate the entire window
|
||||
case "_top":
|
||||
window.top.location = linkHref;
|
||||
break;
|
||||
|
||||
// relocate this panel
|
||||
default:
|
||||
window.location = linkHref;
|
||||
}
|
||||
};
|
||||
}
|
||||
options.push(option);
|
||||
});
|
||||
return options;
|
||||
};
|
||||
|
||||
/** Create a single popupmenu from existing DOM button and anchor elements
|
||||
* @param {jQuery} $buttonElement the element that when clicked will open the menu
|
||||
* @param {jQuery} $menuElement the element that contains the anchors to convert into a menu
|
||||
* @param {String} menuElementLinkSelector jq selector string used to find anchors to be made into menu options
|
||||
* @returns {PopupMenu} the PopupMenu (Backbone View) that can render, control the menu
|
||||
*/
|
||||
PopupMenu.fromExistingDom = ($buttonElement, $menuElement, menuElementLinkSelector) => {
|
||||
$buttonElement = $($buttonElement);
|
||||
$menuElement = $($menuElement);
|
||||
var options = PopupMenu.convertLinksToOptions($menuElement, menuElementLinkSelector);
|
||||
// we're done with the menu (having converted it to an options map)
|
||||
$menuElement.remove();
|
||||
return new PopupMenu($buttonElement, options);
|
||||
};
|
||||
|
||||
/** Create all popupmenus within a document or a more specific element
|
||||
* @param {DOMElement} parent the DOM element in which to search for popupmenus to build (defaults to document)
|
||||
* @param {String} menuSelector jq selector string to find popupmenu menu elements (defaults to "div[popupmenu]")
|
||||
* @param {Function} buttonSelectorBuildFn the function to build the jq button selector.
|
||||
* Will be passed $menuElement, parent.
|
||||
* (Defaults to return '#' + $menuElement.attr( 'popupmenu' ); )
|
||||
* @returns {PopupMenu[]} array of popupmenus created
|
||||
*/
|
||||
PopupMenu.make_popup_menus = (parent, menuSelector, buttonSelectorBuildFn) => {
|
||||
parent = parent || document;
|
||||
// orig. Glx popupmenu menus have a (non-std) attribute 'popupmenu'
|
||||
// which contains the id of the button that activates the menu
|
||||
menuSelector = menuSelector || "div[popupmenu]";
|
||||
// default to (orig. Glx) matching button to menu by using the popupmenu attr of the menu as the id of the button
|
||||
buttonSelectorBuildFn = buttonSelectorBuildFn || (($menuElement, parent) => `#${$menuElement.attr("popupmenu")}`);
|
||||
|
||||
// aggregate and return all PopupMenus
|
||||
var popupMenusCreated = [];
|
||||
$(parent)
|
||||
.find(menuSelector)
|
||||
.each(function() {
|
||||
var $menuElement = $(this);
|
||||
|
||||
var $buttonElement = $(parent).find(buttonSelectorBuildFn($menuElement, parent));
|
||||
|
||||
popupMenusCreated.push(PopupMenu.fromDom($buttonElement, $menuElement));
|
||||
$buttonElement.addClass("popup");
|
||||
});
|
||||
return popupMenusCreated;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
export default PopupMenu;
|
||||
|
||||
@@ -356,7 +356,7 @@ const View = Backbone.View.extend({
|
||||
},
|
||||
{
|
||||
multiple: cnf.multiple,
|
||||
library: cnf.library,
|
||||
library: !!cnf.library,
|
||||
format: null
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
|
||||
import Utils from "utils/utils";
|
||||
|
||||
var View = Backbone.View.extend({
|
||||
const View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.model =
|
||||
(options && options.model) ||
|
||||
new Backbone.Model({
|
||||
@@ -26,51 +24,25 @@ var View = Backbone.View.extend({
|
||||
this.$slider = this.$(".ui-form-slider-element");
|
||||
|
||||
// add text field event
|
||||
var pressed = [];
|
||||
this.$text
|
||||
.on("change", function() {
|
||||
self.value($(this).val());
|
||||
.on("change", e => {
|
||||
this.value(e.currentTarget.value);
|
||||
})
|
||||
.on("keyup", e => {
|
||||
pressed[e.which] = false;
|
||||
})
|
||||
.on("keydown", function(e) {
|
||||
var v = e.which;
|
||||
pressed[v] = true;
|
||||
if (self.model.get("is_workflow") && pressed[16] && v == 52) {
|
||||
self.value("$");
|
||||
event.preventDefault();
|
||||
} else if (
|
||||
!(
|
||||
v == 8 ||
|
||||
v == 9 ||
|
||||
v == 13 ||
|
||||
v == 37 ||
|
||||
v == 39 ||
|
||||
(v >= 48 && v <= 57) ||
|
||||
(v >= 96 && v <= 105) ||
|
||||
((v == 190 || v == 110) &&
|
||||
$(this)
|
||||
.val()
|
||||
.indexOf(".") == -1 &&
|
||||
self.model.get("precise")) ||
|
||||
((v == 189 || v == 109) &&
|
||||
$(this)
|
||||
.val()
|
||||
.indexOf("-") == -1) ||
|
||||
self._isParameter($(this).val()) ||
|
||||
pressed[91] ||
|
||||
pressed[17]
|
||||
)
|
||||
) {
|
||||
event.preventDefault();
|
||||
.on("input", e => {
|
||||
const input = e.currentTarget;
|
||||
if (this._isParameter(input.value)) {
|
||||
return;
|
||||
}
|
||||
else if (!this.model.get("precise")) {
|
||||
input.value = input.value.split(".")[0];
|
||||
}
|
||||
input.value = input.value.replace(/[^0-9eE.-]/g, '');
|
||||
});
|
||||
|
||||
// build slider, cannot be rebuild in render
|
||||
var opts = this.model.attributes;
|
||||
const opts = this.model.attributes;
|
||||
this.has_slider = opts.max !== null && opts.min !== null && opts.max > opts.min;
|
||||
var step = opts.step;
|
||||
let step = opts.step;
|
||||
if (!step) {
|
||||
if (opts.precise && this.has_slider) {
|
||||
step = (opts.max - opts.min) / opts.split;
|
||||
@@ -80,7 +52,7 @@ var View = Backbone.View.extend({
|
||||
}
|
||||
if (this.has_slider) {
|
||||
this.$slider.slider({ min: opts.min, max: opts.max, step: step }).on("slide", (event, ui) => {
|
||||
self.value(ui.value);
|
||||
this.value(ui.value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +62,7 @@ var View = Backbone.View.extend({
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var value = this.model.get("value");
|
||||
const value = this.model.get("value");
|
||||
if (this.has_slider) {
|
||||
this.$slider.slider("value", value);
|
||||
this.$slider.show();
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import _ from "underscore";
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import Utils from "utils/utils";
|
||||
import UploadUtils from "mvc/upload/upload-utils";
|
||||
@@ -15,7 +14,7 @@ export default Backbone.View.extend({
|
||||
class_remove: "upload-icon-button fa fa-check-square-o",
|
||||
class_partial: "upload-icon-button fa fa-minus-square-o",
|
||||
help_enabled: true,
|
||||
oidc_text: `<br/>If you are signed-in to Galaxy using a third-party identity and you <strong>don't have a Galaxy password</strong> please go to <a href="${getAppRoot()}user/reset_password" target="_blank">this</a> page and request a password for your Galaxy account.`,
|
||||
oidc_text: `<br/>If you are signed-in to Galaxy using a third-party identity and you <strong>do not have a Galaxy password</strong> please use the reset password option in the login form with your email to create a password for your account.`,
|
||||
help_text: `This Galaxy server allows you to upload files via FTP. To upload some files, log in to the FTP server at <strong>${
|
||||
options.ftp_upload_site
|
||||
}</strong> using your Galaxy credentials.
|
||||
|
||||
@@ -435,6 +435,10 @@ var InputTerminal = BaseInputTerminal.extend({
|
||||
}
|
||||
if (thisMapOver.isCollection && thisMapOver.canMatch(otherCollectionType)) {
|
||||
return this._producesAcceptableDatatype(other);
|
||||
} else if (this.multiple && new CollectionTypeDescription('list').canMatch(otherCollectionType)) {
|
||||
// This handles the special case of a list input being connected to a multiple="true" data input.
|
||||
// Nested lists would be correctly mapped over by the above condition.
|
||||
return this._producesAcceptableDatatype(other);
|
||||
} else {
|
||||
// Need to check if this would break constraints...
|
||||
var mappingConstraints = this._mappingConstraints();
|
||||
|
||||
@@ -258,7 +258,7 @@ export default Backbone.View.extend({
|
||||
|
||||
for (let i = 0; i < workflow_versions.length; i++) {
|
||||
const current_wf = workflow_versions[i];
|
||||
let version_text = `Version ${current_wf["version"]}, ${current_wf["steps"]} steps`;
|
||||
let version_text = `Version ${current_wf.version}, ${current_wf.steps} steps`;
|
||||
let selected = false;
|
||||
if (i == self.workflow.workflow_version) {
|
||||
version_text = `${version_text} (active)`;
|
||||
@@ -287,7 +287,9 @@ export default Backbone.View.extend({
|
||||
$("#workflow-version-switch").unbind("change");
|
||||
if (this.value != self.workflow.workflow_version) {
|
||||
if (self.workflow && self.workflow.has_changes) {
|
||||
const r = confirm("There are unsaved changes to your workflow which will be lost. Continue ?");
|
||||
const r = window.confirm(
|
||||
"There are unsaved changes to your workflow which will be lost. Continue ?"
|
||||
);
|
||||
if (r == false) {
|
||||
// We rebuild the version select list, to reset the selected version
|
||||
self.build_version_select();
|
||||
@@ -774,6 +776,7 @@ export default Backbone.View.extend({
|
||||
// Fix width to computed width
|
||||
// Now add floats
|
||||
var buttons = $("<div class='buttons' style='float: right;'></div>");
|
||||
buttons.append($(`<div class="sr-only"><a href="#right">Node Details</a></div>`));
|
||||
if (type !== "subworkflow") {
|
||||
buttons.append(
|
||||
$("<div/>")
|
||||
|
||||
@@ -60,6 +60,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
tr.light {
|
||||
font-weight: initial;
|
||||
color: initial;
|
||||
}
|
||||
tr.light td {
|
||||
background-color: white;
|
||||
color: black;
|
||||
@@ -75,6 +79,12 @@
|
||||
background-color: #ebd4a4;
|
||||
color: white;
|
||||
}
|
||||
tr.table-primary td {
|
||||
color: $brand-light;
|
||||
}
|
||||
tr.table-primary td a {
|
||||
color: $brand-white;
|
||||
}
|
||||
a.dark {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -53,18 +53,8 @@ input[type="radio"] {
|
||||
max-width: 900px; // BS4 sets this to 500px now, so width not respected.
|
||||
}
|
||||
|
||||
.pagination {
|
||||
> .active > a {
|
||||
background-color: #ebd9b2;
|
||||
color: black;
|
||||
&:hover {
|
||||
color: black;
|
||||
background-color: #ebd9b2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll modal body.
|
||||
|
||||
.modal-body {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,7 @@
|
||||
<datatype extension="mz5" type="galaxy.datatypes.binary:H5" subclass="true" mimetype="application/octet-stream" display_in_upload="true"/>
|
||||
<datatype extension="hivtrace" type="galaxy.datatypes.text:Json" mimetype="application/json" subclass="true" display_in_upload="false"/>
|
||||
<datatype extension="cool" type="galaxy.datatypes.binary:Cool" mimetype="application/octet-stream" display_in_upload="true"/>
|
||||
<datatype extension="mcool" type="galaxy.datatypes.binary:MCool" 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"/>
|
||||
@@ -730,6 +731,12 @@
|
||||
<datatype extension="sbml" type="galaxy.datatypes.xml:Sbml" mimetype="application/xml" display_in_upload="true"/>
|
||||
<datatype extension="spalndbnp" type="galaxy.datatypes.spaln:SpalnNuclDb" display_in_upload="true" />
|
||||
<datatype extension="spalndba" type="galaxy.datatypes.spaln:SpalnProtDb" display_in_upload="true" />
|
||||
<datatype extension="dada2_derep" type="galaxy.datatypes.binary:RData" subclass="true" display_in_upload="true" />
|
||||
<datatype extension="dada2_dada" type="galaxy.datatypes.binary:RData" subclass="true" display_in_upload="true" />
|
||||
<datatype extension="dada2_errorrates" type="galaxy.datatypes.binary:RData" subclass="true" display_in_upload="true" />
|
||||
<datatype extension="dada2_mergepairs" type="galaxy.datatypes.binary:RData" subclass="true" display_in_upload="true" />
|
||||
<datatype extension="dada2_sequencetable" type="galaxy.datatypes.tabular:Tabular" mimetype="application/text" subclass="true" display_in_upload="true" />
|
||||
<datatype extension="dada2_uniques" type="galaxy.datatypes.tabular:Tabular" mimetype="application/text" subclass="true" display_in_upload="true" />
|
||||
</registration>
|
||||
<sniffers>
|
||||
<!--
|
||||
@@ -769,6 +776,7 @@
|
||||
<sniffer type="galaxy.datatypes.binary:GAFASQLite"/>
|
||||
<sniffer type="galaxy.datatypes.binary:SQlite"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Cool"/>
|
||||
<sniffer type="galaxy.datatypes.binary:MCool"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Loom"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Anndata"/>
|
||||
<sniffer type="galaxy.datatypes.binary:Biom2"/>
|
||||
|
||||
+14
-10
@@ -144,7 +144,7 @@ galaxy:
|
||||
# than 5 milliseconds.
|
||||
#slow_query_log_threshold: 0
|
||||
|
||||
# Enable's a per request sql debugging option. If this is set to true,
|
||||
# Enables a per request sql debugging option. If this is set to true,
|
||||
# append ?sql_debug=1 to web request URLs to enable detailed logging
|
||||
# on the backend of SQL queries generated during that request. This is
|
||||
# useful for debugging slow endpoints during development.
|
||||
@@ -333,7 +333,7 @@ galaxy:
|
||||
# be used for job destinations with Docker enabled.
|
||||
#enable_beta_mulled_containers: false
|
||||
|
||||
# Container resolvers configuration (beta). Setup a file describing
|
||||
# Container resolvers configuration (beta). Set up a file describing
|
||||
# container resolvers to use when discovering containers for Galaxy.
|
||||
# If this is set to None, the default containers loaded is determined
|
||||
# by enable_beta_mulled_containers.
|
||||
@@ -632,7 +632,7 @@ galaxy:
|
||||
|
||||
# Galaxy can display data at various external browsers. These options
|
||||
# specify which browsers should be available. URLs and builds
|
||||
# available at these browsers are defined in the specifield files. If
|
||||
# available at these browsers are defined in the specified files. If
|
||||
# use_remote_user = True, display application servers will be denied
|
||||
# access to Galaxy and so displaying datasets in these sites will
|
||||
# fail. display_servers contains a list of hostnames which should be
|
||||
@@ -693,11 +693,10 @@ galaxy:
|
||||
# URL (with schema http/https) of the Galaxy instance as accessible
|
||||
# within your local network - if specified used as a default by pulsar
|
||||
# file staging and Jupyter Docker container for communicating back
|
||||
# with Galaxy via the API. If you are attempting to setup GIEs on Mac
|
||||
# OS X with Docker for Mac - this should likely be the IP address of
|
||||
# your machine on the virtualbox network (vboxnet0) setup for the
|
||||
# Docker host VM. This can found by running ifconfig and using the IP
|
||||
# address of the network vboxnet0.
|
||||
# with Galaxy via the API. If you are attempting to set up GIEs on
|
||||
# Mac OS X with Docker Desktop for Mac and your Galaxy instance runs
|
||||
# on port 8080 this should be 'http://host.docker.internal:8080'. For
|
||||
# more details see https://docs.docker.com/docker-for-mac/networking/
|
||||
#galaxy_infrastructure_url: http://localhost:8080
|
||||
|
||||
# If the above URL cannot be determined ahead of time in dynamic
|
||||
@@ -877,11 +876,11 @@ galaxy:
|
||||
# for IPC, set that here.
|
||||
#dynamic_proxy_session_map: database/session_map.sqlite
|
||||
|
||||
# Set the port and IP for the the dynamic proxy to bind to, this must
|
||||
# Set the port and IP for the dynamic proxy to bind to, this must
|
||||
# match the external configuration if dynamic_proxy_manage is False.
|
||||
#dynamic_proxy_bind_port: 8800
|
||||
|
||||
# Set the port and IP for the the dynamic proxy to bind to, this must
|
||||
# Set the port and IP for the dynamic proxy to bind to, this must
|
||||
# match the external configuration if dynamic_proxy_manage is False.
|
||||
#dynamic_proxy_bind_ip: 0.0.0.0
|
||||
|
||||
@@ -1530,6 +1529,11 @@ galaxy:
|
||||
# configuration file.
|
||||
#job_config_file: config/job_conf.xml
|
||||
|
||||
# Description of job running configuration, can be embedded into
|
||||
# Galaxy configuration or loaded from an additional file with the
|
||||
# job_config_file option.
|
||||
#job_config: null
|
||||
|
||||
# When jobs fail due to job runner problems, Galaxy can be configured
|
||||
# to retry these or reroute the jobs to new destinations. Very fine
|
||||
# control of this is available with resubmit declarations in
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<!-- <param id="persistence_directory">/path/to/dir</param> -->
|
||||
<!-- Number of seconds to wait for an acknowledgement before
|
||||
republishing a message. -->
|
||||
<!-- <param id="amqp_republish_time">30</param> -->
|
||||
<!-- <param id="amqp_ack_republish_time">30</param> -->
|
||||
<!-- Pulsar job manager to communicate with (see Pulsar
|
||||
docs for information on job managers). -->
|
||||
<!-- <param id="manager">_default_</param> -->
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
var IES = window.IES;
|
||||
|
||||
function load_askomics(url){
|
||||
$( document ).ready(function() {
|
||||
IES.test_ie_availability(url, function(){
|
||||
IES.append_notebook(url);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
var IES = window.IES;
|
||||
|
||||
function load_askomics(url) {
|
||||
$(document).ready(function() {
|
||||
IES.test_ie_availability(url, function() {
|
||||
IES.append_notebook(url);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -34,16 +34,13 @@ url = ie_request.url_template('${PROXY_URL}/login_api_gie?key=' + askomics_api_k
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/askomics'], function(IES){
|
||||
window.IES = IES;
|
||||
load_askomics(url);
|
||||
});
|
||||
load_askomics(url);
|
||||
</script>
|
||||
<div id="main" width="100%" height="100%">
|
||||
</div>
|
||||
|
||||
+15
-15
@@ -2,20 +2,20 @@
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function message_failed_auth(password){
|
||||
toastr.info(
|
||||
"Automatic authorization failed.",
|
||||
"Please login manually",
|
||||
{'closeButton': true, 'timeOut': 100000, 'tapToDismiss': false}
|
||||
);
|
||||
function message_failed_auth(password) {
|
||||
toastr.info("Automatic authorization failed.", "Please login manually", {
|
||||
closeButton: true,
|
||||
timeOut: 100000,
|
||||
tapToDismiss: false
|
||||
});
|
||||
}
|
||||
|
||||
function message_failed_connection(){
|
||||
toastr.error(
|
||||
"Could not connect to BAM iobio. Please contact your administrator.",
|
||||
"Security warning",
|
||||
{'closeButton': true, 'timeOut': 20000, 'tapToDismiss': true}
|
||||
);
|
||||
function message_failed_connection() {
|
||||
toastr.error("Could not connect to BAM iobio. Please contact your administrator.", "Security warning", {
|
||||
closeButton: true,
|
||||
timeOut: 20000,
|
||||
tapToDismiss: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,10 +25,10 @@ function message_failed_connection(){
|
||||
* @param {String} notebook_access_url: the URL embeded in the page and loaded
|
||||
*
|
||||
*/
|
||||
function load_notebook(notebook_access_url){
|
||||
function load_notebook(notebook_access_url) {
|
||||
// Test notebook_login_url for accessibility, executing the login+load function whenever
|
||||
// we've successfully connected to the IE.
|
||||
IES.test_ie_availability(notebook_access_url, function(){
|
||||
IES.test_ie_availability(notebook_access_url, function() {
|
||||
_handle_notebook_loading(notebook_access_url);
|
||||
});
|
||||
}
|
||||
@@ -36,6 +36,6 @@ function load_notebook(notebook_access_url){
|
||||
/**
|
||||
* Must be implemented by IEs
|
||||
*/
|
||||
function _handle_notebook_loading(notebook_access_url){
|
||||
function _handle_notebook_loading(notebook_access_url) {
|
||||
IES.append_notebook(notebook_access_url);
|
||||
}
|
||||
@@ -24,6 +24,7 @@ root = h.url_for( '/' )
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -31,12 +32,8 @@ root = h.url_for( '/' )
|
||||
|
||||
${ ie.default_javascript_variables() }
|
||||
var notebook_access_url = '${ notebook_access_url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/bam_iobio'], function(IES){
|
||||
window.IES = IES;
|
||||
IES.display_spinner();
|
||||
});
|
||||
IES.display_spinner();
|
||||
|
||||
toastr.info(
|
||||
"BAM io.bio is starting up!",
|
||||
@@ -46,11 +43,8 @@ root = h.url_for( '/' )
|
||||
|
||||
var startup = function(){
|
||||
// Load notebook
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/bam_iobio'], function(IES){
|
||||
window.IES = IES;
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
-
|
||||
image: quay.io/galaxy/cellxgene-galaxy-ie:2019.01.30
|
||||
image: quay.io/galaxy/cellxgene-galaxy-ie:2019.05.13
|
||||
description: |
|
||||
An interactive data explorer for single-cell transcriptomics datasets
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
FROM python:3.6.8-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
net-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN pip3 install cellxgene && rm -rf ~/.cache
|
||||
RUN pip3 install cellxgene galaxy-ie-helpers && rm -rf ~/.cache
|
||||
|
||||
ADD ./run_cellxgene.sh /
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
cellxgene launch --host 0.0.0.0 --port 80 /input/file.*
|
||||
get -i ${DATASET_HID} \
|
||||
&& mv /import/${DATASET_HID} /import/${DATASET_HID}.h5ad \
|
||||
&& cellxgene launch --host 0.0.0.0 --port 80 /import/${DATASET_HID}.h5ad
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
<%
|
||||
ie_request.load_deploy_config()
|
||||
|
||||
# Make the dataset available inside the container
|
||||
data_file = ie_request.volume('/input/file.' + hda.ext, hda.file_name, mode='ro')
|
||||
|
||||
ie_request.launch(
|
||||
image = trans.request.params.get('image_tag', None),
|
||||
volumes = [data_file]
|
||||
image = trans.request.params.get('image_tag', None),
|
||||
env_override={
|
||||
'dataset_hid': hda.hid
|
||||
}
|
||||
)
|
||||
|
||||
url = ie_request.url_template('${PROXY_URL}')
|
||||
@@ -21,14 +20,11 @@
|
||||
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
requirejs(['galaxy.interactive_environments'], function (IES) {
|
||||
$( document ).ready(function() {
|
||||
IES.keepAlive(url);
|
||||
IES.test_ie_availability(url, function() {
|
||||
IES.append_notebook(url);
|
||||
});
|
||||
$( document ).ready(function() {
|
||||
IES.keepAlive(url);
|
||||
IES.test_ie_availability(url, function() {
|
||||
IES.append_notebook(url);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
<%def name="load_default_js()">
|
||||
${h.css( 'base' ) }
|
||||
${h.js('bundled/libs.chunk',
|
||||
'bundled/base.chunk',
|
||||
'bundled/generic.bundled')}
|
||||
</%def>
|
||||
|
||||
<%def name="default_javascript_variables()">
|
||||
// Globals
|
||||
|
||||
@@ -10,28 +17,15 @@ ie_password = '${ ie_request.notebook_pw }';
|
||||
var galaxy_root = '${ ie_request.attr.root }';
|
||||
var app_root = '${ ie_request.attr.app_root }';
|
||||
var ie_readiness_url = '${ h.url_for("/interactive_environments/ready") }';
|
||||
</%def>
|
||||
|
||||
|
||||
<%def name="load_default_js()">
|
||||
${h.css( 'base' ) }
|
||||
${h.js( 'libs/jquery/jquery',
|
||||
'libs/toastr',
|
||||
'libs/require')}
|
||||
</%def>
|
||||
|
||||
<%def name="plugin_require_config()">
|
||||
require.config({
|
||||
baseUrl: app_root,
|
||||
paths: {
|
||||
"plugin" : app_root + "js",
|
||||
"galaxy.interactive_environments": "${h.url_for('/static/scripts/galaxy.interactive_environments')}",
|
||||
},
|
||||
urlArgs: "v=${app.server_starttime}",
|
||||
});
|
||||
window.IES = bundleEntries.IES;
|
||||
window.toastr = bundleEntries.Toast;
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
return 'You are leaving your Interactive Environment.';
|
||||
};
|
||||
</%def>
|
||||
|
||||
<%def name="load_default_app()">
|
||||
<script src="${'%sjs/main.js?v=%s' % (ie_request.attr.app_root, app.server_starttime)}" type="text/javascript"></script>
|
||||
</%def>
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function load_notebook(url){
|
||||
IES.test_ie_availability(url, function(){
|
||||
function load_notebook(url) {
|
||||
IES.test_ie_availability(url, function() {
|
||||
IES.append_notebook(url);
|
||||
});
|
||||
}
|
||||
@@ -18,20 +18,17 @@ url = ie_request.url_template('${PROXY_URL}/ethercalc/')
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
// Keep container running and load IE
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/ethercalc'], function(IES){
|
||||
window.IES = IES;
|
||||
IES.keepAlive(url);
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
IES.keepAlive(url);
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
</script>
|
||||
<div id="main" width="100%" height="100%">
|
||||
|
||||
+3
-3
@@ -3,12 +3,12 @@ var IES = window.IES;
|
||||
|
||||
// Load an interactive environment (IE) from a remote URL
|
||||
// @param {String} hicexplorer_access_url: the URL embeded in the page and loaded
|
||||
function load_hicexplorer(hicexplorer_access_url){
|
||||
function load_hicexplorer(hicexplorer_access_url) {
|
||||
// When the page has completely loaded...
|
||||
$( document ).ready(function() {
|
||||
$(document).ready(function() {
|
||||
// Test if we can access the GIE, and if so, execute the function
|
||||
// to load the GIE for the user.
|
||||
IES.test_ie_availability(hicexplorer_access_url, function(){
|
||||
IES.test_ie_availability(hicexplorer_access_url, function() {
|
||||
IES.append_notebook(hicexplorer_access_url);
|
||||
});
|
||||
});
|
||||
@@ -29,19 +29,14 @@
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/hicbrowser'], function (IES) {
|
||||
window.IES = IES;
|
||||
load_hicexplorer(url);
|
||||
});
|
||||
load_hicexplorer(url);
|
||||
|
||||
</script>
|
||||
<div id="main" width="100%" height="100%">
|
||||
|
||||
+58
-44
@@ -2,23 +2,25 @@
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function message_failed_auth(password){
|
||||
function message_failed_auth(password) {
|
||||
toastr.info(
|
||||
"Automatic authorization failed. You can manually login with:<br>" + password + "<br> <a href='https://github.com/bgruening/galaxy-ipython/wiki/Automatic-Authorization-Failed' target='_blank'>More details ...</a>",
|
||||
"Automatic authorization failed. You can manually login with:<br>" +
|
||||
password +
|
||||
"<br> <a href='https://github.com/bgruening/galaxy-ipython/wiki/Automatic-Authorization-Failed' target='_blank'>More details ...</a>",
|
||||
"Please login manually",
|
||||
{'closeButton': true, 'timeOut': 100000, 'tapToDismiss': false}
|
||||
{ closeButton: true, timeOut: 100000, tapToDismiss: false }
|
||||
);
|
||||
}
|
||||
|
||||
function message_failed_connection(){
|
||||
function message_failed_connection() {
|
||||
toastr.error(
|
||||
"Could not connect to Jupyter Notebook. Please contact your administrator. <a href='https://github.com/bgruening/galaxy-ipython/wiki/Could-not-connect-to-IPython-Notebook' target='_blank'>More details ...</a>",
|
||||
"Security warning",
|
||||
{'closeButton': true, 'timeOut': 20000, 'tapToDismiss': true}
|
||||
"Security warning",
|
||||
{ closeButton: true, timeOut: 20000, tapToDismiss: true }
|
||||
);
|
||||
}
|
||||
|
||||
function message_no_auth(){
|
||||
function message_no_auth() {
|
||||
// No longer a security issue, proxy validates Galaxy session token.
|
||||
/*
|
||||
toastr.warning(
|
||||
@@ -29,7 +31,6 @@ function message_no_auth(){
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load an interactive environment (IE) from a remote URL
|
||||
* @param {String} password: password used to authenticate to the remote resource
|
||||
@@ -37,68 +38,82 @@ function message_no_auth(){
|
||||
* @param {String} notebook_access_url: the URL embeded in the page and loaded
|
||||
*
|
||||
*/
|
||||
function load_notebook(password, notebook_login_url, notebook_access_url){
|
||||
function load_notebook(password, notebook_login_url, notebook_access_url) {
|
||||
// Test notebook_login_url for accessibility, executing the login+load function whenever
|
||||
// we've successfully connected to the IE.
|
||||
IES.test_ie_availability(notebook_login_url, function(){
|
||||
IES.test_ie_availability(notebook_login_url, function() {
|
||||
_handle_notebook_loading(password, notebook_login_url, notebook_access_url);
|
||||
keep_alive();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function keep_alive(){
|
||||
function keep_alive() {
|
||||
/**
|
||||
* This is needed to keep the container alive. If the user leaves this site
|
||||
* this function is not constantly pinging the container, the container will
|
||||
* terminate itself.
|
||||
*/
|
||||
* This is needed to keep the container alive. If the user leaves this site
|
||||
* this function is not constantly pinging the container, the container will
|
||||
* terminate itself.
|
||||
*/
|
||||
var warn_at = 4;
|
||||
var count_max = 60;
|
||||
// we sleep 15 seconds between requests and the default timeout for the Jupyter container is 120 seconds, so start
|
||||
// with a pretty high ajax timeout. sleep starts low because we want to get the warning up pretty quickly
|
||||
var spin_state = IES.make_spin_state("IE keepalive", 8000, 16000, 2000, 5000, 15000, 5000, false);
|
||||
var success = function(){
|
||||
var success = function() {
|
||||
console.log("IE keepalive request succeeded");
|
||||
toastr.clear();
|
||||
if(spin_state.count >= warn_at){
|
||||
if (spin_state.count >= warn_at) {
|
||||
toastr.clear();
|
||||
toastr.success(
|
||||
"Interactive environment connection restored",
|
||||
{'closeButton': true, 'timeOut': 5000, 'extendedTimeOut': 2000, 'tapToDismiss': true}
|
||||
);
|
||||
toastr.success("Interactive environment connection restored", {
|
||||
closeButton: true,
|
||||
timeOut: 5000,
|
||||
extendedTimeOut: 2000,
|
||||
tapToDismiss: true
|
||||
});
|
||||
}
|
||||
spin_state.count = 0;
|
||||
spin_state.timeout_count = 0;
|
||||
spin_state.error_count = 0;
|
||||
return false; // keep spinning
|
||||
return false; // keep spinning
|
||||
};
|
||||
var timeout_error = function(jqxhr, status, error){
|
||||
console.log("IE keepalive request failed " + spin_state.count + " time(s) of " + count_max + " max: " + status + ": " + error);
|
||||
if(spin_state.count == warn_at){
|
||||
var timeout_error = function(jqxhr, status, error) {
|
||||
console.log(
|
||||
"IE keepalive request failed " +
|
||||
spin_state.count +
|
||||
" time(s) of " +
|
||||
count_max +
|
||||
" max: " +
|
||||
status +
|
||||
": " +
|
||||
error
|
||||
);
|
||||
if (spin_state.count == warn_at) {
|
||||
toastr.warning(
|
||||
"Your browser has been unable to contact the interactive environment for "
|
||||
+ spin_state.count + " consecutive attempts, if you do not reestablish "
|
||||
+ "a connection, your IE container may be terminated.",
|
||||
"Your browser has been unable to contact the interactive environment for " +
|
||||
spin_state.count +
|
||||
" consecutive attempts, if you do not reestablish " +
|
||||
"a connection, your IE container may be terminated.",
|
||||
"Warning",
|
||||
{'closeButton': true, 'timeOut': 0, 'extendedTimeOut': 0, 'tapToDismiss': false}
|
||||
{ closeButton: true, timeOut: 0, extendedTimeOut: 0, tapToDismiss: false }
|
||||
);
|
||||
return false; // keep spinning
|
||||
}else if(spin_state.count >= count_max){
|
||||
IES.spin_error("IE keepalive failure limit reached", "Lost connection to interactive environment, contact your administrator", false);
|
||||
return true; // stop spinning
|
||||
return false; // keep spinning
|
||||
} else if (spin_state.count >= count_max) {
|
||||
IES.spin_error(
|
||||
"IE keepalive failure limit reached",
|
||||
"Lost connection to interactive environment, contact your administrator",
|
||||
false
|
||||
);
|
||||
return true; // stop spinning
|
||||
}
|
||||
};
|
||||
console.log("IE keepalive worker starting");
|
||||
IES.spin(notebook_keepalive_url, false, success, timeout_error, timeout_error, spin_state);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Must be implemented by IEs
|
||||
*/
|
||||
function _handle_notebook_loading(password, notebook_login_url, notebook_access_url){
|
||||
if ( ie_password_auth ) {
|
||||
function _handle_notebook_loading(password, notebook_login_url, notebook_access_url) {
|
||||
if (ie_password_auth) {
|
||||
// Make an AJAX POST
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
@@ -106,29 +121,28 @@ function _handle_notebook_loading(password, notebook_login_url, notebook_access_
|
||||
url: notebook_login_url,
|
||||
// With our password
|
||||
data: {
|
||||
'password': password
|
||||
password: password
|
||||
},
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
// If that is successful, load the notebook
|
||||
success: function(){
|
||||
success: function() {
|
||||
IES.append_notebook(notebook_access_url);
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
if(ie_password_auth){
|
||||
error: function(jqxhr, status, error) {
|
||||
if (ie_password_auth) {
|
||||
// Failure happens due to CORS
|
||||
message_failed_auth(password);
|
||||
IES.append_notebook(notebook_access_url);
|
||||
}else{
|
||||
} else {
|
||||
message_failed_connection();
|
||||
// Do we want to try and load the notebook anyway? Just in case?
|
||||
IES.append_notebook(notebook_access_url);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Not using password auth, just embed it to avoid content-origin issues.
|
||||
message_no_auth();
|
||||
IES.append_notebook(notebook_access_url);
|
||||
@@ -50,6 +50,7 @@ notebook_keepalive_url = ie_request.url_template('${PROXY_URL}/ipython/tree')
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -58,16 +59,10 @@ ${ ie.default_javascript_variables() }
|
||||
var notebook_login_url = '${ notebook_login_url }';
|
||||
var notebook_access_url = '${ notebook_access_url }';
|
||||
var notebook_keepalive_url = '${ notebook_keepalive_url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
// Load notebook
|
||||
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/jupyter'], function(IES){
|
||||
// This global is not awesome, get rid of it when possible (when IES are a part of the build process)
|
||||
window.IES = IES;
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(ie_password, notebook_login_url, notebook_access_url);
|
||||
});
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(ie_password, notebook_login_url, notebook_access_url);
|
||||
});
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@ var IES = window.IES;
|
||||
|
||||
// Load an interactive environment (IE) from a remote URL
|
||||
// @param {String} notebook_access_url: the URL embeded in the page and loaded
|
||||
function load_notebook(notebook_access_url){
|
||||
function load_notebook(notebook_access_url) {
|
||||
// Test if we can access the GIE, and if so, execute the function
|
||||
// to load the GIE for the user.
|
||||
IES.test_ie_availability(notebook_access_url, function(){
|
||||
IES.test_ie_availability(notebook_access_url, function() {
|
||||
IES.append_notebook(notebook_access_url);
|
||||
});
|
||||
}
|
||||
@@ -23,20 +23,14 @@
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
${ ie.default_javascript_variables() }
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/neo'], function (IES) {
|
||||
window.IES = IES;
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
// Globals to be rid of
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function load_notebook(url) {
|
||||
IES.test_ie_availability(url, function() {
|
||||
append_notebook(url);
|
||||
});
|
||||
}
|
||||
|
||||
function append_notebook(url) {
|
||||
IES.clear_main_area();
|
||||
$("#main").append(
|
||||
'<iframe frameBorder="0" seamless="seamless" style="width: 100%; height: 100%; overflow:auto;" scrolling="yes" src="' +
|
||||
url +
|
||||
'"></iframe>'
|
||||
);
|
||||
}
|
||||
|
||||
function keep_alive(notebook_access_url) {
|
||||
/**
|
||||
* This is needed to keep the container alive. If the user leaves this site
|
||||
* this function is not constantly pinging the container, the container will
|
||||
* terminate itself.
|
||||
*/
|
||||
|
||||
var request_count = 0;
|
||||
var interval = window.setInterval(function() {
|
||||
$.ajax({
|
||||
url: notebook_access_url,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
type: "GET",
|
||||
timeout: 500,
|
||||
success: function() {
|
||||
console.log("Connected to IE, returning");
|
||||
},
|
||||
error: function(jqxhr, status, error) {
|
||||
request_count++;
|
||||
console.log("Request " + request_count);
|
||||
if (request_count > 30) {
|
||||
window.clearInterval(interval);
|
||||
IES.clear_main_area();
|
||||
toastr.error("Could not connect to IE, contact your administrator", "Error", {
|
||||
closeButton: true,
|
||||
timeOut: 20000,
|
||||
tapToDismiss: false
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Globals to be rid of
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function load_notebook(url){
|
||||
IES.test_ie_availability(url, function(){
|
||||
append_notebook(url);
|
||||
});
|
||||
}
|
||||
|
||||
function append_notebook(url){
|
||||
IES.clear_main_area();
|
||||
$('#main').append(
|
||||
'<iframe frameBorder="0" seamless="seamless" style="width: 100%; height: 100%; overflow:auto;" scrolling="yes" src="'+ url +'"></iframe>'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function keep_alive(notebook_access_url){
|
||||
/**
|
||||
* This is needed to keep the container alive. If the user leaves this site
|
||||
* this function is not constantly pinging the container, the container will
|
||||
* terminate itself.
|
||||
*/
|
||||
|
||||
var request_count = 0;
|
||||
var interval = window.setInterval(function(){
|
||||
$.ajax({
|
||||
url: notebook_access_url,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
},
|
||||
type: "GET",
|
||||
timeout: 500,
|
||||
success: function(){
|
||||
console.log("Connected to IE, returning");
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
request_count++;
|
||||
console.log("Request " + request_count);
|
||||
if(request_count > 30){
|
||||
window.clearInterval(interval);
|
||||
IES.clear_main_area();
|
||||
toastr.error(
|
||||
"Could not connect to IE, contact your administrator",
|
||||
"Error",
|
||||
{'closeButton': true, 'timeOut': 20000, 'tapToDismiss': false}
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
|
||||
@@ -21,21 +21,18 @@ url = ie_request.url_template('${PROXY_URL}/phinch/')
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
${ ie.default_javascript_variables() }
|
||||
var url = '${ url }';
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
// Keep container running and load notebook
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/phinch'], function(IES){
|
||||
window.IES = IES;
|
||||
keep_alive(url);
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
keep_alive(url);
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(url);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# appropriate `apt-get/pip install` statements.
|
||||
---
|
||||
-
|
||||
image: erasche/docker-rstudio-notebook:19.05
|
||||
image: quay.io/erasche/docker-rstudio-notebook:19.05
|
||||
description: |
|
||||
This familiar R analysis software suite will let you explore your
|
||||
datasets in depth. Comes with ggplot2, RODBC, maps, shinyapps, knitr,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Assumed globals we need to get rid of
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function message_failed_connection() {
|
||||
toastr.error("Could not connect to RStudio. Please contact your administrator.", "Security warning", {
|
||||
closeButton: true,
|
||||
timeOut: 20000,
|
||||
tapToDismiss: true
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an interactive environment (IE) from a remote URL
|
||||
* @param {String} notebook_access_url: the URL embeded in the page and loaded
|
||||
*
|
||||
*/
|
||||
function load_notebook(notebook_access_url) {
|
||||
// Test notebook_login_url for accessibility, executing the login+load function whenever
|
||||
// we've successfully connected to the IE.
|
||||
IES.test_ie_availability(notebook_access_url, function() {
|
||||
IES.append_notebook(notebook_access_url);
|
||||
});
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Assumed globals we need to get rid of
|
||||
var IES = window.IES;
|
||||
var toastr = window.toastr;
|
||||
|
||||
function message_failed_connection(){
|
||||
toastr.error(
|
||||
"Could not connect to RStudio. Please contact your administrator.",
|
||||
"Security warning",
|
||||
{'closeButton': true, 'timeOut': 20000, 'tapToDismiss': true}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load an interactive environment (IE) from a remote URL
|
||||
* @param {String} notebook_access_url: the URL embeded in the page and loaded
|
||||
*
|
||||
*/
|
||||
function load_notebook(notebook_access_url){
|
||||
// Test notebook_login_url for accessibility, executing the login+load function whenever
|
||||
// we've successfully connected to the IE.
|
||||
IES.test_ie_availability(notebook_access_url, function(){
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: notebook_access_url,
|
||||
success: function(response_text){
|
||||
IES.append_notebook(notebook_access_url);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
@@ -27,18 +27,15 @@ notebook_access_url = ie_request.url_template('${PROXY_URL}/rstudio/')
|
||||
<html>
|
||||
<head>
|
||||
${ ie.load_default_js() }
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body style="margin: 0px">
|
||||
|
||||
<script type="text/javascript">
|
||||
${ ie.default_javascript_variables() }
|
||||
var notebook_access_url = '${ notebook_access_url }';
|
||||
${ ie.plugin_require_config() }
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/rstudio'], function(IES){
|
||||
window.IES = IES;
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
</script>
|
||||
<div id="main" width="100%" height="100%">
|
||||
|
||||
@@ -393,15 +393,31 @@ Gitter or IRC channel.
|
||||
17. How can I upgrade Conda?
|
||||
****************************
|
||||
|
||||
Many potential issues with Conda have been resolved with fixes in Conda itself. If
|
||||
you let Galaxy install Conda prior to the release of 17.01 you probably have version
|
||||
3.19.3. This can be updated to 4.2.13 with the following command:
|
||||
Many potential issues with Conda have been resolved with fixes in Conda itself.
|
||||
The Conda installed by Galaxy can be updated to e.g. version 4.6.14 with the
|
||||
following command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ <tool_dependency_dir/_conda/bin/conda update -y conda==4.2.13
|
||||
$ <tool_dependency_dir/_conda/bin/conda install conda==4.6.14
|
||||
|
||||
The command can obviously be adapted to install any version of Conda.
|
||||
The command can obviously be adapted to install any version of Conda. If the
|
||||
above command fails with an error like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
UnsatisfiableError: The following specifications were found to be in conflict:
|
||||
- conda ==4.6.14 -> python >=3.6,<3.7.0a0
|
||||
- python 3.5*
|
||||
Use "conda info <package>" to see the dependencies for each package.
|
||||
|
||||
Then you need to also update the ``python`` package installed in the base
|
||||
environment by appending to the ``conda install`` command above an appropriate
|
||||
specification, which for the example error above would be ``python==3.6``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ <tool_dependency_dir/_conda/bin/conda install conda==4.6.14 python==3.6
|
||||
|
||||
|
||||
.. _Conda documentation: https://conda.io/docs/
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:Description:
|
||||
Enable's a per request sql debugging option. If this is set to
|
||||
Enables a per request sql debugging option. If this is set to
|
||||
true, append ?sql_debug=1 to web request URLs to enable detailed
|
||||
logging on the backend of SQL queries generated during that
|
||||
request. This is useful for debugging slow endpoints during
|
||||
@@ -517,7 +517,7 @@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:Description:
|
||||
Container resolvers configuration (beta). Setup a file describing
|
||||
Container resolvers configuration (beta). Set up a file describing
|
||||
container resolvers to use when discovering containers for Galaxy.
|
||||
If this is set to None, the default containers loaded is
|
||||
determined by enable_beta_mulled_containers.
|
||||
@@ -1175,7 +1175,7 @@
|
||||
:Description:
|
||||
Galaxy can display data at various external browsers. These
|
||||
options specify which browsers should be available. URLs and
|
||||
builds available at these browsers are defined in the specifield
|
||||
builds available at these browsers are defined in the specified
|
||||
files. If use_remote_user = True, display application servers
|
||||
will be denied access to Galaxy and so displaying datasets in
|
||||
these sites will fail. display_servers contains a list of
|
||||
@@ -1301,11 +1301,11 @@
|
||||
URL (with schema http/https) of the Galaxy instance as accessible
|
||||
within your local network - if specified used as a default by
|
||||
pulsar file staging and Jupyter Docker container for communicating
|
||||
back with Galaxy via the API. If you are attempting to setup GIEs
|
||||
on Mac OS X with Docker for Mac - this should likely be the IP
|
||||
address of your machine on the virtualbox network (vboxnet0) setup
|
||||
for the Docker host VM. This can found by running ifconfig and
|
||||
using the IP address of the network vboxnet0.
|
||||
back with Galaxy via the API. If you are attempting to set up
|
||||
GIEs on Mac OS X with Docker Desktop for Mac and your Galaxy
|
||||
instance runs on port 8080 this should be
|
||||
'http://host.docker.internal:8080'. For more details see
|
||||
https://docs.docker.com/docker-for-mac/networking/
|
||||
:Default: ``http://localhost:8080``
|
||||
:Type: str
|
||||
|
||||
@@ -1732,9 +1732,8 @@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:Description:
|
||||
Set the port and IP for the the dynamic proxy to bind to, this
|
||||
must match the external configuration if dynamic_proxy_manage is
|
||||
False.
|
||||
Set the port and IP for the dynamic proxy to bind to, this must
|
||||
match the external configuration if dynamic_proxy_manage is False.
|
||||
:Default: ``8800``
|
||||
:Type: int
|
||||
|
||||
@@ -1744,9 +1743,8 @@
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:Description:
|
||||
Set the port and IP for the the dynamic proxy to bind to, this
|
||||
must match the external configuration if dynamic_proxy_manage is
|
||||
False.
|
||||
Set the port and IP for the dynamic proxy to bind to, this must
|
||||
match the external configuration if dynamic_proxy_manage is False.
|
||||
:Default: ``0.0.0.0``
|
||||
:Type: str
|
||||
|
||||
@@ -3187,6 +3185,18 @@
|
||||
:Type: str
|
||||
|
||||
|
||||
~~~~~~~~~~~~~~
|
||||
``job_config``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
:Description:
|
||||
Description of job running configuration, can be embedded into
|
||||
Galaxy configuration or loaded from an additional file with the
|
||||
job_config_file option.
|
||||
:Default: ``None``
|
||||
:Type: map
|
||||
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
``default_job_resubmission_condition``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -36,17 +36,13 @@ and `Ansible Galaxy <https://galaxy.ansible.com/detail#/role/6056>`__.
|
||||
Setting up the Proxy
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Currently the Galaxy proxy is a NodeJS+Sqlite3 proxy.
|
||||
The Galaxy IE Proxy is a NodeJS+Sqlite3 application. The NodeJS that is
|
||||
installed by default into the Galaxy Virtualenv is suitable for an execution
|
||||
environment for the Galaxy IE Proxy.
|
||||
|
||||
- Node has recently upgraded, and our proxy is pinned to an old version of
|
||||
sqlite3. As such you'll currently need to have an older version of Node
|
||||
available (0.10.X - 0.11.X vintage).
|
||||
- One can use `NVM <https://github.com/creationix/nvm>`__ to install and manage multiple versions of Node.
|
||||
- We're working on solutions in this space to provide a better deployment
|
||||
mechanism here and fewer dependencies.
|
||||
- Please note that if you have NodeJS installed under Ubuntu, it often
|
||||
installs to ``/usr/bin/nodejs``, whereas ``npm`` expects it to be
|
||||
``/usr/bin/node``. You will need to create that symlink yourself.
|
||||
- Note that if you have NodeJS installed under Ubuntu, it often installs to
|
||||
``/usr/bin/nodejs``, whereas ``npm`` expects it to be ``/usr/bin/node``. You
|
||||
may need to create that symlink yourself.
|
||||
|
||||
Once Node and npm are ready to go, you'll need to install the dependencies
|
||||
|
||||
|
||||
@@ -205,9 +205,10 @@ We'll continue appending to our ``helloworld.mako`` the HTML code that's actuall
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<!-- Loads some necessary javascript libraries. Specifically jquery,
|
||||
toastr, and requirejs -->
|
||||
<!-- Loads core Galaxy javascript libraries for a 'generic' entrypoint. -->
|
||||
${ ie.load_default_js() }
|
||||
<!-- This will load code from static/main.js, often used to handle things like login -->
|
||||
${ ie.load_default_app() }
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -217,18 +218,11 @@ We'll continue appending to our ``helloworld.mako`` the HTML code that's actuall
|
||||
var notebook_login_url = 'unused';
|
||||
var notebook_access_url = '${ notebook_access_url }';
|
||||
|
||||
// Load code with require.js
|
||||
${ ie.plugin_require_config() }
|
||||
|
||||
// Load notebook
|
||||
// This will load code from static/helloworld.js, often used to handle
|
||||
// things like Login. The load_notebook function will eventually append
|
||||
// an IFrame to the <div id="main" /> below.
|
||||
requirejs(['galaxy.interactive_environments', 'plugin/helloworld'], function(IES){
|
||||
window.IES = IES
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
// The load_notebook function will eventually append an IFrame to the <div id="main" /> below.
|
||||
IES.load_when_ready(ie_readiness_url, function(){
|
||||
load_notebook(notebook_access_url);
|
||||
});
|
||||
</script>
|
||||
<div id="main" width="100%" height="100%">
|
||||
@@ -262,7 +256,7 @@ authentication of users, so you don't have to worry about it, and can just
|
||||
assume that only the correct user will have access to a given notebook.
|
||||
|
||||
In the ``static/`` directory, we generally create a ``js/`` directory below that,
|
||||
and create a ``{gie}.js`` (so, ``static/js/helloworld.js``) file in there.
|
||||
and create a ``main.js`` file in there.
|
||||
That file will have a function, ``load_notebook`` which will check if the GIE is available,
|
||||
and when it is, display it to the user.
|
||||
|
||||
|
||||
@@ -1107,6 +1107,66 @@ class Cool(H5):
|
||||
return "Cool (HDF5) file (%s)." % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
class MCool(H5):
|
||||
"""
|
||||
Class describing the multi-resolution cool format (https://github.com/mirnylab/cooler)
|
||||
"""
|
||||
|
||||
file_ext = "mcool"
|
||||
|
||||
def sniff(self, filename):
|
||||
"""
|
||||
>>> from galaxy.datatypes.sniff import get_test_fname
|
||||
>>> fname = get_test_fname('matrix.mcool')
|
||||
>>> MCool().sniff(fname)
|
||||
True
|
||||
>>> fname = get_test_fname('matrix.cool')
|
||||
>>> MCool().sniff(fname)
|
||||
False
|
||||
>>> fname = get_test_fname('test.mz5')
|
||||
>>> MCool().sniff(fname)
|
||||
False
|
||||
>>> fname = get_test_fname('wiggle.wig')
|
||||
>>> MCool().sniff(fname)
|
||||
False
|
||||
>>> fname = get_test_fname('biom2_sparse_otu_table_hdf5.biom2')
|
||||
>>> MCool().sniff(fname)
|
||||
False
|
||||
"""
|
||||
|
||||
MAGIC = "HDF5::Cooler"
|
||||
URL = "https://github.com/mirnylab/cooler"
|
||||
|
||||
if super(MCool, self).sniff(filename):
|
||||
keys0 = ['resolutions']
|
||||
with h5py.File(filename, 'r') as handle:
|
||||
if not all(name in handle.keys() for name in keys0):
|
||||
return False
|
||||
res0 = list(handle['resolutions'].keys())[0]
|
||||
keys = ['chroms', 'bins', 'pixels', 'indexes']
|
||||
fmt = handle['resolutions'][res0].attrs.get('format', None)
|
||||
url = handle['resolutions'][res0].attrs.get('format-url', None)
|
||||
if fmt == MAGIC or url == URL:
|
||||
if not all(name in handle['resolutions'][res0].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 = "Multi-resolution 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 "MCool (HDF5) file (%s)." % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
class Scf(Binary):
|
||||
"""Class describing an scf binary sequence file"""
|
||||
edam_format = "format_1632"
|
||||
|
||||
@@ -1030,8 +1030,14 @@ def get_file_peek(file_name, is_multi_byte=False, WIDTH=256, LINE_COUNT=5, skipc
|
||||
:param is_multi_byte: deprecated
|
||||
:type is_multi_byte: bool
|
||||
|
||||
>>> fname = get_test_fname('4.bed')
|
||||
>>> assert get_file_peek(fname, LINE_COUNT=1) == u'chr22\\t30128507\\t31828507\\tuc003bnx.1_cds_2_0_chr22_29227_f\\t0\\t+\\n'
|
||||
>>> def assert_peek_is(file_name, expected, *args, **kwd):
|
||||
... path = get_test_fname(file_name)
|
||||
... peek = get_file_peek(path, *args, **kwd)
|
||||
... assert peek == expected, "%s != %s" % (peek, expected)
|
||||
>>> assert_peek_is('0_nonewline', u'0')
|
||||
>>> assert_peek_is('0.txt', u'0\\n')
|
||||
>>> assert_peek_is('4.bed', u'chr22\\t30128507\\t31828507\\tuc003bnx.1_cds_2_0_chr22_29227_f\\t0\\t+\\n', LINE_COUNT=1)
|
||||
>>> assert_peek_is('1.bed', u'chr1\\t147962192\\t147962580\\tCCDS989.1_cds_0_0_chr1_147962193_r\\t0\\t-\\nchr1\\t147984545\\t147984630\\tCCDS990.1_cds_0_0_chr1_147984546_f\\t0\\t+\\n', LINE_COUNT=2)
|
||||
"""
|
||||
# Set size for file.readline() to a negative number to force it to
|
||||
# read until either a newline or EOF. Needed for datasets with very
|
||||
@@ -1042,20 +1048,27 @@ def get_file_peek(file_name, is_multi_byte=False, WIDTH=256, LINE_COUNT=5, skipc
|
||||
skipchars = []
|
||||
lines = []
|
||||
count = 0
|
||||
|
||||
last_line_break = False
|
||||
with compression_utils.get_fileobj(file_name, "U") as temp:
|
||||
while count < LINE_COUNT:
|
||||
try:
|
||||
line = temp.readline(WIDTH)
|
||||
except UnicodeDecodeError:
|
||||
return "binary file"
|
||||
if not line_wrap:
|
||||
if line.endswith('\n'):
|
||||
line = line[:-1]
|
||||
else:
|
||||
while True:
|
||||
i = temp.read(1)
|
||||
if not i or i == '\n':
|
||||
break
|
||||
if line == "":
|
||||
break
|
||||
last_line_break = False
|
||||
if line.endswith('\n'):
|
||||
line = line[:-1]
|
||||
last_line_break = True
|
||||
elif not line_wrap:
|
||||
while True:
|
||||
i = temp.read(1)
|
||||
if i == '\n':
|
||||
last_line_break = True
|
||||
if not i or i == '\n':
|
||||
break
|
||||
skip_line = False
|
||||
for skipchar in skipchars:
|
||||
if line.startswith(skipchar):
|
||||
@@ -1064,4 +1077,4 @@ def get_file_peek(file_name, is_multi_byte=False, WIDTH=256, LINE_COUNT=5, skipc
|
||||
if not skip_line:
|
||||
lines.append(line)
|
||||
count += 1
|
||||
return '\n'.join(lines)
|
||||
return '\n'.join(lines) + ('\n' if last_line_break else '')
|
||||
|
||||
@@ -14,7 +14,11 @@ import sys
|
||||
import tempfile
|
||||
import zipfile
|
||||
|
||||
from six import StringIO, text_type
|
||||
from six import (
|
||||
PY3,
|
||||
StringIO,
|
||||
text_type,
|
||||
)
|
||||
from six.moves import filter
|
||||
from six.moves.urllib.request import urlopen
|
||||
|
||||
@@ -103,28 +107,40 @@ def stream_to_file(stream, suffix='', prefix='', dir=None, text=False, **kwd):
|
||||
return stream_to_open_named_file(stream, fd, temp_name, **kwd)
|
||||
|
||||
|
||||
def convert_newlines(fname, in_place=True, tmp_dir=None, tmp_prefix="gxupload"):
|
||||
def convert_newlines(fname, in_place=True, tmp_dir=None, tmp_prefix="gxupload", block_size=128 * 1024, regexp=None):
|
||||
"""
|
||||
Converts in place a file from universal line endings
|
||||
to Posix line endings.
|
||||
|
||||
>>> fname = get_test_fname('temp.txt')
|
||||
>>> with open(fname, 'wt') as fh:
|
||||
... _ = fh.write("1 2\\r3 4")
|
||||
>>> convert_newlines(fname, tmp_prefix="gxtest", tmp_dir=tempfile.gettempdir())
|
||||
(2, None)
|
||||
>>> open(fname).read()
|
||||
'1 2\\n3 4\\n'
|
||||
"""
|
||||
fd, temp_name = tempfile.mkstemp(prefix=tmp_prefix, dir=tmp_dir)
|
||||
with io.open(fd, mode="wt", encoding='utf-8') as fp:
|
||||
i = None
|
||||
for i, line in enumerate(io.open(fname, encoding='utf-8')):
|
||||
fp.write("%s\n" % line.rstrip("\r\n"))
|
||||
if i is None:
|
||||
i = 0
|
||||
i = 0
|
||||
if PY3:
|
||||
NEWLINE_BYTE = 10
|
||||
CR_BYTE = 13
|
||||
else:
|
||||
i += 1
|
||||
NEWLINE_BYTE = "\n"
|
||||
CR_BYTE = "\r"
|
||||
with io.open(fd, mode="wb") as fp, io.open(fname, mode="rb") as fi:
|
||||
last_char = None
|
||||
block = fi.read(block_size)
|
||||
last_block = b""
|
||||
while block:
|
||||
if last_char == CR_BYTE and block.startswith(b"\n"):
|
||||
# Last block ended with CR, new block startswith newline.
|
||||
# Since we replace CR with newline in the previous iteration we skip the first byte
|
||||
block = block[1:]
|
||||
if block:
|
||||
last_char = block[-1]
|
||||
block = block.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
|
||||
if regexp:
|
||||
block = b"\t".join(regexp.split(block))
|
||||
fp.write(block)
|
||||
i += block.count(b"\n")
|
||||
last_block = block
|
||||
block = fi.read(block_size)
|
||||
if last_block and last_block[-1] != NEWLINE_BYTE:
|
||||
i += 1
|
||||
fp.write(b"\n")
|
||||
if in_place:
|
||||
shutil.move(temp_name, fname)
|
||||
# Return number of lines in file.
|
||||
@@ -133,47 +149,9 @@ def convert_newlines(fname, in_place=True, tmp_dir=None, tmp_prefix="gxupload"):
|
||||
return (i, temp_name)
|
||||
|
||||
|
||||
def sep2tabs(fname, in_place=True, patt=r"\s+", tmp_dir=None, tmp_prefix="gxupload"):
|
||||
def convert_newlines_sep2tabs(fname, in_place=True, patt=br"[^\S\n]+", tmp_dir=None, tmp_prefix="gxupload"):
|
||||
"""
|
||||
Transforms in place a 'sep' separated file to a tab separated one
|
||||
|
||||
>>> fname = get_test_fname('temp.txt')
|
||||
>>> with open(fname, 'wt') as fh:
|
||||
... _ = fh.write(u"1 2\\n3 4\\n")
|
||||
>>> sep2tabs(fname)
|
||||
(2, None)
|
||||
>>> open(fname).read()
|
||||
'1\\t2\\n3\\t4\\n'
|
||||
"""
|
||||
regexp = re.compile(patt)
|
||||
fd, temp_name = tempfile.mkstemp(prefix=tmp_prefix, dir=tmp_dir)
|
||||
with io.open(fd, mode="wt", encoding='utf-8') as fp:
|
||||
i = None
|
||||
for i, line in enumerate(io.open(fname, encoding='utf-8')):
|
||||
if line.endswith("\r"):
|
||||
line = line.rstrip('\r')
|
||||
elems = regexp.split(line)
|
||||
fp.write(u"%s\r" % '\t'.join(elems))
|
||||
else:
|
||||
line = line.rstrip('\n')
|
||||
elems = regexp.split(line)
|
||||
fp.write(u"%s\n" % '\t'.join(elems))
|
||||
if i is None:
|
||||
i = 0
|
||||
else:
|
||||
i += 1
|
||||
if in_place:
|
||||
shutil.move(temp_name, fname)
|
||||
# Return number of lines in file.
|
||||
return (i, None)
|
||||
else:
|
||||
return (i, temp_name)
|
||||
|
||||
|
||||
def convert_newlines_sep2tabs(fname, in_place=True, patt=r"\s+", tmp_dir=None, tmp_prefix="gxupload"):
|
||||
"""
|
||||
Combines above methods: convert_newlines() and sep2tabs()
|
||||
so that files do not need to be read twice
|
||||
Converts newlines in a file to posix newlines and replaces spaces with tabs.
|
||||
|
||||
>>> fname = get_test_fname('temp.txt')
|
||||
>>> with open(fname, 'wt') as fh:
|
||||
@@ -184,18 +162,7 @@ def convert_newlines_sep2tabs(fname, in_place=True, patt=r"\s+", tmp_dir=None, t
|
||||
'1\\t2\\n3\\t4\\n'
|
||||
"""
|
||||
regexp = re.compile(patt)
|
||||
fd, temp_name = tempfile.mkstemp(prefix=tmp_prefix, dir=tmp_dir)
|
||||
with io.open(fd, mode="wt", encoding='utf-8') as fp:
|
||||
for i, line in enumerate(io.open(fname, encoding='utf-8')):
|
||||
line = line.rstrip('\r\n')
|
||||
elems = regexp.split(line)
|
||||
fp.write(u"%s\n" % '\t'.join(elems))
|
||||
if in_place:
|
||||
shutil.move(temp_name, fname)
|
||||
# Return number of lines in file.
|
||||
return (i + 1, None)
|
||||
else:
|
||||
return (i + 1, temp_name)
|
||||
return convert_newlines(fname, in_place, tmp_dir, tmp_prefix, regexp=regexp)
|
||||
|
||||
|
||||
def iter_headers(fname_or_file_prefix, sep, count=60, comment_designator=None):
|
||||
@@ -474,6 +441,9 @@ def guess_ext(fname, sniff_order, is_binary=False):
|
||||
>>> fname = get_test_fname('1.mtx')
|
||||
>>> guess_ext(fname, sniff_order)
|
||||
'mtx'
|
||||
>>> fname = get_test_fname('1imzml')
|
||||
>>> guess_ext(fname, sniff_order) # This test case is ensuring doesn't throw exception, actual value could change if non-utf encoding handling improves.
|
||||
'data'
|
||||
"""
|
||||
file_prefix = FilePrefix(fname)
|
||||
file_ext = run_sniffers_raw(file_prefix, sniff_order, is_binary)
|
||||
@@ -555,8 +525,9 @@ def zip_single_fileobj(path):
|
||||
class FilePrefix(object):
|
||||
|
||||
def __init__(self, filename):
|
||||
binary = False
|
||||
non_utf8_error = None
|
||||
compressed_format = None
|
||||
contents_header_bytes = None
|
||||
contents_header = None # First MAX_BYTES of the file.
|
||||
truncated = False
|
||||
# A future direction to optimize sniffing even more for sniffers at the top of the list
|
||||
@@ -565,20 +536,23 @@ class FilePrefix(object):
|
||||
# populates contents_header while providing a StringIO-like interface until the file is read
|
||||
# but then would fallback to native string_io()
|
||||
try:
|
||||
compressed_format, f = compression_utils.get_fileobj_raw(filename)
|
||||
compressed_format, f = compression_utils.get_fileobj_raw(filename, "rb")
|
||||
try:
|
||||
contents_header = f.read(SNIFF_PREFIX_BYTES)
|
||||
truncated = len(contents_header) == SNIFF_PREFIX_BYTES
|
||||
contents_header_bytes = f.read(SNIFF_PREFIX_BYTES)
|
||||
truncated = len(contents_header_bytes) == SNIFF_PREFIX_BYTES
|
||||
contents_header = contents_header_bytes.decode("utf-8")
|
||||
finally:
|
||||
f.close()
|
||||
except UnicodeDecodeError:
|
||||
binary = True
|
||||
except UnicodeDecodeError as e:
|
||||
non_utf8_error = e
|
||||
|
||||
self.truncated = truncated
|
||||
self.filename = filename
|
||||
self.binary = binary
|
||||
self.non_utf8_error = non_utf8_error
|
||||
self.binary = non_utf8_error is not None # obviously wrong
|
||||
self.compressed_format = compressed_format
|
||||
self.contents_header = contents_header
|
||||
self.contents_header_bytes = contents_header_bytes
|
||||
self._file_size = None
|
||||
|
||||
@property
|
||||
@@ -588,8 +562,8 @@ class FilePrefix(object):
|
||||
return self._file_size
|
||||
|
||||
def string_io(self):
|
||||
if self.binary:
|
||||
raise Exception("Attempting to create a StringIO object for binary data.")
|
||||
if self.non_utf8_error is not None:
|
||||
raise self.non_utf8_error
|
||||
rval = StringIO(self.contents_header)
|
||||
return rval
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ Tabular datatype
|
||||
from __future__ import absolute_import
|
||||
|
||||
import abc
|
||||
import binascii
|
||||
import csv
|
||||
import logging
|
||||
import os
|
||||
@@ -691,11 +692,11 @@ class BaseVcf(Tabular):
|
||||
MetadataElement(name="viz_filter_cols", desc="Score column for visualization", default=[5], param=metadata.ColumnParameter, optional=True, multiple=True, visible=False)
|
||||
MetadataElement(name="sample_names", default=[], desc="Sample names", readonly=True, visible=False, optional=True, no_value=[])
|
||||
|
||||
def sniff_prefix(self, file_prefix):
|
||||
def _sniff(self, fname_or_file_prefix):
|
||||
# Because this sniffer is run on compressed files that might be BGZF (due to the VcfGz subclass), we should
|
||||
# handle unicode decode errors. This should ultimately be done in get_headers(), but guess_ext() currently
|
||||
# relies on get_headers() raising this exception.
|
||||
headers = get_headers(file_prefix, '\n', count=1)
|
||||
headers = get_headers(fname_or_file_prefix, '\n', count=1)
|
||||
return headers[0][0].startswith("##fileformat=VCF")
|
||||
|
||||
def display_peek(self, dataset):
|
||||
@@ -745,14 +746,29 @@ class BaseVcf(Tabular):
|
||||
class Vcf(BaseVcf):
|
||||
file_ext = 'vcf'
|
||||
|
||||
def sniff_prefix(self, file_prefix):
|
||||
return self._sniff(file_prefix)
|
||||
|
||||
|
||||
class VcfGz(BaseVcf, binary.Binary):
|
||||
# This class name is a misnomer, should be VcfBgzip
|
||||
file_ext = 'vcf_bgzip'
|
||||
compressed = True
|
||||
compressed_format = "gzip"
|
||||
|
||||
MetadataElement(name="tabix_index", desc="Vcf Index File", param=metadata.FileParameter, file_ext="tbi", readonly=True, no_value=None, visible=False, optional=True)
|
||||
|
||||
def sniff(self, filename):
|
||||
if not self._sniff(filename):
|
||||
return False
|
||||
# Check that the file is compressed with bgzip (not gzip), i.e. the
|
||||
# compressed format is BGZF, as explained in
|
||||
# http://samtools.github.io/hts-specs/SAMv1.pdf
|
||||
with open(filename, 'rb') as fh:
|
||||
fh.seek(-28, 2)
|
||||
last28 = fh.read()
|
||||
return binascii.hexlify(last28) == b'1f8b08040000000000ff0600424302001b0003000000000000000000'
|
||||
|
||||
def set_meta(self, dataset, **kwd):
|
||||
super(BaseVcf, self).set_meta(dataset, **kwd)
|
||||
""" Creates the index for the VCF file. """
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,380 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<mzML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0.xsd" xmlns="http://psi.hupo.org/ms/mzml" version="1.1">
|
||||
<cvList count="4">
|
||||
<cv URI="http://ontologies.berkeleybop.org/pato.obo" fullName="Phenotype And Trait Ontology" id="PATO" version="releases/2017-07-10"/>
|
||||
<cv URI="http://ontologies.berkeleybop.org/uo.obo" fullName="Units of Measurement Ontology" id="UO" version="releases/2017-09-25"/>
|
||||
<cv URI="https://raw.githubusercontent.com/hupo-psi/psi-ms-cv/master/psi-ms.obo" fullName="Proteomics Standards Initiative Mass Spectrometry Ontology" id="MS" version="4.1.0"/>
|
||||
<cv URI="https://raw.githubusercontent.com/imzML/imzML/master/imagingMS.obo" fullName="Mass Spectrometry Imaging Ontology" id="IMS" version="1.1.0"/>
|
||||
</cvList>
|
||||
<fileDescription>
|
||||
<fileContent>
|
||||
<cvParam cvRef="MS" accession="MS:1000579" name="MS1 spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000080" name="universally unique identifier" value="9d501bdc53444916b7e97e795b02c856"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000091" name="ibd SHA-1" value="7e8fdb93053915d3edb51b70aa0619ac209964df"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000031" name="processed"/>
|
||||
</fileContent>
|
||||
<sourceFileList count="1">
|
||||
<sourceFile id="sf1" location="C:\Users\Thorsten Schramm\Documents\Promotion\imzML\Website\files\Beispiel-Dateien\Example images\" name="Example.raw">
|
||||
<cvParam cvRef="MS" accession="MS:1000563" name="Thermo RAW format"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000768" name="Thermo nativeID format"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000569" name="SHA-1" value="7623BE263B25FF99FDF017154B86FAB742D4BB0B"/>
|
||||
</sourceFile>
|
||||
</sourceFileList>
|
||||
<contact>
|
||||
<cvParam cvRef="MS" accession="MS:1000586" name="contact name" value="Thorsten Schramm"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000590" name="contact affiliation" value="Institut für Anorganische und Analytische Chemie"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000587" name="contact address" value="Schubertstraße 60, Haus 16, Gießen, Germany"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000589" name="contact email" value="thorsten.schramm@anorg.chemie.uni-.giessen.de"/>
|
||||
</contact>
|
||||
</fileDescription>
|
||||
<referenceableParamGroupList count="4">
|
||||
<referenceableParamGroup id="mzArray">
|
||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000514" name="m/z array" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="intensityArray">
|
||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000515" name="intensity array" unitCvRef="MS" unitAccession="MS:1000131" unitName="number of detector counts"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="scan1">
|
||||
<cvParam cvRef="MS" accession="MS:1000093" name="increasing m/z scan"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000512" name="filter string" value="ITMS - p NSI Full ms [100,00-800,00]"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="spectrum1">
|
||||
<cvParam cvRef="MS" accession="MS:1000579" name="MS1 spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000511" name="ms level" value="0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000129" name="negative scan"/>
|
||||
</referenceableParamGroup>
|
||||
</referenceableParamGroupList>
|
||||
<sampleList count="1">
|
||||
<sample id="sample1" name="Sample1">
|
||||
<cvParam cvRef="MS" accession="MS:1000001" name="sample number" value="1"/>
|
||||
</sample>
|
||||
</sampleList>
|
||||
<softwareList count="2">
|
||||
<software id="Xcalibur" version="2.2">
|
||||
<cvParam cvRef="MS" accession="MS:1000532" name="Xcalibur"/>
|
||||
</software>
|
||||
<software id="TMC" version="1.1 beta">
|
||||
<cvParam cvRef="MS" accession="MS:1000799" name="custom unreleased software tool" value=""/>
|
||||
</software>
|
||||
</softwareList>
|
||||
<scanSettingsList count="1">
|
||||
<scanSettings id="scansettings1">
|
||||
<cvParam cvRef="IMS" accession="IMS:1000401" name="top down"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000413" name="flyback"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000480" name="horizontal line scan"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000491" name="linescan left right"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000042" name="max count of pixels x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000043" name="max count of pixels y" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000044" name="max dimension x" value="300" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000045" name="max dimension y" value="300" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000046" name="pixel size (x)" value="100.0" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000047" name="pixel size y" value="100.0" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
</scanSettings>
|
||||
</scanSettingsList>
|
||||
<instrumentConfigurationList count="1">
|
||||
<instrumentConfiguration id="LTQFTUltra0">
|
||||
<cvParam cvRef="MS" accession="MS:1000557" name="LTQ FT Ultra"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000529" name="instrument serial number" value="none"/>
|
||||
<componentList count="3">
|
||||
<source order="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000073" name="electrospray ionization"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000485" name="nanospray inlet"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000844" name="focus diameter x" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000845" name="focus diameter y" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000846" name="pulse energy" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000847" name="pulse duration" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000848" name="attenuation" value="50.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000850" name="gas laser"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000836" name="dried droplet MALDI matrix preparation"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000835" name="matrix solution concentration" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000834" name="matrix solution" value="DHB"/>
|
||||
</source>
|
||||
<analyzer order="2">
|
||||
<cvParam cvRef="MS" accession="MS:1000264" name="ion trap"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000014" name="accuracy" value="0.0" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
||||
</analyzer>
|
||||
<detector order="3">
|
||||
<cvParam cvRef="MS" accession="MS:1000253" name="electron multiplier"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000120" name="transient recorder"/>
|
||||
</detector>
|
||||
</componentList>
|
||||
<softwareRef ref="Xcalibur"/>
|
||||
</instrumentConfiguration>
|
||||
</instrumentConfigurationList>
|
||||
<dataProcessingList count="2">
|
||||
<dataProcessing id="XcaliburProcessing">
|
||||
<processingMethod softwareRef="Xcalibur" order="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000594" name="low intensity data point removal"/>
|
||||
</processingMethod>
|
||||
</dataProcessing>
|
||||
<dataProcessing id="TMCConversion">
|
||||
<processingMethod softwareRef="TMC" order="2">
|
||||
<cvParam cvRef="MS" accession="MS:1000544" name="Conversion to mzML"/>
|
||||
</processingMethod>
|
||||
</dataProcessing>
|
||||
</dataProcessingList>
|
||||
<run defaultInstrumentConfigurationRef="LTQFTUltra0" defaultSourceFileRef="sf1" id="Experiment01" sampleRef="sample1" startTimeStamp="2009-08-11T15:59:44">
|
||||
<spectrumList count="9" defaultDataProcessingRef="XcaliburProcessing">
|
||||
<spectrum id="Scan=1" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="0">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="121.85039039868471"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="16"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="33612"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=2" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="1">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="182.31835420101888"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="67208"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="100804"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=3" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="2">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="161.8091904482675"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="134400"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="167996"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=4" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="3">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="200.9633277092539"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="201592"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="235188"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=5" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="4">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="135.30584173158496"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="268784"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="302380"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=6" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="5">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="108.39597418421639"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="335976"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="369572"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=7" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="6">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="127.84664447846832"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="403168"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="436764"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=8" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="7">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="168.27018147522492"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="470360"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="503956"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=9" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="8">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="243.5395066031077"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="537552"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="571148"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
</spectrumList>
|
||||
</run>
|
||||
</mzML>
|
||||
@@ -0,0 +1,380 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<mzML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://psi.hupo.org/ms/mzml http://psidev.info/files/ms/mzML/xsd/mzML1.1.0.xsd" xmlns="http://psi.hupo.org/ms/mzml" version="1.1">
|
||||
<cvList count="4">
|
||||
<cv URI="http://ontologies.berkeleybop.org/pato.obo" fullName="Phenotype And Trait Ontology" id="PATO" version="releases/2017-07-10"/>
|
||||
<cv URI="http://ontologies.berkeleybop.org/uo.obo" fullName="Units of Measurement Ontology" id="UO" version="releases/2017-09-25"/>
|
||||
<cv URI="https://raw.githubusercontent.com/hupo-psi/psi-ms-cv/master/psi-ms.obo" fullName="Proteomics Standards Initiative Mass Spectrometry Ontology" id="MS" version="4.1.0"/>
|
||||
<cv URI="https://raw.githubusercontent.com/imzML/imzML/master/imagingMS.obo" fullName="Mass Spectrometry Imaging Ontology" id="IMS" version="1.1.0"/>
|
||||
</cvList>
|
||||
<fileDescription>
|
||||
<fileContent>
|
||||
<cvParam cvRef="MS" accession="MS:1000579" name="MS1 spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000080" name="universally unique identifier" value="9d501bdc53444916b7e97e795b02c856"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000091" name="ibd SHA-1" value="7e8fdb93053915d3edb51b70aa0619ac209964df"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000031" name="processed"/>
|
||||
</fileContent>
|
||||
<sourceFileList count="1">
|
||||
<sourceFile id="sf1" location="C:\Users\Thorsten Schramm\Documents\Promotion\imzML\Website\files\Beispiel-Dateien\Example images\" name="Example.raw">
|
||||
<cvParam cvRef="MS" accession="MS:1000563" name="Thermo RAW format"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000768" name="Thermo nativeID format"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000569" name="SHA-1" value="7623BE263B25FF99FDF017154B86FAB742D4BB0B"/>
|
||||
</sourceFile>
|
||||
</sourceFileList>
|
||||
<contact>
|
||||
<cvParam cvRef="MS" accession="MS:1000586" name="contact name" value="Thorsten Schramm"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000590" name="contact affiliation" value="Institut für Anorganische und Analytische Chemie"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000587" name="contact address" value="Schubertstraße 60, Haus 16, Gießen, Germany"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000589" name="contact email" value="thorsten.schramm@anorg.chemie.uni-.giessen.de"/>
|
||||
</contact>
|
||||
</fileDescription>
|
||||
<referenceableParamGroupList count="4">
|
||||
<referenceableParamGroup id="mzArray">
|
||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000514" name="m/z array" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="intensityArray">
|
||||
<cvParam cvRef="MS" accession="MS:1000576" name="no compression"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000515" name="intensity array" unitCvRef="MS" unitAccession="MS:1000131" unitName="number of detector counts"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000101" name="external data" value="true"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000521" name="32-bit float"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="scan1">
|
||||
<cvParam cvRef="MS" accession="MS:1000093" name="increasing m/z scan"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000512" name="filter string" value="ITMS - p NSI Full ms [100,00-800,00]"/>
|
||||
</referenceableParamGroup>
|
||||
<referenceableParamGroup id="spectrum1">
|
||||
<cvParam cvRef="MS" accession="MS:1000579" name="MS1 spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000511" name="ms level" value="0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000128" name="profile spectrum"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000129" name="negative scan"/>
|
||||
</referenceableParamGroup>
|
||||
</referenceableParamGroupList>
|
||||
<sampleList count="1">
|
||||
<sample id="sample1" name="Sample1">
|
||||
<cvParam cvRef="MS" accession="MS:1000001" name="sample number" value="1"/>
|
||||
</sample>
|
||||
</sampleList>
|
||||
<softwareList count="2">
|
||||
<software id="Xcalibur" version="2.2">
|
||||
<cvParam cvRef="MS" accession="MS:1000532" name="Xcalibur"/>
|
||||
</software>
|
||||
<software id="TMC" version="1.1 beta">
|
||||
<cvParam cvRef="MS" accession="MS:1000799" name="custom unreleased software tool" value=""/>
|
||||
</software>
|
||||
</softwareList>
|
||||
<scanSettingsList count="1">
|
||||
<scanSettings id="scansettings1">
|
||||
<cvParam cvRef="IMS" accession="IMS:1000401" name="top down"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000413" name="flyback"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000480" name="horizontal line scan"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000491" name="linescan left right"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000042" name="max count of pixels x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000043" name="max count of pixels y" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000044" name="max dimension x" value="300" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000045" name="max dimension y" value="300" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000046" name="pixel size (x)" value="100.0" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000047" name="pixel size y" value="100.0" unitCvRef="UO" unitAccession="UO:0000017" unitName="micrometer"/>
|
||||
</scanSettings>
|
||||
</scanSettingsList>
|
||||
<instrumentConfigurationList count="1">
|
||||
<instrumentConfiguration id="LTQFTUltra0">
|
||||
<cvParam cvRef="MS" accession="MS:1000557" name="LTQ FT Ultra"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000529" name="instrument serial number" value="none"/>
|
||||
<componentList count="3">
|
||||
<source order="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000073" name="electrospray ionization"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000485" name="nanospray inlet"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000844" name="focus diameter x" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000845" name="focus diameter y" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000846" name="pulse energy" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000847" name="pulse duration" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000848" name="attenuation" value="50.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000850" name="gas laser"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000836" name="dried droplet MALDI matrix preparation"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000835" name="matrix solution concentration" value="10.0"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000834" name="matrix solution" value="DHB"/>
|
||||
</source>
|
||||
<analyzer order="2">
|
||||
<cvParam cvRef="MS" accession="MS:1000264" name="ion trap"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000014" name="accuracy" value="0.0" unitCvRef="MS" unitAccession="MS:1000040" unitName="m/z"/>
|
||||
</analyzer>
|
||||
<detector order="3">
|
||||
<cvParam cvRef="MS" accession="MS:1000253" name="electron multiplier"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000120" name="transient recorder"/>
|
||||
</detector>
|
||||
</componentList>
|
||||
<softwareRef ref="Xcalibur"/>
|
||||
</instrumentConfiguration>
|
||||
</instrumentConfigurationList>
|
||||
<dataProcessingList count="2">
|
||||
<dataProcessing id="XcaliburProcessing">
|
||||
<processingMethod softwareRef="Xcalibur" order="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000594" name="low intensity data point removal"/>
|
||||
</processingMethod>
|
||||
</dataProcessing>
|
||||
<dataProcessing id="TMCConversion">
|
||||
<processingMethod softwareRef="TMC" order="2">
|
||||
<cvParam cvRef="MS" accession="MS:1000544" name="Conversion to mzML"/>
|
||||
</processingMethod>
|
||||
</dataProcessing>
|
||||
</dataProcessingList>
|
||||
<run defaultInstrumentConfigurationRef="LTQFTUltra0" defaultSourceFileRef="sf1" id="Experiment01" sampleRef="sample1" startTimeStamp="2009-08-11T15:59:44">
|
||||
<spectrumList count="9" defaultDataProcessingRef="XcaliburProcessing">
|
||||
<spectrum id="Scan=1" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="0">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="121.85039039868471"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="16"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="33612"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=2" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="1">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="182.31835420101888"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="67208"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="100804"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=3" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="2">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="161.8091904482675"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="1"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="134400"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="167996"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=4" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="3">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="200.9633277092539"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="201592"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="235188"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=5" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="4">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="135.30584173158496"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="268784"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="302380"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=6" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="5">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="108.39597418421639"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="2"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="335976"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="369572"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=7" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="6">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="127.84664447846832"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="403168"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="436764"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=8" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="7">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="168.27018147522492"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="2"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="470360"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="503956"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
<spectrum id="Scan=9" defaultArrayLength="0" dataProcessingRef="XcaliburProcessing" sourceFileRef="sf1" index="8">
|
||||
<referenceableParamGroupRef ref="spectrum1"/>
|
||||
<cvParam cvRef="MS" accession="MS:1000285" name="total ion current" value="243.5395066031077"/>
|
||||
<scanList count="1">
|
||||
<cvParam cvRef="MS" accession="MS:1000795" name="no combination"/>
|
||||
<scan instrumentConfigurationRef="LTQFTUltra0">
|
||||
<referenceableParamGroupRef ref="scan1"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000050" name="position x" value="3"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000051" name="position y" value="3"/>
|
||||
</scan>
|
||||
</scanList>
|
||||
<binaryDataArrayList count="2">
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="mzArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="537552"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
<binaryDataArray encodedLength="0">
|
||||
<referenceableParamGroupRef ref="intensityArray"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000103" name="external array length" value="8399"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000102" name="external offset" value="571148"/>
|
||||
<cvParam cvRef="IMS" accession="IMS:1000104" name="external encoded length" value="33596"/>
|
||||
<binary />
|
||||
</binaryDataArray>
|
||||
</binaryDataArrayList>
|
||||
</spectrum>
|
||||
</spectrumList>
|
||||
</run>
|
||||
</mzML>
|
||||
Binary file not shown.
Binary file not shown.
@@ -34,20 +34,46 @@ class ConditionalDependencies(object):
|
||||
|
||||
def parse_configs(self):
|
||||
self.config = load_app_properties(config_file=self.config_file)
|
||||
job_conf_xml = self.config.get(
|
||||
"job_config_file",
|
||||
join(dirname(self.config_file), 'job_conf.xml'))
|
||||
try:
|
||||
for plugin in ElementTree.parse(job_conf_xml).find('plugins').findall('plugin'):
|
||||
if 'load' in plugin.attrib:
|
||||
self.job_runners.append(plugin.attrib['load'])
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
try:
|
||||
for plugin in ElementTree.parse(job_conf_xml).findall('.//destination/param[@id="rules_module"]'):
|
||||
self.job_rule_modules.append(plugin.text)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
def load_job_config_dict(job_conf_dict):
|
||||
for runner in job_conf_dict.get("runners"):
|
||||
if "load" in runner:
|
||||
self.job_runners.append(runner.get("load"))
|
||||
if "rules_module" in runner:
|
||||
self.job_rule_modules.append(plugin.text)
|
||||
if "params" in runner:
|
||||
runner_params = runner["params"]
|
||||
if "rules_module" in runner_params:
|
||||
self.job_rule_modules.append(plugin.text)
|
||||
|
||||
if "job_config" in self.config:
|
||||
load_job_config_dict(self.config.get("job_config"))
|
||||
else:
|
||||
job_conf_path = self.config.get(
|
||||
"job_config_file",
|
||||
join(dirname(self.config_file), 'job_conf.xml'))
|
||||
if '.xml' in job_conf_path:
|
||||
try:
|
||||
try:
|
||||
for plugin in ElementTree.parse(job_conf_path).find('plugins').findall('plugin'):
|
||||
if 'load' in plugin.attrib:
|
||||
self.job_runners.append(plugin.attrib['load'])
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
try:
|
||||
for plugin in ElementTree.parse(job_conf_path).findall('.//destination/param[@id="rules_module"]'):
|
||||
self.job_rule_modules.append(plugin.text)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
except ElementTree.ParseError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
job_conf_dict = yaml.safe_load(job_conf_path)
|
||||
load_job_config_dict(job_conf_dict)
|
||||
except (OSError, IOError):
|
||||
pass
|
||||
|
||||
object_store_conf_xml = self.config.get(
|
||||
"object_store_config_file",
|
||||
join(dirname(self.config_file), 'object_store_conf.xml'))
|
||||
|
||||
@@ -36,7 +36,7 @@ cachetools==3.1.0
|
||||
certifi==2019.3.9
|
||||
cffi==1.12.3
|
||||
chardet==3.0.4
|
||||
cheetah3==3.2.1
|
||||
cheetah3==3.2.2
|
||||
cliff==2.14.1
|
||||
cloudauthz==0.2.0
|
||||
cloudbridge==2.0.0
|
||||
|
||||
+296
-128
@@ -20,6 +20,7 @@ from tempfile import NamedTemporaryFile
|
||||
from xml.etree import ElementTree
|
||||
|
||||
import six
|
||||
import yaml
|
||||
from pulsar.client.staging import COMMAND_VERSION_FILENAME
|
||||
|
||||
import galaxy
|
||||
@@ -46,7 +47,7 @@ log = logging.getLogger(__name__)
|
||||
# that import Galaxy internals - but it shouldn't be used in Galaxy's code
|
||||
# itself.
|
||||
TOOL_PROVIDED_JOB_METADATA_FILE = 'galaxy.json'
|
||||
TOOL_PROVIDED_JOB_METADATA_KEYS = ['name', 'info', 'dbkey']
|
||||
TOOL_PROVIDED_JOB_METADATA_KEYS = ['name', 'info', 'dbkey', 'created_from_basename']
|
||||
|
||||
# Override with config.default_job_shell.
|
||||
DEFAULT_JOB_SHELL = '/bin/bash'
|
||||
@@ -80,10 +81,6 @@ class JobDestination(Bunch):
|
||||
|
||||
super(JobDestination, self).__init__(**kwds)
|
||||
|
||||
# Store tags as a list
|
||||
if self.tags is not None:
|
||||
self['tags'] = [x.strip() for x in self.tags.split(',')]
|
||||
|
||||
|
||||
class JobToolConfiguration(Bunch):
|
||||
"""
|
||||
@@ -112,6 +109,139 @@ def config_exception(e, file):
|
||||
return Exception(message)
|
||||
|
||||
|
||||
def job_config_xml_to_dict(config, root):
|
||||
config_dict = {}
|
||||
|
||||
runners = {}
|
||||
config_dict["runners"] = runners
|
||||
|
||||
# Parser plugins section populate 'runners' and 'dynamic' in config_dict.
|
||||
plugins = root.find('plugins')
|
||||
if plugins is not None:
|
||||
for plugin in ConfiguresHandlers._findall_with_required(plugins, 'plugin', ('id', 'type', 'load')):
|
||||
if plugin.get('type') == 'runner':
|
||||
workers = plugin.get('workers', plugins.get('workers', JobConfiguration.DEFAULT_NWORKERS))
|
||||
runner_kwds = JobConfiguration.get_params(config, plugin)
|
||||
plugin_id = plugin.get('id')
|
||||
runner_info = dict(id=plugin_id,
|
||||
load=plugin.get('load'),
|
||||
workers=int(workers),
|
||||
kwds=runner_kwds)
|
||||
runners[plugin_id] = runner_info
|
||||
else:
|
||||
log.error('Unknown plugin type: %s' % plugin.get('type'))
|
||||
|
||||
for plugin in ConfiguresHandlers._findall_with_required(plugins, 'plugin', ('id', 'type')):
|
||||
if plugin.get('id') == 'dynamic' and plugin.get('type') == 'runner':
|
||||
config_dict["dynamic"] = JobConfiguration.get_params(config, plugin)
|
||||
|
||||
handling_config_dict = ConfiguresHandlers.xml_to_dict(config, root.find("handlers"))
|
||||
config_dict["handling"] = handling_config_dict
|
||||
|
||||
# Parse destinations
|
||||
environments = []
|
||||
|
||||
destinations = root.find('destinations')
|
||||
for destination in ConfiguresHandlers._findall_with_required(destinations, 'destination', ('id', 'runner')):
|
||||
destination_id = destination.get('id')
|
||||
destination_metrics = destination.get("metrics", None)
|
||||
|
||||
environment = {"id": destination_id}
|
||||
|
||||
metrics_to_dict = {"src": "default"}
|
||||
if destination_metrics:
|
||||
if not util.asbool(destination_metrics):
|
||||
metrics_to_dict = {"src": "disabled"}
|
||||
else:
|
||||
metrics_to_dict = {"src": "path", "path": destination_metrics}
|
||||
else:
|
||||
metrics_elements = ConfiguresHandlers._findall_with_required(destination, 'job_metrics', ())
|
||||
if metrics_elements:
|
||||
metrics_to_dict = {"src": "xml_element", 'xml_element': metrics_elements[0]}
|
||||
|
||||
environment["metrics"] = metrics_to_dict
|
||||
|
||||
params = JobConfiguration.get_params(config, destination)
|
||||
# TODO: handle enabled/disabled in configure_from
|
||||
environment['params'] = params
|
||||
environment['env'] = JobConfiguration.get_envs(destination)
|
||||
destination_resubmits = JobConfiguration.get_resubmits(destination)
|
||||
if destination_resubmits:
|
||||
environment['resubmit'] = destination_resubmits
|
||||
# TODO: handle empty resubmits defaults in configure_from
|
||||
|
||||
runner = destination.get('runner')
|
||||
if runner:
|
||||
environment['runner'] = runner
|
||||
|
||||
tags = destination.get('tags')
|
||||
# Store tags as a list
|
||||
if tags is not None:
|
||||
tags = [x.strip() for x in tags.split(',')]
|
||||
environment['tags'] = tags
|
||||
|
||||
environments.append(environment)
|
||||
|
||||
config_dict['execution'] = {
|
||||
'environments': environments,
|
||||
}
|
||||
default_destination = ConfiguresHandlers.get_xml_default(config, destinations)
|
||||
if default_destination:
|
||||
config_dict['execution']['default'] = default_destination
|
||||
|
||||
resources_config_dict = {}
|
||||
resource_groups = {}
|
||||
|
||||
# Parse resources...
|
||||
resources = root.find('resources')
|
||||
if resources is not None:
|
||||
default_resource_group = resources.get("default", None)
|
||||
if default_resource_group:
|
||||
resources_config_dict["default"] = default_resource_group
|
||||
|
||||
for group in ConfiguresHandlers._findall_with_required(resources, 'group'):
|
||||
group_id = group.get('id')
|
||||
fields_str = group.get('fields', None) or group.text or ''
|
||||
fields = [f for f in fields_str.split(",") if f]
|
||||
resource_groups[group_id] = fields
|
||||
|
||||
resources_config_dict["groups"] = resource_groups
|
||||
config_dict["resources"] = resources_config_dict
|
||||
|
||||
# Parse tool mappings
|
||||
tools = root.find('tools')
|
||||
config_dict['tools'] = []
|
||||
if tools is not None:
|
||||
for tool in ConfiguresHandlers._findall_with_required(tools, 'tool'):
|
||||
# There can be multiple definitions with identical ids, but different params
|
||||
tool_mapping_conf = {}
|
||||
for key in ['handler', 'destination', 'id', 'resources']:
|
||||
value = tool.get(key)
|
||||
if value:
|
||||
if key == "destination":
|
||||
key = "environment"
|
||||
tool_mapping_conf[key] = value
|
||||
tool_mapping_conf["params"] = JobConfiguration.get_params(config, tool)
|
||||
config_dict['tools'].append(tool_mapping_conf)
|
||||
|
||||
limits_config = []
|
||||
limits = root.find('limits')
|
||||
if limits is not None:
|
||||
for limit in JobConfiguration._findall_with_required(limits, 'limit', ('type',)):
|
||||
limit_dict = {}
|
||||
for key in ['type', 'tag', 'id', 'window']:
|
||||
if key == 'type' and key.startswith('destination_'):
|
||||
key = 'environment_%s' % key[len("destination_"):]
|
||||
value = limit.get(key)
|
||||
if value:
|
||||
limit_dict[key] = value
|
||||
limit_dict['value'] = limit.text
|
||||
limits_config.append(limit_dict)
|
||||
|
||||
config_dict['limits'] = limits_config
|
||||
return config_dict
|
||||
|
||||
|
||||
class JobConfiguration(ConfiguresHandlers):
|
||||
"""A parser and interface to advanced job management features.
|
||||
|
||||
@@ -162,7 +292,7 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
default_resubmit_condition = self.app.config.default_job_resubmission_condition
|
||||
if default_resubmit_condition:
|
||||
default_resubmits.append(dict(
|
||||
destination=None,
|
||||
environment=None,
|
||||
condition=default_resubmit_condition,
|
||||
handler=None,
|
||||
delay=None,
|
||||
@@ -171,10 +301,26 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
|
||||
self.__parse_resource_parameters()
|
||||
# Initialize the config
|
||||
job_config_file = self.app.config.job_config_file
|
||||
try:
|
||||
tree = load(job_config_file)
|
||||
self.__parse_job_conf_xml(tree)
|
||||
if 'job_config' in self.app.config.config_dict:
|
||||
job_config_dict = self.app.config.config_dict["job_config"]
|
||||
else:
|
||||
job_config_file = self.app.config.job_config_file
|
||||
if '.xml' in job_config_file:
|
||||
tree = load(job_config_file)
|
||||
job_config_dict = self.__parse_job_conf_xml(tree)
|
||||
else:
|
||||
with open(job_config_file, "r") as f:
|
||||
job_config_dict = yaml.safe_load(f)
|
||||
|
||||
# Load tasks if configured
|
||||
if self.app.config.use_tasked_jobs:
|
||||
job_config_dict["runners"]["tasks"] = dict(id='tasks', load='tasks', workers=self.app.config.local_task_queue_workers, kwds={})
|
||||
|
||||
self._configure_from_dict(job_config_dict)
|
||||
|
||||
log.debug('Done loading job configuration')
|
||||
|
||||
except IOError:
|
||||
log.warning('Job configuration "%s" does not exist, using default job configuration',
|
||||
self.app.config.job_config_file)
|
||||
@@ -182,43 +328,33 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
except Exception as e:
|
||||
raise config_exception(e, job_config_file)
|
||||
|
||||
def __parse_job_conf_xml(self, tree):
|
||||
"""Loads the new-style job configuration from options in the job config file (by default, job_conf.xml).
|
||||
|
||||
:param tree: Object representing the root ``<job_conf>`` object in the job config file.
|
||||
:type tree: ``xml.etree.ElementTree.Element``
|
||||
"""
|
||||
root = tree.getroot()
|
||||
log.debug('Loading job configuration from %s' % self.app.config.job_config_file)
|
||||
|
||||
# Parse job plugins
|
||||
plugins = root.find('plugins')
|
||||
if plugins is not None:
|
||||
for plugin in self._findall_with_required(plugins, 'plugin', ('id', 'type', 'load')):
|
||||
if plugin.get('type') == 'runner':
|
||||
workers = plugin.get('workers', plugins.get('workers', JobConfiguration.DEFAULT_NWORKERS))
|
||||
runner_kwds = self.__get_params(plugin)
|
||||
if not self.__is_enabled(runner_kwds):
|
||||
def _configure_from_dict(self, job_config_dict):
|
||||
for runner_id, runner_info in job_config_dict["runners"].items():
|
||||
if "kwds" not in runner_info:
|
||||
# convert all 'extra' parameters into kwds, allows defining a runner
|
||||
# with a flat dictionary.
|
||||
kwds = {}
|
||||
for key, value in runner_info.items():
|
||||
if key in ['id', 'load', 'workers']:
|
||||
continue
|
||||
runner_info = dict(id=plugin.get('id'),
|
||||
load=plugin.get('load'),
|
||||
workers=int(workers),
|
||||
kwds=runner_kwds)
|
||||
self.runner_plugins.append(runner_info)
|
||||
else:
|
||||
log.error('Unknown plugin type: %s' % plugin.get('type'))
|
||||
for plugin in self._findall_with_required(plugins, 'plugin', ('id', 'type')):
|
||||
if plugin.get('id') == 'dynamic' and plugin.get('type') == 'runner':
|
||||
self.dynamic_params = self.__get_params(plugin)
|
||||
kwds[key] = value
|
||||
runner_info["kwds"] = kwds
|
||||
|
||||
# Load tasks if configured
|
||||
if self.app.config.use_tasked_jobs:
|
||||
self.runner_plugins.append(dict(id='tasks', load='tasks', workers=self.app.config.local_task_queue_workers))
|
||||
if not self.__is_enabled(runner_info.get("kwds")):
|
||||
continue
|
||||
runner_info["id"] = runner_id
|
||||
if runner_id == "dynamic":
|
||||
log.warning('Deprecated treatment of dynamic running configuration as an actual job runner.')
|
||||
self.dynamic_params = runner_info["kwds"]
|
||||
continue
|
||||
self.runner_plugins.append(runner_info)
|
||||
if "dynamic" in job_config_dict:
|
||||
self.dynamic_params = job_config_dict.get("dynamic", None)
|
||||
|
||||
# Parse handlers
|
||||
handlers_conf = root.find('handlers')
|
||||
self._init_handler_assignment_methods(handlers_conf)
|
||||
self._init_handlers(handlers_conf)
|
||||
handling_config_dict = job_config_dict.get("handling", {})
|
||||
self._init_handler_assignment_methods(handling_config_dict)
|
||||
self._init_handlers(handling_config_dict)
|
||||
if not self.handler_assignment_methods_configured:
|
||||
self._set_default_handler_assignment_methods()
|
||||
else:
|
||||
@@ -227,38 +363,51 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
for tag, handlers in [(t, h) for t, h in self.handlers.items() if isinstance(h, list)]:
|
||||
log.info("Tag [%s] handlers: %s", tag, ', '.join(handlers))
|
||||
|
||||
# Parse destinations
|
||||
destinations = root.find('destinations')
|
||||
# Parse environments
|
||||
job_metrics = self.app.job_metrics
|
||||
for destination in self._findall_with_required(destinations, 'destination', ('id', 'runner')):
|
||||
id = destination.get('id')
|
||||
destination_metrics = destination.get("metrics", None)
|
||||
if destination_metrics:
|
||||
if not util.asbool(destination_metrics):
|
||||
# disable
|
||||
job_metrics.set_destination_instrumenter(id, None)
|
||||
else:
|
||||
metrics_conf_path = self.app.config.resolve_path(destination_metrics)
|
||||
job_metrics.set_destination_conf_file(id, metrics_conf_path)
|
||||
else:
|
||||
metrics_elements = self._findall_with_required(destination, 'job_metrics', ())
|
||||
if metrics_elements:
|
||||
job_metrics.set_destination_conf_element(id, metrics_elements[0])
|
||||
job_destination = JobDestination(**dict(destination.items()))
|
||||
params = self.__get_params(destination)
|
||||
if not self.__is_enabled(params):
|
||||
execution_dict = job_config_dict.get('execution', {})
|
||||
environments = execution_dict.get("environments", [])
|
||||
enviroment_iter = map(lambda e: (e["id"], e), environments) if isinstance(environments, list) else environments.items()
|
||||
for environment_id, environment_dict in enviroment_iter:
|
||||
metrics = environment_dict.get("metrics") or {"src": "default"}
|
||||
metrics_src = metrics.get("src") or "default"
|
||||
if metrics_src != "default":
|
||||
# customized metrics for this environment.
|
||||
if metrics_src == "disabled":
|
||||
job_metrics.set_destination_instrumenter(environment_id, None)
|
||||
elif metrics_src == "xml_element":
|
||||
metrics_element = metrics.get("xml_element")
|
||||
job_metrics.set_destination_conf_element(environment_id, metrics_element)
|
||||
elif metrics_src == "path":
|
||||
metrics_conf_path = self.app.config.resolve_path(metrics.get("path"))
|
||||
job_metrics.set_destination_conf_file(environment_id, metrics_conf_path)
|
||||
|
||||
destination_kwds = {}
|
||||
|
||||
params = environment_dict.get("params")
|
||||
if params is None:
|
||||
# Treat the excess keys in the environment as the destination parameters
|
||||
# allowing a flat configuration of these things.
|
||||
params = {}
|
||||
for key, value in environment_dict.items():
|
||||
if key in ['id', 'tags', 'runner', 'shell', 'env', 'resubmit']:
|
||||
continue
|
||||
params[key] = value
|
||||
environment_dict["params"] = params
|
||||
|
||||
for key in ['tags', 'runner', 'shell', 'env', 'resubmit', 'params']:
|
||||
if key in environment_dict:
|
||||
destination_kwds[key] = environment_dict[key]
|
||||
destination_kwds["id"] = environment_id
|
||||
job_destination = JobDestination(**destination_kwds)
|
||||
if not self.__is_enabled(job_destination.params):
|
||||
continue
|
||||
|
||||
job_destination['params'] = params
|
||||
job_destination['env'] = self.__get_envs(destination)
|
||||
destination_resubmits = self.__get_resubmits(destination)
|
||||
if destination_resubmits:
|
||||
resubmits = destination_resubmits
|
||||
else:
|
||||
if not job_destination.resubmit:
|
||||
resubmits = self.default_resubmits
|
||||
job_destination["resubmit"] = resubmits
|
||||
job_destination.resubmit = resubmits
|
||||
|
||||
self.destinations[id] = (job_destination,)
|
||||
self.destinations[environment_id] = (job_destination,)
|
||||
if job_destination.tags is not None:
|
||||
for tag in job_destination.tags:
|
||||
if tag not in self.destinations:
|
||||
@@ -266,29 +415,30 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
self.destinations[tag].append(job_destination)
|
||||
|
||||
# Determine the default destination
|
||||
self.default_destination_id = self._get_default(
|
||||
self.app.config, destinations, list(self.destinations.keys()), auto=True)
|
||||
self.default_destination_id = self._ensure_default_set(execution_dict.get("default"), list(self.destinations.keys()), auto=True)
|
||||
|
||||
# Parse resources...
|
||||
resources = root.find('resources')
|
||||
if resources is not None:
|
||||
self.default_resource_group = resources.get("default", None)
|
||||
for group in self._findall_with_required(resources, 'group'):
|
||||
id = group.get('id')
|
||||
fields_str = group.get('fields', None) or group.text or ''
|
||||
fields = [f for f in fields_str.split(",") if f]
|
||||
self.resource_groups[id] = fields
|
||||
# Read in resources
|
||||
resources = job_config_dict.get("resources", {})
|
||||
self.default_resource_group = resources.get("default", None)
|
||||
for group_id, fields in resources.get("groups", {}).items():
|
||||
self.resource_groups[group_id] = fields
|
||||
|
||||
# Parse tool mappings
|
||||
tools = root.find('tools')
|
||||
if tools is not None:
|
||||
for tool in self._findall_with_required(tools, 'tool'):
|
||||
# There can be multiple definitions with identical ids, but different params
|
||||
id = tool.get('id').lower().rstrip('/')
|
||||
if id not in self.tools:
|
||||
self.tools[id] = list()
|
||||
self.tools[id].append(JobToolConfiguration(**dict(tool.items())))
|
||||
self.tools[id][-1]['params'] = self.__get_params(tool)
|
||||
tools = job_config_dict.get('tools', [])
|
||||
for tool in tools:
|
||||
tool_id = tool.get('id').lower().rstrip('/')
|
||||
if tool_id not in self.tools:
|
||||
self.tools[tool_id] = list()
|
||||
params = tool.get("params")
|
||||
if params is None:
|
||||
params = {}
|
||||
for key, value in tool.items():
|
||||
if key in ["environment", "handler", "id"]:
|
||||
continue
|
||||
params[key] = value
|
||||
tool["params"] = params
|
||||
if "environment" in tool:
|
||||
tool["destination"] = tool.pop("environment")
|
||||
self.tools[tool_id].append(JobToolConfiguration(**dict(tool.items())))
|
||||
|
||||
types = dict(registered_user_concurrent_jobs=int,
|
||||
anonymous_user_concurrent_jobs=int,
|
||||
@@ -297,26 +447,28 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
output_size=util.size_to_bytes)
|
||||
|
||||
# Parse job limits
|
||||
limits = root.find('limits')
|
||||
if limits is not None:
|
||||
for limit in self._findall_with_required(limits, 'limit', ('type',)):
|
||||
type = limit.get('type')
|
||||
# concurrent_jobs renamed to destination_user_concurrent_jobs in job_conf.xml
|
||||
if type in ('destination_user_concurrent_jobs', 'concurrent_jobs', 'destination_total_concurrent_jobs'):
|
||||
id = limit.get('tag', None) or limit.get('id')
|
||||
if type == 'destination_total_concurrent_jobs':
|
||||
self.limits.destination_total_concurrent_jobs[id] = int(limit.text)
|
||||
else:
|
||||
self.limits.destination_user_concurrent_jobs[id] = int(limit.text)
|
||||
elif type == 'total_walltime':
|
||||
self.limits.total_walltime["window"] = (
|
||||
int(limit.get('window')) or 30
|
||||
)
|
||||
self.limits.total_walltime["raw"] = (
|
||||
types.get(type, str)(limit.text)
|
||||
)
|
||||
elif limit.text:
|
||||
self.limits.__dict__[type] = types.get(type, str)(limit.text)
|
||||
for limit_dict in job_config_dict.get("limits", []):
|
||||
limit_type = limit_dict.get('type')
|
||||
if limit_type.startswith("environment_"):
|
||||
limit_type = 'destination_%s' % limit_type[len("environment_"):]
|
||||
|
||||
limit_value = limit_dict.get("value")
|
||||
# concurrent_jobs renamed to destination_user_concurrent_jobs in job_conf.xml
|
||||
if limit_type in ('destination_user_concurrent_jobs', 'concurrent_jobs', 'destination_total_concurrent_jobs'):
|
||||
id = limit_dict.get('tag', None) or limit_dict.get('id')
|
||||
if limit_type == 'destination_total_concurrent_jobs':
|
||||
self.limits.destination_total_concurrent_jobs[id] = int(limit_value)
|
||||
else:
|
||||
self.limits.destination_user_concurrent_jobs[id] = int(limit_value)
|
||||
elif limit_type == 'total_walltime':
|
||||
self.limits.total_walltime["window"] = (
|
||||
int(limit_dict.get('window')) or 30
|
||||
)
|
||||
self.limits.total_walltime["raw"] = (
|
||||
types.get(limit_type, str)(limit_value)
|
||||
)
|
||||
elif limit_value:
|
||||
self.limits.__dict__[limit_type] = types.get(limit_type, str)(limit_value)
|
||||
|
||||
if self.limits.walltime is not None:
|
||||
h, m, s = [int(v) for v in self.limits.walltime.split(':')]
|
||||
@@ -329,13 +481,23 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
0, s, 0, 0, m, h
|
||||
)
|
||||
|
||||
log.debug('Done loading job configuration')
|
||||
def __parse_job_conf_xml(self, tree):
|
||||
"""Loads the new-style job configuration from options in the job config file (by default, job_conf.xml).
|
||||
|
||||
def _parse_handler(self, handler_id, handler_element):
|
||||
for plugin in handler_element.findall('plugin'):
|
||||
:param tree: Object representing the root ``<job_conf>`` object in the job config file.
|
||||
:type tree: ``xml.etree.ElementTree.Element``
|
||||
"""
|
||||
root = tree.getroot()
|
||||
log.debug('Loading job configuration from %s' % self.app.config.job_config_file)
|
||||
|
||||
job_config_dict = job_config_xml_to_dict(self.app.config, root)
|
||||
return job_config_dict
|
||||
|
||||
def _parse_handler(self, handler_id, process_dict):
|
||||
for plugin_id in process_dict.get("plugins") or []:
|
||||
if handler_id not in self.handler_runner_plugins:
|
||||
self.handler_runner_plugins[handler_id] = []
|
||||
self.handler_runner_plugins[handler_id].append(plugin.get('id'))
|
||||
self.handler_runner_plugins[handler_id].append(plugin_id)
|
||||
|
||||
def __set_default_job_conf(self):
|
||||
# Run jobs locally
|
||||
@@ -383,14 +545,8 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
def __parse_resource_parameters(self):
|
||||
self.resource_parameters = util.parse_resource_parameters(self.app.config.job_resource_params_file)
|
||||
|
||||
def __get_params(self, parent):
|
||||
"""Parses any child <param> tags in to a dictionary suitable for persistence.
|
||||
|
||||
:param parent: Parent element in which to find child <param> tags.
|
||||
:type parent: ``xml.etree.ElementTree.Element``
|
||||
|
||||
:returns: dict
|
||||
"""
|
||||
@staticmethod
|
||||
def get_params(config, parent):
|
||||
rval = {}
|
||||
for param in parent.findall('param'):
|
||||
key = param.get('id')
|
||||
@@ -406,12 +562,23 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
param_value = os.environ.get(environ_var, param_value)
|
||||
elif 'from_config' in param.attrib:
|
||||
config_val = param.attrib['from_config']
|
||||
param_value = self.app.config.config_dict.get(config_val, param_value)
|
||||
param_value = config.config_dict.get(config_val, param_value)
|
||||
|
||||
rval[key] = param_value
|
||||
return rval
|
||||
|
||||
def __get_envs(self, parent):
|
||||
def __get_params(self, parent):
|
||||
"""Parses any child <param> tags in to a dictionary suitable for persistence.
|
||||
|
||||
:param parent: Parent element in which to find child <param> tags.
|
||||
:type parent: ``xml.etree.ElementTree.Element``
|
||||
|
||||
:returns: dict
|
||||
"""
|
||||
return JobConfiguration.get_params(self.app.config, parent)
|
||||
|
||||
@staticmethod
|
||||
def get_envs(parent):
|
||||
"""Parses any child <env> tags in to a dictionary suitable for persistence.
|
||||
|
||||
:param parent: Parent element in which to find child <env> tags.
|
||||
@@ -430,7 +597,8 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
))
|
||||
return rval
|
||||
|
||||
def __get_resubmits(self, parent):
|
||||
@staticmethod
|
||||
def get_resubmits(parent):
|
||||
"""Parses any child <resubmit> tags in to a dictionary suitable for persistence.
|
||||
|
||||
:param parent: Parent element in which to find child <resubmit> tags.
|
||||
@@ -442,7 +610,7 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
for resubmit in parent.findall('resubmit'):
|
||||
rval.append(dict(
|
||||
condition=resubmit.get('condition'),
|
||||
destination=resubmit.get('destination'),
|
||||
environment=resubmit.get('destination'),
|
||||
handler=resubmit.get('handler'),
|
||||
delay=resubmit.get('delay'),
|
||||
))
|
||||
@@ -451,7 +619,7 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
def __is_enabled(self, params):
|
||||
"""Check for an enabled parameter - pop it out - and return as boolean."""
|
||||
enabled = True
|
||||
if "enabled" in params:
|
||||
if "enabled" in (params or {}):
|
||||
raw_enabled = params.pop("enabled")
|
||||
enabled = util.asbool(raw_enabled)
|
||||
|
||||
@@ -596,7 +764,7 @@ class JobConfiguration(ConfiguresHandlers):
|
||||
log.warning("Job runner classes must be subclassed from BaseJobRunner, %s has bases: %s" % (id, runner_class.__bases__))
|
||||
continue
|
||||
try:
|
||||
rval[id] = runner_class(self.app, runner['workers'], **runner.get('kwds', {}))
|
||||
rval[id] = runner_class(self.app, runner.get('workers', JobConfiguration.DEFAULT_NWORKERS), **runner.get('kwds', {}))
|
||||
except TypeError:
|
||||
log.exception("Job runner '%s:%s' has not been converted to a new-style runner or encountered TypeError on load",
|
||||
module_name, class_name)
|
||||
|
||||
@@ -146,10 +146,9 @@ def check_output(stdio_regexes, stdio_exit_codes, stdout, stderr, tool_exit_code
|
||||
if stderr:
|
||||
state = DETECTED_JOB_STATE.GENERIC_ERROR
|
||||
|
||||
if DETECTED_JOB_STATE != DETECTED_JOB_STATE.OK and stderr:
|
||||
if stderr:
|
||||
peak = stderr[0:ERROR_PEAK]
|
||||
log.debug("job failed, standard error is - [%s]" % peak)
|
||||
if state != DETECTED_JOB_STATE.OK:
|
||||
peak = stderr[0:ERROR_PEAK] if stderr else ""
|
||||
log.debug("job failed, detected state %s, standard error is - [%s]" % (state, peak))
|
||||
except Exception:
|
||||
log.exception("Job state check encountered unexpected exception; assuming execution successful")
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ from time import sleep
|
||||
|
||||
import packaging.version
|
||||
import pulsar.core
|
||||
import six
|
||||
import yaml
|
||||
from pulsar.client import (
|
||||
build_client_manager,
|
||||
@@ -449,7 +450,7 @@ class PulsarJobRunner(AsynchronousJobRunner):
|
||||
user = job_wrapper.get_job().user
|
||||
if user:
|
||||
for key, value in params.items():
|
||||
if value:
|
||||
if value and isinstance(value, six.string_types):
|
||||
params[key] = model.User.expand_user_properties(user, value)
|
||||
|
||||
env = getattr(job_wrapper.job_destination, "env", [])
|
||||
|
||||
@@ -28,13 +28,9 @@ SLURM_MEMORY_LIMIT_EXCEEDED_MSG = 'slurmstepd: error: Exceeded job memory limit'
|
||||
SLURM_MEMORY_LIMIT_EXCEEDED_PARTIAL_WARNINGS = [': Exceeded job memory limit at some point.',
|
||||
': Exceeded step memory limit at some point.']
|
||||
SLURM_MEMORY_LIMIT_SCAN_SIZE = 16 * 1024 * 1024 # 16MB
|
||||
SLURM_UNABLE_TO_ADD_TASK_TO_MEMORY_CG_MSG_RE = re.compile(r"""slurmstepd: error: task/cgroup: unable to add task\[pid=\d+\] to memory cg '\(null\)'$""")
|
||||
SLURM_UNABLE_TO_CREATE_CGROUP_MSG_RE = re.compile(r"""slurmstepd: error: xcgroup_instantiate: unable to create cgroup '[^']+' : No space left on device$""")
|
||||
SLURM_UNABLE_TO_INSTANCIATE_CGROUP_MSG_RE = re.compile(r"""slurmstepd: error: jobacct_gather/cgroup: unable to instanciate (job|user) \d+ memory cgroup$""")
|
||||
SLURM_CGROUP_RE = re.compile(r"""slurmstepd: .*cgroup.*$""")
|
||||
SLURM_TOP_WARNING_RES = (
|
||||
SLURM_UNABLE_TO_ADD_TASK_TO_MEMORY_CG_MSG_RE,
|
||||
SLURM_UNABLE_TO_CREATE_CGROUP_MSG_RE,
|
||||
SLURM_UNABLE_TO_INSTANCIATE_CGROUP_MSG_RE
|
||||
SLURM_CGROUP_RE,
|
||||
)
|
||||
|
||||
# These messages are returned to the user
|
||||
|
||||
@@ -97,7 +97,8 @@ def _handle_resubmit_definitions(resubmit_definitions, app, job_runner, job_stat
|
||||
else:
|
||||
job_log_prefix = "(%s)" % (job_state.job_wrapper.job_id)
|
||||
|
||||
destination = resubmit['destination']
|
||||
# Is destination needed here, might these be serialized to the database?
|
||||
destination = resubmit.get('environment') or resubmit.get('destination')
|
||||
log.info("%s Job will be resubmitted to '%s' because %s at "
|
||||
"the '%s' destination",
|
||||
job_log_prefix,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import functools
|
||||
import logging
|
||||
import os
|
||||
|
||||
import requests
|
||||
from beaker.cache import CacheManager
|
||||
@@ -26,8 +25,8 @@ class CitationsManager(object):
|
||||
citation_collection.add(citation)
|
||||
return citation_collection.citations
|
||||
|
||||
def parse_citation(self, citation_elem, tool_directory):
|
||||
return parse_citation(citation_elem, tool_directory, self)
|
||||
def parse_citation(self, citation_elem):
|
||||
return parse_citation(citation_elem, self)
|
||||
|
||||
def _get_tool(self, tool_id):
|
||||
tool = self.app.toolbox.get_tool(tool_id)
|
||||
@@ -55,10 +54,9 @@ class DoiCache(object):
|
||||
return self._cache.get(key=doi, createfunc=createfunc)
|
||||
|
||||
|
||||
def parse_citation(elem, directory, citation_manager):
|
||||
""" Parse an abstract citation entry from the specified XML element.
|
||||
The directory parameter should be used to find external files for this
|
||||
citation.
|
||||
def parse_citation(elem, citation_manager):
|
||||
"""
|
||||
Parse an abstract citation entry from the specified XML element.
|
||||
"""
|
||||
citation_type = elem.attrib.get('type', None)
|
||||
citation_class = CITATION_CLASSES.get(citation_type, None)
|
||||
@@ -66,7 +64,7 @@ def parse_citation(elem, directory, citation_manager):
|
||||
log.warning("Unknown or unspecified citation type: %s" % citation_type)
|
||||
return None
|
||||
try:
|
||||
citation = citation_class(elem, directory, citation_manager)
|
||||
citation = citation_class(elem, citation_manager)
|
||||
except Exception as e:
|
||||
raise Exception("Invalid citation of type '%s' with content '%s': %s" % (citation_type, elem.text, e))
|
||||
return citation
|
||||
@@ -118,16 +116,8 @@ class BaseCitation(object):
|
||||
|
||||
class BibtexCitation(BaseCitation):
|
||||
|
||||
def __init__(self, elem, directory, citation_manager):
|
||||
bibtex_file = elem.attrib.get("file", None)
|
||||
if bibtex_file:
|
||||
raw_bibtex = open(os.path.join(directory, bibtex_file), "r").read()
|
||||
else:
|
||||
raw_bibtex = elem.text.strip()
|
||||
self._set_raw_bibtex(raw_bibtex)
|
||||
|
||||
def _set_raw_bibtex(self, raw_bibtex):
|
||||
self.raw_bibtex = raw_bibtex
|
||||
def __init__(self, elem, citation_manager):
|
||||
self.raw_bibtex = elem.text.strip()
|
||||
|
||||
def to_bibtex(self):
|
||||
return self.raw_bibtex
|
||||
@@ -136,7 +126,7 @@ class BibtexCitation(BaseCitation):
|
||||
class DoiCitation(BaseCitation):
|
||||
BIBTEX_UNSET = object()
|
||||
|
||||
def __init__(self, elem, directory, citation_manager):
|
||||
def __init__(self, elem, citation_manager):
|
||||
self.__doi = elem.text.strip()
|
||||
self.doi_cache = citation_manager.doi_cache
|
||||
self.raw_bibtex = DoiCitation.BIBTEX_UNSET
|
||||
|
||||
@@ -300,7 +300,8 @@ class HDASerializer( # datasets._UnflattenedMetadataDatasetAssociationSerialize
|
||||
|
||||
'annotation',
|
||||
|
||||
'api_type'
|
||||
'api_type',
|
||||
'created_from_basename',
|
||||
], include_keys_from='summary')
|
||||
|
||||
self.add_view('extended', [
|
||||
@@ -354,7 +355,8 @@ class HDASerializer( # datasets._UnflattenedMetadataDatasetAssociationSerialize
|
||||
# TODO: to DatasetAssociationSerializer
|
||||
'accessible' : lambda i, k, user=None, **c: self.manager.is_accessible(i, user, **c),
|
||||
'api_type' : lambda *a, **c: 'file',
|
||||
'type' : lambda *a, **c: 'file'
|
||||
'type' : lambda *a, **c: 'file',
|
||||
'created_from_basename' : lambda i, k, **c: i.created_from_basename,
|
||||
})
|
||||
|
||||
def serialize(self, hda, keys, user=None, **context):
|
||||
|
||||
@@ -143,7 +143,7 @@ class PortableDirectoryMetadataGenerator(MetadataCollectionStrategy):
|
||||
script_path = os.path.join(metadata_dir, "set.py")
|
||||
with open(script_path, "w") as f:
|
||||
f.write(SET_METADATA_SCRIPT)
|
||||
return 'pwd; python "metadata/set.py"'
|
||||
return 'python "metadata/set.py"'
|
||||
else:
|
||||
# return args to galaxy_ext.metadata.set_metadata required to build
|
||||
return ''
|
||||
|
||||
@@ -42,6 +42,7 @@ from sqlalchemy.orm import (
|
||||
)
|
||||
from sqlalchemy.schema import UniqueConstraint
|
||||
|
||||
import galaxy.exceptions
|
||||
import galaxy.model.metadata
|
||||
import galaxy.model.orm.now
|
||||
import galaxy.model.tags
|
||||
@@ -2156,8 +2157,10 @@ class Dataset(StorableObject, RepresentById):
|
||||
def get_file_name(self):
|
||||
if not self.external_filename:
|
||||
assert self.object_store is not None, "Object Store has not been initialized for dataset %s" % self.id
|
||||
filename = self.object_store.get_filename(self)
|
||||
return filename
|
||||
if self.object_store.exists(self):
|
||||
return self.object_store.get_filename(self)
|
||||
else:
|
||||
return ''
|
||||
else:
|
||||
filename = self.external_filename
|
||||
# Make filename absolute
|
||||
@@ -2175,10 +2178,16 @@ class Dataset(StorableObject, RepresentById):
|
||||
# actual database column so if SA instantiates this object - the
|
||||
# attribute won't exist yet.
|
||||
if not getattr(self, "external_extra_files_path", None):
|
||||
return self.object_store.get_filename(self, dir_only=True, extra_dir=self._extra_files_rel_path)
|
||||
if self.object_store.exists(self, dir_only=True, extra_dir=self._extra_files_rel_path):
|
||||
return self.object_store.get_filename(self, dir_only=True, extra_dir=self._extra_files_rel_path)
|
||||
return ''
|
||||
else:
|
||||
return os.path.abspath(self.external_extra_files_path)
|
||||
|
||||
def create_extra_files_path(self):
|
||||
if not self.extra_files_path_exists():
|
||||
self.object_store.create(self, dir_only=True, extra_dir=self._extra_files_rel_path)
|
||||
|
||||
def set_extra_files_path(self, extra_files_path):
|
||||
if not extra_files_path:
|
||||
self.external_extra_files_path = None
|
||||
@@ -2266,11 +2275,12 @@ class Dataset(StorableObject, RepresentById):
|
||||
def full_delete(self):
|
||||
"""Remove the file and extra files, marks deleted and purged"""
|
||||
# os.unlink( self.file_name )
|
||||
self.object_store.delete(self)
|
||||
try:
|
||||
self.object_store.delete(self)
|
||||
except galaxy.exceptions.ObjectNotFound:
|
||||
pass
|
||||
if self.object_store.exists(self, extra_dir=self._extra_files_rel_path, dir_only=True):
|
||||
self.object_store.delete(self, entire_dir=True, extra_dir=self._extra_files_rel_path, dir_only=True)
|
||||
# if os.path.exists( self.extra_files_path ):
|
||||
# shutil.rmtree( self.extra_files_path )
|
||||
# TODO: purge metadata files
|
||||
self.deleted = True
|
||||
self.purged = True
|
||||
@@ -2510,6 +2520,16 @@ class DatasetInstance(object):
|
||||
"""Detects whether there is any data"""
|
||||
return self.dataset.has_data()
|
||||
|
||||
def get_created_from_basename(self):
|
||||
return self.dataset.created_from_basename
|
||||
|
||||
def set_created_from_basename(self, created_from_basename):
|
||||
if self.dataset.created_from_basename is not None:
|
||||
raise Exception("Underlying dataset already has a created_from_basename set.")
|
||||
self.dataset.created_from_basename = created_from_basename
|
||||
|
||||
created_from_basename = property(get_created_from_basename, set_created_from_basename)
|
||||
|
||||
def get_raw_data(self):
|
||||
"""Returns the full data. To stream it open the file_name and read/write as needed"""
|
||||
return self.datatype.get_raw_data(self)
|
||||
@@ -3393,6 +3413,7 @@ class LibraryDataset(RepresentById):
|
||||
state=ldda.state,
|
||||
name=ldda.name,
|
||||
file_name=ldda.file_name,
|
||||
created_from_basename=ldda.created_from_basename,
|
||||
uploaded_by=ldda.user.email,
|
||||
message=ldda.message,
|
||||
date_uploaded=ldda.create_time.isoformat(),
|
||||
@@ -3545,7 +3566,8 @@ class LibraryDatasetDatasetAssociation(DatasetInstance, HasName, RepresentById):
|
||||
data_type=ldda.datatype.__class__.__module__ + '.' + ldda.datatype.__class__.__name__,
|
||||
genome_build=ldda.dbkey,
|
||||
misc_info=ldda.info,
|
||||
misc_blurb=ldda.blurb)
|
||||
misc_blurb=ldda.blurb,
|
||||
created_from_basename=ldda.created_from_basename)
|
||||
if ldda.dataset.uuid is None:
|
||||
rval['uuid'] = None
|
||||
else:
|
||||
|
||||
@@ -263,6 +263,7 @@ model.Dataset.table = Table(
|
||||
Column("object_store_id", TrimmedString(255), index=True),
|
||||
Column("external_filename", TEXT),
|
||||
Column("_extra_files_path", TEXT),
|
||||
Column("created_from_basename", TEXT),
|
||||
Column('file_size', Numeric(15, 0)),
|
||||
Column('total_size', Numeric(15, 0)),
|
||||
Column('uuid', UUIDType()))
|
||||
|
||||
@@ -6,9 +6,10 @@ from __future__ import print_function
|
||||
|
||||
import logging
|
||||
|
||||
from sqlalchemy import Column, MetaData, Table
|
||||
from sqlalchemy import Column, MetaData
|
||||
|
||||
from galaxy.model.custom_types import UUIDType
|
||||
from galaxy.model.migrate.versions.util import add_column, drop_column
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -19,14 +20,8 @@ def upgrade(migrate_engine):
|
||||
metadata.bind = migrate_engine
|
||||
metadata.reflect()
|
||||
|
||||
metadata_file_table = Table("metadata_file", metadata, autoload=True)
|
||||
|
||||
try:
|
||||
uuid_column = Column('uuid', UUIDType())
|
||||
uuid_column.create(metadata_file_table)
|
||||
assert uuid_column is metadata_file_table.c.uuid
|
||||
except Exception:
|
||||
log.exception("Adding column 'uuid' to `MetadataFile` table failed.")
|
||||
uuid_column = Column('uuid', UUIDType())
|
||||
add_column(uuid_column, 'metadata_file', metadata)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
@@ -34,10 +29,4 @@ def downgrade(migrate_engine):
|
||||
metadata.bind = migrate_engine
|
||||
metadata.reflect()
|
||||
|
||||
metadata_file_table = Table("metadata_file", metadata, autoload=True)
|
||||
|
||||
try:
|
||||
column = metadata_file_table.c.uuid
|
||||
column.drop()
|
||||
except Exception:
|
||||
log.exception("Dropping 'uuid' column from `metadata_file` table failed.")
|
||||
drop_column('uuid', 'metadata_file', metadata)
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Adds created_from_basename to dataset.
|
||||
"""
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from sqlalchemy import Column, MetaData, TEXT
|
||||
|
||||
from galaxy.model.migrate.versions.util import add_column, drop_column
|
||||
|
||||
now = datetime.datetime.utcnow
|
||||
log = logging.getLogger(__name__)
|
||||
metadata = MetaData()
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
metadata.bind = migrate_engine
|
||||
print(__doc__)
|
||||
metadata.reflect()
|
||||
|
||||
created_from_basename_column = Column("created_from_basename", TEXT, default=None)
|
||||
add_column(created_from_basename_column, 'dataset', metadata)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
metadata.bind = migrate_engine
|
||||
metadata.reflect()
|
||||
|
||||
drop_column('created_from_basename', 'dataset', metadata)
|
||||
@@ -55,6 +55,7 @@ class ModelPersistenceContext(object):
|
||||
tag_list=[],
|
||||
sources=[],
|
||||
hashes=[],
|
||||
created_from_basename=None,
|
||||
):
|
||||
sa_session = self.sa_session
|
||||
|
||||
@@ -116,6 +117,9 @@ class ModelPersistenceContext(object):
|
||||
hash_object.hash_value = hash_dict["hash_value"]
|
||||
primary_data.dataset.hashes.append(hash_object)
|
||||
|
||||
if created_from_basename is not None:
|
||||
primary_data.created_from_basename = created_from_basename
|
||||
|
||||
self.flush()
|
||||
|
||||
if tag_list:
|
||||
@@ -204,6 +208,7 @@ class ModelPersistenceContext(object):
|
||||
|
||||
sources = discovered_file.match.sources
|
||||
hashes = discovered_file.match.hashes
|
||||
created_from_basename = discovered_file.match.created_from_basename
|
||||
|
||||
dataset = self.create_dataset(
|
||||
ext=ext,
|
||||
@@ -217,6 +222,7 @@ class ModelPersistenceContext(object):
|
||||
tag_list=tag_list,
|
||||
sources=sources,
|
||||
hashes=hashes,
|
||||
created_from_basename=created_from_basename,
|
||||
)
|
||||
log.debug(
|
||||
"(%s) Created dynamic collection dataset for path [%s] with element identifier [%s] for output [%s] %s",
|
||||
@@ -475,6 +481,8 @@ def persist_elements_to_folder(model_persistence_context, elements, library_fold
|
||||
|
||||
sources = fields_match.sources
|
||||
hashes = fields_match.hashes
|
||||
created_from_basename = fields_match.created_from_basename
|
||||
|
||||
model_persistence_context.create_dataset(
|
||||
ext=ext,
|
||||
designation=designation,
|
||||
@@ -487,6 +495,7 @@ def persist_elements_to_folder(model_persistence_context, elements, library_fold
|
||||
link_data=link_data,
|
||||
sources=sources,
|
||||
hashes=hashes,
|
||||
created_from_basename=created_from_basename,
|
||||
)
|
||||
|
||||
|
||||
@@ -517,6 +526,8 @@ def persist_hdas(elements, model_persistence_context):
|
||||
|
||||
sources = fields_match.sources
|
||||
hashes = fields_match.hashes
|
||||
created_from_basename = fields_match.created_from_basename
|
||||
|
||||
dataset = model_persistence_context.create_dataset(
|
||||
ext=ext,
|
||||
designation=designation,
|
||||
@@ -529,6 +540,7 @@ def persist_hdas(elements, model_persistence_context):
|
||||
primary_data=primary_dataset,
|
||||
sources=sources,
|
||||
hashes=hashes,
|
||||
created_from_basename=created_from_basename,
|
||||
)
|
||||
dataset.raw_set_dataset_state('ok')
|
||||
if not hda_id:
|
||||
@@ -701,6 +713,10 @@ class JsonCollectedDatasetMatch(object):
|
||||
def hashes(self):
|
||||
return self.as_dict.get("hashes", [])
|
||||
|
||||
@property
|
||||
def created_from_basename(self):
|
||||
return self.as_dict.get("created_from_basename")
|
||||
|
||||
|
||||
class RegexCollectedDatasetMatch(JsonCollectedDatasetMatch):
|
||||
|
||||
|
||||
@@ -467,7 +467,10 @@ class DiskObjectStore(ObjectStore):
|
||||
# construct and return hashed path
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
return self._construct_path(obj, **kwargs)
|
||||
path = self._construct_path(obj, **kwargs)
|
||||
if not os.path.exists(path):
|
||||
raise ObjectNotFound
|
||||
return path
|
||||
|
||||
def update_from_file(self, obj, file_name=None, create=False, **kwargs):
|
||||
"""`create` parameter is not used in this implementation."""
|
||||
|
||||
@@ -5,13 +5,10 @@ This parallelizes the task over available cores using multiprocessing.
|
||||
Code mostly taken form CloudBioLinux.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import functools
|
||||
import glob
|
||||
import multiprocessing
|
||||
import os
|
||||
import subprocess
|
||||
from multiprocessing.pool import IMapIterator
|
||||
import threading
|
||||
|
||||
try:
|
||||
import boto
|
||||
@@ -20,13 +17,6 @@ except ImportError:
|
||||
boto = None
|
||||
|
||||
|
||||
def map_wrap(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(args):
|
||||
return f(*args)
|
||||
return wrapper
|
||||
|
||||
|
||||
def mp_from_ids(s3server, mp_id, mp_keyname, mp_bucketname):
|
||||
"""Get the multipart upload from the bucket and multipart IDs.
|
||||
|
||||
@@ -51,7 +41,6 @@ def mp_from_ids(s3server, mp_id, mp_keyname, mp_bucketname):
|
||||
return mp
|
||||
|
||||
|
||||
@map_wrap
|
||||
def transfer_part(s3server, mp_id, mp_keyname, mp_bucketname, i, part):
|
||||
"""Transfer a part of a multipart upload. Designed to be run in parallel.
|
||||
"""
|
||||
@@ -64,8 +53,6 @@ def transfer_part(s3server, mp_id, mp_keyname, mp_bucketname, i, part):
|
||||
def multipart_upload(s3server, bucket, s3_key_name, tarball, mb_size):
|
||||
"""Upload large files using Amazon's multipart upload functionality.
|
||||
"""
|
||||
cores = multiprocessing.cpu_count()
|
||||
|
||||
def split_file(in_file, mb_size, split_num=5):
|
||||
prefix = os.path.join(os.path.dirname(in_file),
|
||||
"%sS3PART" % (os.path.basename(s3_key_name)))
|
||||
@@ -80,29 +67,11 @@ def multipart_upload(s3server, bucket, s3_key_name, tarball, mb_size):
|
||||
mp = bucket.initiate_multipart_upload(s3_key_name,
|
||||
reduced_redundancy=s3server['use_rr'])
|
||||
|
||||
with multimap(cores) as pmap:
|
||||
for _ in pmap(transfer_part, ((s3server, mp.id, mp.key_name, mp.bucket_name, i, part)
|
||||
for (i, part) in
|
||||
enumerate(split_file(tarball, mb_size, cores)))):
|
||||
pass
|
||||
for (i, part) in enumerate(split_file(tarball, mb_size)):
|
||||
t = threading.Thread(
|
||||
target=transfer_part,
|
||||
args=(s3server, mp.id, mp.key_name, mp.bucket_name, i, part))
|
||||
t.start()
|
||||
t.join()
|
||||
|
||||
mp.complete_upload()
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def multimap(cores=None):
|
||||
"""Provide multiprocessing imap like function.
|
||||
|
||||
The context manager handles setting up the pool, worked around interrupt issues
|
||||
and terminating the pool on completion.
|
||||
"""
|
||||
if cores is None:
|
||||
cores = max(multiprocessing.cpu_count() - 1, 1)
|
||||
|
||||
def wrapper(func):
|
||||
def wrap(self, timeout=None):
|
||||
return func(self, timeout=timeout if timeout is not None else 1e100)
|
||||
return wrap
|
||||
IMapIterator.next = wrapper(IMapIterator.next)
|
||||
pool = multiprocessing.Pool(cores)
|
||||
yield pool.imap
|
||||
pool.terminate()
|
||||
|
||||
@@ -464,6 +464,7 @@ class Tool(Dictifiable):
|
||||
self.guid = guid
|
||||
self.old_id = None
|
||||
self.version = None
|
||||
self.python_template_version = None
|
||||
self._lineage = None
|
||||
self.dependencies = []
|
||||
# populate toolshed repository info, if available
|
||||
@@ -643,6 +644,14 @@ class Tool(Dictifiable):
|
||||
message = template % (self.id, self.profile)
|
||||
raise Exception(message)
|
||||
|
||||
self.python_template_version = tool_source.parse_python_template_version()
|
||||
if self.python_template_version is None:
|
||||
# If python_template_version not specified we assume tools with profile versions >= 19.05 are python 3 ready
|
||||
if self.profile >= 19.05:
|
||||
self.python_template_version = '3.5'
|
||||
else:
|
||||
self.python_template_version = '2.7'
|
||||
|
||||
# Get the (user visible) name of the tool
|
||||
self.name = tool_source.parse_name()
|
||||
if not self.name and dynamic:
|
||||
@@ -1065,7 +1074,7 @@ class Tool(Dictifiable):
|
||||
if citation_elem.tag != "citation":
|
||||
pass
|
||||
if hasattr(self.app, 'citations_manager'):
|
||||
citation = self.app.citations_manager.parse_citation(citation_elem, self.tool_dir)
|
||||
citation = self.app.citations_manager.parse_citation(citation_elem)
|
||||
if citation:
|
||||
citations.append(citation)
|
||||
return citations
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from json import dumps
|
||||
|
||||
@@ -377,7 +378,8 @@ class DefaultToolAction(object):
|
||||
wrapped_params.params,
|
||||
inp_data,
|
||||
inp_dataset_collections,
|
||||
input_ext
|
||||
input_ext,
|
||||
python_template_version=tool.python_template_version,
|
||||
)
|
||||
create_datasets = True
|
||||
dataset = None
|
||||
@@ -391,6 +393,10 @@ class DefaultToolAction(object):
|
||||
break
|
||||
|
||||
data = app.model.HistoryDatasetAssociation(extension=ext, dataset=dataset, create_dataset=create_datasets, flush=False)
|
||||
if create_datasets:
|
||||
from_work_dir = output.from_work_dir
|
||||
if from_work_dir is not None:
|
||||
data.dataset.created_from_basename = os.path.basename(from_work_dir)
|
||||
if hidden is None:
|
||||
hidden = output.hidden
|
||||
if not hidden and dataset_collection_elements is not None: # Mapping over a collection - hide datasets
|
||||
@@ -744,7 +750,7 @@ class DefaultToolAction(object):
|
||||
if output.label:
|
||||
params['tool'] = tool
|
||||
params['on_string'] = on_text
|
||||
return fill_template(output.label, context=params)
|
||||
return fill_template(output.label, context=params, python_template_version=tool.python_template_version)
|
||||
else:
|
||||
return self._get_default_data_name(dataset, tool, on_text=on_text, trans=trans, incoming=incoming, history=history, params=params, job_params=job_params)
|
||||
|
||||
@@ -761,7 +767,7 @@ class DefaultToolAction(object):
|
||||
if output.actions:
|
||||
for action in output.actions.actions:
|
||||
if action.tag == "metadata" and action.default:
|
||||
metadata_new_value = fill_template(action.default, context=params).split(",")
|
||||
metadata_new_value = fill_template(action.default, context=params, python_template_version=tool.python_template_version).split(",")
|
||||
dataset.metadata.__setattr__(str(action.name), metadata_new_value)
|
||||
|
||||
def _get_default_data_name(self, dataset, tool, on_text=None, trans=None, incoming=None, history=None, params=None, job_params=None, **kwd):
|
||||
@@ -924,7 +930,7 @@ def get_ext_or_implicit_ext(hda):
|
||||
return hda.ext
|
||||
|
||||
|
||||
def determine_output_format(output, parameter_context, input_datasets, input_dataset_collections, random_input_ext):
|
||||
def determine_output_format(output, parameter_context, input_datasets, input_dataset_collections, random_input_ext, python_template_version='3'):
|
||||
""" Determines the output format for a dataset based on an abstract
|
||||
description of the output (galaxy.tools.parser.ToolOutput), the parameter
|
||||
wrappers, a map of the input datasets (name => HDA), and the last input
|
||||
@@ -986,7 +992,7 @@ def determine_output_format(output, parameter_context, input_datasets, input_dat
|
||||
if '$' not in check:
|
||||
# allow a simple name or more complex specifications
|
||||
check = '${%s}' % check
|
||||
if str(fill_template(check, context=parameter_context)) == when_elem.get('value', None):
|
||||
if fill_template(check, context=parameter_context, python_template_version=python_template_version) == when_elem.get('value', None):
|
||||
ext = when_elem.get('format', ext)
|
||||
except Exception: # bad tag input value; possibly referencing a param within a different conditional when block or other nonexistent grouping construct
|
||||
continue
|
||||
|
||||
@@ -108,6 +108,7 @@ def _fetch_target(upload_config, target):
|
||||
dbkey = item.get("dbkey", "?")
|
||||
requested_ext = item.get("ext", "auto")
|
||||
info = item.get("info", None)
|
||||
created_from_basename = item.get("created_from_basename", None)
|
||||
tags = item.get("tags", [])
|
||||
object_id = item.get("object_id", None)
|
||||
link_data_only = upload_config.link_data_only
|
||||
@@ -162,6 +163,8 @@ def _fetch_target(upload_config, target):
|
||||
rval["object_id"] = object_id
|
||||
if tags:
|
||||
rval["tags"] = tags
|
||||
if created_from_basename:
|
||||
rval["created_from_basename"] = created_from_basename
|
||||
return rval
|
||||
|
||||
elements = elements_tree_map(_resolve_src, items)
|
||||
|
||||
@@ -206,7 +206,9 @@ class ContainerRegistry(object):
|
||||
if self.enable_beta_mulled_containers:
|
||||
default_resolvers.extend([
|
||||
CachedMulledDockerContainerResolver(self.app_info, namespace="biocontainers"),
|
||||
CachedMulledDockerContainerResolver(self.app_info, namespace="local"),
|
||||
CachedMulledSingularityContainerResolver(self.app_info, namespace="biocontainers"),
|
||||
CachedMulledSingularityContainerResolver(self.app_info, namespace="local"),
|
||||
MulledDockerContainerResolver(self.app_info, namespace="biocontainers"),
|
||||
MulledSingularityContainerResolver(self.app_info, namespace="biocontainers"),
|
||||
BuildMulledDockerContainerResolver(self.app_info),
|
||||
|
||||
@@ -469,7 +469,7 @@ class ToolEvaluator(object):
|
||||
return
|
||||
try:
|
||||
# Substituting parameters into the command
|
||||
command_line = fill_template(command, context=param_dict)
|
||||
command_line = fill_template(command, context=param_dict, python_template_version=self.tool.python_template_version)
|
||||
cleaned_command_line = []
|
||||
# Remove leading and trailing whitespace from each line for readability.
|
||||
for line in command_line.split('\n'):
|
||||
@@ -575,7 +575,7 @@ class ToolEvaluator(object):
|
||||
|
||||
def __write_workdir_file(self, config_filename, content, context, is_template=True):
|
||||
if is_template:
|
||||
value = fill_template(content, context=context)
|
||||
value = fill_template(content, context=context, python_template_version=self.tool.python_template_version)
|
||||
else:
|
||||
value = unicodify(content)
|
||||
with io.open(config_filename, "w", encoding='utf-8') as f:
|
||||
|
||||
@@ -316,6 +316,7 @@ def collect_primary_datasets(job_context, output, input_ext):
|
||||
extra_files_path = new_primary_datasets_attributes.get('extra_files', None)
|
||||
if extra_files_path:
|
||||
extra_files_path_joined = os.path.join(job_working_directory, extra_files_path)
|
||||
primary_data.dataset.create_extra_files_path()
|
||||
for root, dirs, files in os.walk(extra_files_path_joined):
|
||||
extra_dir = os.path.join(primary_data.extra_files_path, root.replace(extra_files_path_joined, '', 1).lstrip(os.path.sep))
|
||||
extra_dir = os.path.normpath(extra_dir)
|
||||
|
||||
@@ -150,6 +150,9 @@ class CwlToolSource(ToolSource):
|
||||
def parse_profile(self):
|
||||
return "16.04"
|
||||
|
||||
def parse_python_template_version(self):
|
||||
return '3.5'
|
||||
|
||||
|
||||
class CwlPageSource(PageSource):
|
||||
|
||||
|
||||
@@ -218,6 +218,12 @@ class ToolSource(object):
|
||||
""" Return tool profile version as Galaxy major e.g. 16.01 or 16.04.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def parse_python_template_version(self):
|
||||
"""
|
||||
Return minimum python version that the tool template has been developed against.
|
||||
"""
|
||||
|
||||
def macro_paths(self):
|
||||
return []
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import traceback
|
||||
import uuid
|
||||
from math import isinf
|
||||
|
||||
import packaging.version
|
||||
|
||||
from galaxy.tools.deps import requirements
|
||||
from galaxy.util import string_as_bool, xml_text, xml_to_string
|
||||
from galaxy.util.odict import odict
|
||||
@@ -483,6 +485,12 @@ class XmlToolSource(ToolSource):
|
||||
# - Enable buggy interpreter attribute.
|
||||
return self.root.get("profile", "16.01")
|
||||
|
||||
def parse_python_template_version(self):
|
||||
python_template_version = self.root.get("python_template_version", None)
|
||||
if python_template_version is not None:
|
||||
python_template_version = packaging.version.parse(python_template_version)
|
||||
return python_template_version
|
||||
|
||||
|
||||
def _test_elem_to_dict(test_elem, i):
|
||||
rval = dict(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import packaging.version
|
||||
|
||||
from galaxy.tools.deps import requirements
|
||||
from galaxy.util.odict import odict
|
||||
from .interface import InputSource
|
||||
@@ -162,6 +164,12 @@ class YamlToolSource(ToolSource):
|
||||
def parse_profile(self):
|
||||
return self.root_dict.get("profile", "16.04")
|
||||
|
||||
def parse_python_template_version(self):
|
||||
python_template_version = self.root_dict.get("python_template_version", None)
|
||||
if python_template_version is not None:
|
||||
python_template_version = packaging.version.parse(python_template_version)
|
||||
return python_template_version
|
||||
|
||||
|
||||
def _parse_test(i, test_dict):
|
||||
inputs = test_dict["inputs"]
|
||||
|
||||
@@ -24,10 +24,19 @@ def assert_has_h5_attribute(output_bytes, key, value):
|
||||
|
||||
|
||||
def assert_has_h5_keys(output_bytes, keys):
|
||||
""" Asserts the specified HDF5 output has exactly the given keys."""
|
||||
""" Asserts the specified HDF5 output has the given keys."""
|
||||
_assert_h5py()
|
||||
keys = [k.strip() for k in keys.strip().split(',')]
|
||||
h5_keys = sorted(keys)
|
||||
output_temp = io.BytesIO(output_bytes)
|
||||
local_keys = sorted(list(h5py.File(output_temp, 'r').keys()))
|
||||
assert local_keys == h5_keys, "Not a HDF5 file or H5 keys do not match:\n\t%s\n\t%s" % (local_keys, h5_keys)
|
||||
local_keys = []
|
||||
|
||||
def append_keys(key):
|
||||
local_keys.append(key)
|
||||
return None
|
||||
h5py.File(output_temp, 'r').visit(append_keys)
|
||||
missing = 0
|
||||
for key in h5_keys:
|
||||
if key not in local_keys:
|
||||
missing += 1
|
||||
assert missing == 0, "Not a HDF5 file or H5 keys missing:\n\t%s\n\t%s" % (local_keys, h5_keys)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user