galaxy-commits
Threads by month
- ----- 2025 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions

galaxy-dist commit d8184d91928c: Remove FASTA filter script from BLAST+ tools (I want to generalise it)
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User peterjc <p.j.a.cock(a)googlemail.com>
# Date 1287998919 -3600
# Node ID d8184d91928c83f0269bd0267be949bc5d676e8b
# Parent 5c212dfc6189bb41d334b0519411ca4f04fde9ec
Remove FASTA filter script from BLAST+ tools (I want to generalise it)
--- a/tool_conf.xml.sample
+++ b/tool_conf.xml.sample
@@ -269,7 +269,6 @@
<tool file="ncbi_blast_plus/ncbi_tblastn_wrapper.xml" /><tool file="ncbi_blast_plus/ncbi_tblastx_wrapper.xml" /><tool file="ncbi_blast_plus/blastxml_to_tabular.xml" />
- <tool file="ncbi_blast_plus/blast_filter_fasta.xml" /></section><section name="NGS: Mapping" id="solexa_tools"><tool file="sr_mapping/lastz_wrapper.xml" />
--- a/tools/ncbi_blast_plus/blast_filter_fasta.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python
-"""Filter a FASTA file using tabular output, e.g. from BLAST.
-
-Takes five command line options, tabular BLAST filename, ID column number
-(using one based counting), input FASTA filename, and two output FASTA
-filenames (for records with and without any BLAST hits).
-
-In the default NCBI BLAST+ tabular output, the query sequence ID is in column
-one, and the ID of the match from the database is in column two.
-"""
-import sys
-from galaxy_utils.sequence.fasta import fastaReader, fastaWriter
-
-#Parse Command Line
-blast_file, blast_col, in_file, out_positive_file, out_negative_file = sys.argv[1:]
-blast_col = int(blast_col)-1
-assert blast_col >= 0
-
-#Read tabular BLAST file and record all queries with hit(s)
-ids = set()
-blast_handle = open(blast_file, "rU")
-for line in blast_handle:
- ids.add(line.split("\t")[blast_col])
-blast_handle.close()
-
-#Write filtered FASTA file based on IDs from BLAST file
-reader = fastaReader(open(in_file, "rU"))
-positive_writer = fastaWriter(open(out_positive_file, "w"))
-negative_writer = fastaWriter(open(out_negative_file, "w"))
-for record in reader:
- #The [1:] is because the fastaReader leaves the > on the identifer.
- if record.identifier and record.identifier.split()[0][1:] in ids:
- positive_writer.write(record)
- else:
- negative_writer.write(record)
-positive_writer.close()
-negative_writer.close()
-reader.close()
--- a/tools/ncbi_blast_plus/blast_filter_fasta.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<tool id="blast_filter_fasta" name="Filter FASTA using BLAST output" version="0.0.1">
- <description>Divide a FASTA file based on BLAST hits</description>
- <command interpreter="python">
- blast_filter_fasta.py $blast_file $blast_col $in_file $out_positive_file $out_negative_file
- </command>
- <inputs>
- <param name="in_file" type="data" format="fasta" label="FASTA file to filter"/>
- <param name="blast_file" type="data" format="tabular" label="Tabular BLAST output"/>
- <param name="blast_col" type="select" label="Column containing FASTA identifiers">
- <option value="1">Column 1 - BLAST query ID</option>
- <option value="2">Column 2 - BLAST match ID</option>
- </param>
- </inputs>
- <outputs>
- <data name="out_positive_file" format="fasta" label="Sequences with BLAST hits" />
- <data name="out_negative_file" format="fasta" label="Sequences without BLAST hits" />
- </outputs>
- <requirements>
- </requirements>
- <tests>
- </tests>
- <help>
-
-**What it does**
-
-Typical use would be to take a multi-sequence FASTA and the tabular output of
-running BLAST on it, and divide the FASTA file in two: those sequence with a
-BLAST hit, and those without.
-
-In the default NCBI BLAST+ tabular output, the query sequence ID is in column
-one, and the ID of the match from the database is in column two.
-
-This allows you to filter the FASTA file for the subjects in the BLAST search,
-rather than filtering the FASTA file for the queries in the BLAST search.
-
- </help>
-</tool>
1
0

galaxy-dist commit f2383b761f4e: Make sure samples have associated target libraries befoe enabling ability to transfer datasets, use better naming convention for request history code and templates, eliminate the ability to submit a request unless it has samples.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1289507783 18000
# Node ID f2383b761f4e05442fd5ba6b1cde517732aa2c03
# Parent dfc848840870fa9936a69e62322446fcb940fb40
Make sure samples have associated target libraries befoe enabling ability to transfer datasets, use better naming convention for request history code and templates, eliminate the ability to submit a request unless it has samples.
--- a/templates/requests/common/view_sample_datasets.mako
+++ b/templates/requests/common/view_sample_datasets.mako
@@ -7,14 +7,14 @@
is_complete = sample.request.is_complete
is_submitted = sample.request.is_submitted
can_select_datasets = is_admin and ( is_complete or is_submitted )
- can_transfer_datasets = is_admin and sample.untransferred_dataset_files
+ can_transfer_datasets = is_admin and sample.untransferred_dataset_files and sample.library and sample.folder
%><br/><br/><ul class="manage-table-actions">
%if can_transfer_datasets:
- <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Transfer datasets</a></li>
+ <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Manage selected datasets</a></li>
%endif
<li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=transfer_status )}">Refresh page</a></li><li><a class="action-button" id="sample-${sample.id}-popup" class="menubutton">Dataset Actions</a></li>
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -47,7 +47,7 @@
%if can_edit_request:
<a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
%endif
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
%if can_reject:
<a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
--- a/lib/galaxy/web/controllers/requests.py
+++ b/lib/galaxy/web/controllers/requests.py
@@ -57,9 +57,9 @@ class Requests( BaseController ):
action='undelete_request',
cntrller='requests',
**kwd ) )
- if operation == "request_events":
+ if operation == "view_request_history":
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='request_events',
+ action='view_request_history',
cntrller='requests',
**kwd ) )
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -76,7 +76,7 @@ class RequestsGrid( grids.Grid ):
StateColumn( "State",
key='state',
filterable="advanced",
- link=( lambda item: iff( item.deleted, None, dict( operation="request_events", id=item.id ) ) )
+ link=( lambda item: iff( item.deleted, None, dict( operation="view_request_history", id=item.id ) ) )
)
]
columns.append( grids.MulticolFilterColumn( "Search",
@@ -579,8 +579,8 @@ class RequestsCommon( BaseController, Us
status=status,
message=message ) )
@web.expose
- @web.require_login( "sequencing request events" )
- def request_events( self, trans, cntrller, **kwd ):
+ @web.require_login( "sequencing request history" )
+ def view_request_history( self, trans, cntrller, **kwd ):
params = util.Params( kwd )
request_id = params.get( 'id', None )
try:
@@ -590,7 +590,7 @@ class RequestsCommon( BaseController, Us
events_list = []
for event in request.events:
events_list.append( ( event.state, time_ago( event.update_time ), event.comment ) )
- return trans.fill_template( '/requests/common/events.mako',
+ return trans.fill_template( '/requests/common/view_request_history.mako',
cntrller=cntrller,
events_list=events_list,
request=request )
--- a/templates/admin/requests/select_datasets_to_transfer.mako
+++ b/templates/admin/requests/select_datasets_to_transfer.mako
@@ -72,7 +72,7 @@
<%
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
- can_transfer_datasets = is_admin and sample.untransferred_dataset_files
+ can_transfer_datasets = is_admin and sample.untransferred_dataset_files and sample.library and sample.folder
%><br/><br/>
@@ -85,8 +85,15 @@
</ul>
%if not sample:
+ <br/><font color="red"><b><i>Select a sample before selecting datasets to transfer</i></b></font>
- <br/><br/>
+ <br/>
+%endif
+
+%if request.samples_without_library_destinations:
+ <br/>
+ <font color="red"><b><i>Select a target data library and folder for all samples before starting the sequence run</i></b></font>
+ <br/>
%endif
%if message:
--- a/lib/galaxy/web/controllers/requests_admin.py
+++ b/lib/galaxy/web/controllers/requests_admin.py
@@ -175,9 +175,9 @@ class RequestsAdmin( BaseController, Use
action='view_request',
cntrller='requests_admin',
**kwd ) )
- if operation == "request_events":
+ if operation == "view_request_history":
return trans.response.send_redirect( web.url_for( controller='requests_common',
- action='request_events',
+ action='view_request_history',
cntrller='requests_admin',
**kwd ) )
if operation == "reject":
--- a/test/base/twilltestcase.py
+++ b/test/base/twilltestcase.py
@@ -1517,7 +1517,7 @@ class TwillTestCase( unittest.TestCase )
for check_str in strings_not_displayed:
self.check_string_not_in_page( check_str )
def view_request_history( self, cntrller, request_id, strings_displayed=[], strings_not_displayed=[] ):
- self.visit_url( "%s/requests_common/request_events?cntrller=%s&id=%s" % ( self.url, cntrller, request_id ) )
+ self.visit_url( "%s/requests_common/view_request_history?cntrller=%s&id=%s" % ( self.url, cntrller, request_id ) )
for check_str in strings_displayed:
self.check_page_for_string( check_str )
for check_str in strings_not_displayed:
--- a/templates/requests/common/events.mako
+++ /dev/null
@@ -1,53 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-<%
- is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
- can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
- can_reject_request = is_admin and request.is_submitted
- can_add_samples = request.is_unsubmitted
-%>
-
-<br/><br/>
-<ul class="manage-table-actions">
- <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li>
- <div popupmenu="request-${request.id}-popup">
- <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
- %if can_edit_request:
- <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
- %endif
- %if can_add_samples:
- <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit this request</a>
- %endif
- %if can_reject_request:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
- %endif
- </div>
-</ul>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-<h2>History of Sequencing Request "${request.name}"</h2>
-
-<div class="toolForm">
- <table class="grid">
- <thead>
- <tr>
- <th>State</th>
- <th>Last Update</th>
- <th>Comments</th>
- </tr>
- </thead>
- <tbody>
- %for state, updated, comments in events_list:
- <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
- <td><b><a>${state}</a></b></td>
- <td><a>${updated}</a></td>
- <td><a>${comments}</a></td>
- </tr>
- %endfor
- </tbody>
- </table>
-</div>
--- a/templates/requests/common/edit_basic_request_info.mako
+++ b/templates/requests/common/edit_basic_request_info.mako
@@ -3,7 +3,13 @@
<%
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
- can_add_samples = request.is_unsubmitted
+ is_complete = request.is_complete
+ is_submitted = request.is_submitted
+ is_unsubmitted = request.is_unsubmitted
+ can_add_samples = is_unsubmitted
+ can_reject = is_admin and is_submitted
+ can_select_datasets = is_admin and ( is_complete or is_submitted )
+ can_submit_request = request.samples and is_unsubmitted
%><br/><br/>
@@ -11,12 +17,14 @@
<li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li><div popupmenu="request-${request.id}-popup"><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
- %if can_add_samples:
+ %if can_submit_request:
<a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit this request</a>
%endif
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
- %if is_admin and request.is_submitted:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ %if can_reject:
<a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
+ %endif
+ %if can_select_datasets:
<a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
%endif
</div>
--- a/templates/admin/requests/reject.mako
+++ b/templates/admin/requests/reject.mako
@@ -8,7 +8,7 @@
<h2>Reject Sequencing Request "${request.name}"</h2><ul class="manage-table-actions"><li>
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">View history</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">View history</a></li><li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id(request.id) )}">Browse this request</a>
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -44,7 +44,7 @@
%if can_edit_request:
<a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
%endif
- <a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
%if can_reject:
<a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
@@ -52,8 +52,15 @@
</ul>
%if request.is_rejected:
+ <br/><font color="red"><b><i>Reason for rejection: </i></b></font><b>${request.last_comment}</b>
- <br/><br/>
+ <br/>
+%endif
+
+%if request.samples_without_library_destinations:
+ <br/>
+ <font color="red"><b><i>Select a target data library and folder for all samples before starting the sequence run</i></b></font>
+ <br/>
%endif
%if message:
@@ -94,7 +101,7 @@
<div class="form-row"><label>${field_label}:</label>
%if field_label == 'State':
- <a href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">${field_value}</a>
+ <a href="${h.url_for( controller='requests_common', action='view_request_history', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">${field_value}</a>
%else:
${field_value}
%endif
@@ -154,6 +161,11 @@
render_buttons = can_edit_samples
%>
${render_samples_grid( cntrller, request, displayable_sample_widgets=displayable_sample_widgets, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=render_buttons, grid_header=grid_header )}
+ ## Render the other grids
+ <% trans.sa_session.refresh( request.type.sample_form ) %>
+ %for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), displayable_sample_widgets=displayable_sample_widgets, editing_samples=False )}
+ %endfor
%else:
There are no samples.
%if can_add_samples:
@@ -162,8 +174,3 @@
</ul>
%endif
%endif
-## Render the other grids
-<% trans.sa_session.refresh( request.type.sample_form ) %>
-%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), displayable_sample_widgets=displayable_sample_widgets, editing_samples=False )}
-%endfor
--- /dev/null
+++ b/templates/requests/common/view_request_history.mako
@@ -0,0 +1,58 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+
+<%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_complete = request.is_complete
+ is_submitted = request.is_submitted
+ is_unsubmitted = request.is_unsubmitted
+ can_add_samples = is_unsubmitted
+ can_edit_request = ( is_admin and not is_complete ) or is_unsubmitted
+ can_reject = is_admin and is_submitted
+ can_select_datasets = is_admin and ( is_complete or is_submitted )
+ can_submit_request = request.samples and is_unsubmitted
+%>
+
+<br/><br/>
+<ul class="manage-table-actions">
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li>
+ <div popupmenu="request-${request.id}-popup">
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
+ %if can_edit_request:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
+ %endif
+ %if can_submit_request:
+ <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit this request</a>
+ %endif
+ %if can_reject:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
+ %endif
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+<h2>History of sequencing request "${request.name}"</h2>
+
+<div class="toolForm">
+ <table class="grid">
+ <thead>
+ <tr>
+ <th>State</th>
+ <th>Last Update</th>
+ <th>Comments</th>
+ </tr>
+ </thead>
+ <tbody>
+ %for state, updated, comments in events_list:
+ <tr class="libraryRow libraryOrFolderRow" id="libraryRow">
+ <td><b><a>${state}</a></b></td>
+ <td><a>${updated}</a></td>
+ <td><a>${comments}</a></td>
+ </tr>
+ %endfor
+ </tbody>
+ </table>
+</div>
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -322,7 +322,7 @@
%if can_select_datasets:
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ), sample_id=trans.security.encode_id( sample.id ) )}">Select datasets to transfer</a></li>
%endif
- %if sample.datasets and len( sample.datasets ) > len( transferred_dataset_files ):
+ %if sample.datasets and len( sample.datasets ) > len( transferred_dataset_files ) and sample.library and sample.folder:
<li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', sample_id=trans.security.encode_id( sample.id ) )}">Manage selected datasets</a></li>
%elif sample.datasets and len(sample.datasets ) == len( transferred_dataset_files ):
<li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=trans.model.SampleDataset.transfer_status.COMPLETE )}">View transferred datasets</a></li>
1
0

galaxy-dist commit bbc0f56e3e16: A few more bug fixes in the new sample tracking code.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1289427445 18000
# Node ID bbc0f56e3e16f93bf3c81d09b0fa12876a3f2579
# Parent b1813ff5bb4ef20d0b5d5a1fdcfc16cf6ec3ba53
A few more bug fixes in the new sample tracking code.
--- a/templates/admin/requests/select_datasets_to_transfer.mako
+++ b/templates/admin/requests/select_datasets_to_transfer.mako
@@ -127,7 +127,7 @@
</div>
%if sample and sample.datasets:
- <% title = 'Datasets currently selected for "%s"' % sample.name %>
+ <% title = 'All selected datasets for "%s"' % sample.name %><p/>
${render_sample_datasets( 'requests_admin', sample, sample.datasets, title )}
%endif
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -952,9 +952,10 @@ class RequestsCommon( BaseController, Us
sample_datasets = sample.transfer_error_dataset_files
return trans.fill_template( '/requests/common/view_sample_datasets.mako',
cntrller=cntrller,
+ title=title,
sample=sample,
sample_datasets=sample_datasets,
- transfer_status=transferr_status,
+ transfer_status=transfer_status,
message=message,
status=status,
files=[],
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -329,10 +329,26 @@
%endif
</td><td>
- %if is_admin and sample.untransferred_dataset_files:
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %if is_admin:
+ %if sample.untransferred_dataset_files:
+ ## At least 1 selected dataset is not yet transferred, so this link
+ ## will direct the admin to a page allowing them to transfer datasets.
+ <a href="${h.url_for( controller='requests_common', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %else:
+ ## All selected datasets have successfully transferred, so this link
+ ## will direct the admin to a page displaying all transferred datasets.
+ <a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=trans.model.SampleDataset.transfer_status.COMPLETE )}">${len( sample.transferred_dataset_files )}</a>
+ %endif
%else:
- ${len( sample.transferred_dataset_files )}
+ %if sample.transferred_dataset_files:
+ ## The cuurent user is not an admin, so this link will direct the
+ ## user to the target data library containing those datasets that
+ ## were successfully transferred.
+ <a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %else:
+ ## Display a 0 with no link.
+ ${len( sample.transferred_dataset_files )}
+ %endif
%endif
</td>
%endif
--- a/templates/requests/common/view_sample_datasets.mako
+++ b/templates/requests/common/view_sample_datasets.mako
@@ -40,4 +40,5 @@
No datasets with status ${transfer_status}" belong to this sample
%else:
No datasets have been selected for this sample.
+ %endif
%endif
1
0

galaxy-dist commit 0e5144e49c14: Trackster: packed scripts, support LEN files that are space separated
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User James Taylor <james(a)jamestaylor.org>
# Date 1289414596 18000
# Node ID 0e5144e49c14eb2a77e1d3182a33b4f9c8de98fc
# Parent d56f296aaa610a537d35cb7d235eac9d8f596464
Trackster: packed scripts, support LEN files that are space separated
--- a/lib/galaxy/web/controllers/tracks.py
+++ b/lib/galaxy/web/controllers/tracks.py
@@ -220,9 +220,10 @@ class TracksController( BaseController,
if not os.path.exists( len_file ):
return None
for line in open( len_file ):
- if line.startswith("#"): continue
- line = line.rstrip("\r\n")
- fields = line.split("\t")
+ if line.startswith("#"):
+ continue
+ # LEN files are just whitespace separated
+ fields = line.split()
manifest[fields[0]] = int(fields[1])
return manifest
--- a/static/scripts/packed/trackster.js
+++ b/static/scripts/packed/trackster.js
@@ -1,1 +1,1 @@
-var DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=50,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",FILTERABLE_CLASS="filterable",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}CONTEXT=DUMMY_CANVAS.getContext("2d");PX_PER_CHAR=CONTEXT.measureText("A").width;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPa
ttern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,d,c,b){this.container=a;this.vis_id=c;this.dbkey=b;this.ti
tle=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init();this.reset()};$.extend(View.prototype,{init:function(){var c=this.container,a=this;this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_container=$("<div/>").addClass("nav-container").appendTo(c);this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.nav_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.nav);this.overview_viewport=$("<div/>").addClas
s("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div />").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>").attr("action",function(){}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);var b=function(d){if(d.type==="focusout"||(d.keyCode||d.which)===13||(d.keyCode||d.which)===27){if((d.keyCode||d.wh
ich)!==27){a.go_to($(this).val())}$(this).hide();a.location_span.show();a.chrom_select.show();return false}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keypress focusout",b).appendTo(this.chrom_form);this.location_span=$("<span/>").addClass("location").appendTo(this.chrom_form);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);this.zi_link=$("<a/>").click(function(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:
this.dbkey}),dataType:"json",success:function(e){if(e.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=e.chrom_info;var h='<option value="">Select Chrom/Contig</option>';for(var g=0,d=a.chrom_data.length;g<d;g++){var f=a.chrom_data[g].chrom;h+='<option value="'+f+'">'+f+"</option>"}a.chrom_select.html(h);a.intro_div.show();a.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())})},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("dblclick",function(d){a.zoom_in(d.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(d){this.current_x=d.offsetX}).bind("drag",function(d){var g=d.offsetX-this.current_x;this.current_x=d.offsetX;var f=Math.round(g/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-f)});this.overview_close.bind("click",function(){for(var e=0,d=a.tracks.length;e<d;e++){a.tracks[e].is_overview=false}$(this).siblings().filter("canvas").remove();
$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("dragstart",function(d){this.original_low=a.low;this.current_height=d.clientY;this.current_x=d.offsetX;this.enable_pan=(d.clientX<a.viewport_container.width()-16)?true:false}).bind("drag",function(g){if(!this.enable_pan||this.in_reordering){return}var d=$(this);var i=g.offsetX-this.current_x;var f=d.scrollTop()-(g.clientY-this.current_height);d.scrollTop(f);this.current_height=g.clientY;this.current_x=g.offsetX;var h=Math.round(i/a.viewport_container.width()*(a.high-a.low));a.move_delta(h)});this.top_labeltrack.bind("dragstart",function(d){this.drag_origin_x=d.clientX;this.drag_origin_pos=d.clientX/a.viewport_container.width()*(a.high-a.low)+a.low;this.drag_div=$("<div />").css({height:a.content_div.height()+30,top:"0px",position:"absolute","background-color":"#cfc",border:"1px solid #6a6",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag
",function(i){var f=Math.min(i.clientX,this.drag_origin_x)-a.container.offset().left,d=Math.max(i.clientX,this.drag_origin_x)-a.container.offset().left,h=(a.high-a.low),g=a.viewport_container.width();a.update_location(Math.round(f/g*h)+a.low,Math.round(d/g*h)+a.low);this.drag_div.css({left:f+"px",width:(d-f)+"px"})}).bind("dragend",function(j){var f=Math.min(j.clientX,this.drag_origin_x),d=Math.max(j.clientX,this.drag_origin_x),h=(a.high-a.low),g=a.viewport_container.width(),i=a.low;a.low=Math.round(f/g*h)+i;a.high=Math.round(d/g*h)+i;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window()});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+c
ommatize(b))},change_chrom:function(e,b,g){var d=this;var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){return}if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()},go_to:function(f){var j=this,a,d,b=f.split(":"),h=b[0],i=b[1];if(i!==undefined){try{var g=i.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}j.change_chrom(h,a,d)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counte
r;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max
_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);th
is.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.nav_container.height()-45);this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.slider_min=Number.MAX_VALUE;this.slider_max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b
){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.slider_min){this.slider_min=b[this.index];a=true}if(b[this.index]>this.slider_max){this.slider_max=b[this.index];a=false}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.slider_min<b||this.slider_max>a){this.slider.slider("option","min",this.slider_min);this.slider.slider("option","max",this.slider_max);this.slider.slider("option","values",[this.slider_min,this.slider_max])}}});var get_filters=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e=="int"||e=="float"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var Track=function(b,a,d,c){this.name=b;this.view=a;this.parent_element=d;this.filters=(c!==undefined?get_filters(c):[]);this.init_global()};$.extend(Track.prototype,{init_global:function(){this.container_div=$("<div />").addClass("track").css("position","relative");i
f(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.filtering_div=$("<div class='track-filters'>").appendTo(this.container_div);this.filtering_div.hide();this.filtering_div.bind("drag",function(i){i.stopPropagation()});var b=$("<table class='filters'>").appendTo(this.filtering_div);var c=this;for(var e=0;e<this.filters.length;e++){var a=this.filters[e];var f=$("<tr>").appendTo(b);var g=$("<th class='filter-info'>").appendTo(f);var j=$("<span class='name'>").appendTo(g);j.text(a.name+" ");var d=$("<span class='values'>").appendTo(g);var h=$("<td>").appendTo(f);a.control_element=$("<div id='"+a.name+"-filter-control' style='width: 200
px; position: relative'>").appendTo(h);a.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(k,l){var i=l.values;d.text("["+i[0]+"-"+i[1]+"]");a.low=i[0];a.high=i[1];c.draw(true)},change:function(i,k){a.control_element.slider("option","slide").call(a.control_element,i,k)}});a.slider=a.control_element;a.slider_label=d}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_div.css("height","auto");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("
<a href='javascript:void(0);'></a>").attr("id",f+"_error");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})});a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){var b=this,j=b.view;if(b.hidden){return}if(b.display_modes!==undefined){if(b.mode_div===undefined){b.mode_div=$("<div class='right-float menubutton popup' />").appendTo(b.header_div);var e=
b.display_modes[0];b.mode=e;b.mode_div.text(e);var c=function(i){b.mode_div.text(i);b.mode=i;b.tile_cache.clear();b.draw()};var a={};for(var f=0,h=b.display_modes.length;f<h;f++){var g=b.display_modes[f];a[g]=function(i){return function(){c(i)}}(g)}make_popupmenu(b.mode_div,a)}else{b.mode_div.hide()}}var d={};d["Set as overview"]=function(){j.overview_viewport.find("canvas").remove();b.is_overview=true;b.set_overview();for(var i in j.tracks){if(j.tracks[i]!==b){j.tracks[i].is_overview=false}}};d["Edit configuration"]=function(){var l=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},i=function(){b.update_options(b.track_id);hide_modal();$(window).unbind("keypress.check_enter_esc")},k=function(m){if((m.keyCode||m.which)===27){l()}else{if((m.keyCode||m.which)===13){i()}}};$(window).bind("keypress.check_enter_esc",k);show_modal("Configure Track",b.gen_options(b.track_id),{Cancel:l,OK:i})};if(b.filters.length>0){d["Show filters"]=function(){var i;if(!b.filter
ing_div.is(":visible")){i="Hide filters";b.filters_visible=true}else{i="Show filters";b.filters_visible=false}$("#"+b.name_div.attr("id")+"-menu").find("li").eq(2).text(i);b.filtering_div.toggle()}}d.Remove=function(){j.remove_track(b);if(j.num_tracks===0){$("#no-tracks").show()}};b.popup_menu=make_popupmenu(b.name_div,d);show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters",false)};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(a){var k=this.view.low,g=this.view.high,h=g-k,f=this.view.resolution;var n=$("<div style='position: relative;'></div>"),o=this.content_div.width()/h;this.content_div.append(n);this.max_height=0;var b=Math.floor(k/f/DENSITY);var j={};while((b*DENSITY*f)<g){var l=this.content_div.width()+"_"+o+"_"+b;var e=this.tile_cache.get(l);if(!a&&e){var i=b*DENSITY*f;var d=(i-k)*o;if(this.left_offset){d-=this.left_offset}e.css({left:d});this.show_tile(e,n)}else{this.delayed_draw(this,l,k,g,b,f,n,o,j)}b+=1}var c=this;var m=setInterval(functio
n(){if(obj_length(j)===0){if(c.content_div.children().length>1){c.content_div.children(":first").remove()}for(var p=0;p<c.filters.length;p++){c.filters[p].update_ui_elt()}clearInterval(m)}},50)},delayed_draw:function(c,h,g,e,b,d,i,j,f){var a=setTimeout(function(){if(g<=c.view.high&&e>=c.view.low){var k=c.draw_tile(d,b,i,j);if(k){if(!c.initial_canvas&&!window.G_vmlCanvasManager){c.initial_canvas=$(k).clone();var n=k.get(0).getContext("2d");var l=c.initial_canvas.get(0).getContext("2d");var m=n.getImageData(0,0,n.canvas.width,n.canvas.height);l.putImageData(m,0,0);c.set_overview()}c.tile_cache.set(h,k);c.show_tile(k,i)}}delete f[a]},50);f[a]=true},show_tile:function(a,c){var b=this;c.append(a);b.max_height=Math.max(b.max_height,a.height());b.content_div.css("height",b.max_height+"px");if(a.hasClass(FILTERABLE_CLASS)){show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters");if(b.filters_visible){b.filtering_div.show()}}else{show_hide_popupmenu_options(b.popup_menu,"(Show
|Hide) filters",false);b.filtering_div.hide()}},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_di
v.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,j=f+"_"+b;var e=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(e)}e=$(e);var n=e.get(0).getContext("2d");if(o>PX_PER_CHAR){if(this.dat
a_cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){this.content_div.css("height","0px");return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o-this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o),i=Math.round(o/2);n.fillText(m[h],a+this.left_offset+i,10)}k.append(e);return e}this.content_div.css("height","0px")}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=80;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={color:"black",min_value:undefined,max_value:undefined,mode:this.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.ver
tical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"22px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",top:a.height_px+11+"px",left:"10px"});f.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=
(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){var h=g.data;c.data_cache.set(e,h);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*o,a=DENSITY*o,w=o+"_"+r;var b=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(b)}b=$(b);if(this.data_cache.get(w)===undefined){this.get_data(o,r);return}var v=this.data_cache.get(w);if(!v){return}b.css({position:"absolute",top:0,left:(s-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),j=false,k=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,t=this.total_frequency,d=this.height_px,l=this.mode;n.beginPath();n.fillStyle=this.prefs.co
lor;var u,h,f;if(v.length>1){f=Math.ceil((v[1][0]-v[0][0])*e)}else{f=10}for(var p=0,q=v.length;p<q;p++){u=Math.round((v[p][0]-s)*e);h=v[p][1];if(h===null){if(j&&l==="Filled"){n.lineTo(u,d)}j=false;continue}if(h<k){h=k}else{if(h>g){h=g}}if(l==="Histogram"){h=Math.round(d-(h-k)/m*d);n.fillRect(u,h,f,d-h)}else{if(l==="Intensity"){h=255-Math.floor((h-k)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(u,0,f,d)}else{h=Math.round(d-(h-k)/m*d);if(j){n.lineTo(u,h)}else{j=true;if(l==="Filled"){n.moveTo(u,d);n.lineTo(u,h)}else{n.moveTo(u,h)}}}}}if(l==="Filled"){if(j){n.lineTo(u,d)}n.fill()}else{n.stroke()}c.append(b);return b},gen_options:function(m){var a=$("<div />").addClass("form-row");var e="track_"+m+"_color",b=$("<label />").attr("for",e).text("Color:"),c=$("<input />").attr("id",e).attr("name",e).val(this.prefs.color),h="track_"+m+"_minval",l=$("<label></label>").attr("for",h).text("Min value:"),d=(this.prefs.min_value===undefined?"":this.prefs.min_value),k=$("<input></i
nput>").attr("id",h).val(d),j="track_"+m+"_maxval",g=$("<label></label>").attr("for",j).text("Max value:"),i=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",j).val(i);return a.append(l).append(k).append(g).append(f).append(b).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_color").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!==this.prefs.color){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.color=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,e,c){this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];Track.call(this,d,b,b.viewport_container,e);TiledTrack.call(this);this.height_p
x=0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=2;this.summary_draw_height=30;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.left_offset=200;this.prefs={block_color:"#444",label_color:"black",show_counts:true}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b="initial";this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution,mode:a.mode},function(c){a.mode_div.show();a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.vie
w.resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,b,q){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=a;this.inc_slots[a].mode=q;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,y=[],h=0,n=this.view.max_low;var A=[];if(this.inc_slots[a].mode!==q){delete this.inc_slots[a];this.inc_slots[a]={mode:q,w_scale:m};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var v=0,w=g.length;v<w;v++){var f=g[v],l=f[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);A.push(this.inc_slots[a][l])}else{y.push(v)}}for(var v=0,w=y.length;v<w;v++){var f=g[y[v]],l=f[0],r=f[1],c=f[2],p=f[3],d=Math.floor((r-n)*m),e=Math.ceil((c-n)*m);if(p!==undefined&&!b){var s=CONTEXT.measureText(p).width;if(d-s<0){e+=s}else{d-=s}}var u=0;while(u<=MAX_FEATURE_DEPTH){var o=true;if(this.s_e_by_tile[a][u]!==undefined){for(var t=0,z=this.s_e_by_tile[a][u].length;t<z;t++){var x=this.s_e_
by_tile[a][u][t];if(e>x[0]&&d<x[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][u]===undefined){this.s_e_by_tile[a][u]=[]}this.s_e_by_tile[a][u].push([d,e]);this.inc_slots[a][l]=u;h=Math.max(h,u);break}u++}}return h},rect_or_text:function(r,l,t,b,q,f,i,e){r.textAlign="center";var k=0,p=Math.round(l/2);for(var m=0,s=i.length;m<s;m++){var j=i[m],d="MIDNSHP"[j[0]],n=j[1];if(d==="H"||d==="S"){k-=n}var g=q+k,w=Math.floor(Math.max(0,(g-t)*l)),h=Math.floor(Math.max(0,(g+n-t)*l));switch(d){case"S":case"H":case"M":var o=f.slice(k,n);if((this.mode==="Pack"||this.mode==="Auto")&&f!==undefined&&l>PX_PER_CHAR){r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+1,h-w,9);r.fillStyle=CONNECTOR_COLOR;for(var u=0,a=o.length;u<a;u++){if(g+u>=t&&g+u<=b){var v=Math.floor(Math.max(0,(g+u-t)*l));r.fillText(o[u],v+this.left_offset+p,e+9)}}}else{r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+4,h-w,3)}break;case"N":r.fillStyle=CONNECTOR_COLOR;r.fillRect(w+this.lef
t_offset,e+5,h-w,1);break;case"D":r.fillStyle="red";r.fillRect(w+this.left_offset,e+4,h-w,3);break;case"P":case"I":break}k+=n}},draw_tile:function(ag,o,s,av){var N=o*DENSITY*ag,al=(o+1)*DENSITY*ag,M=al-N;var an=(!this.initial_canvas?"initial":N+"_"+al);var I=this.data_cache.get(an);var e;if(I===undefined||(this.mode!=="Auto"&&I.dataset_type==="summary_tree")){this.data_queue[[N,al]]=true;this.get_data(N,al);return}var a=Math.ceil(M*av),ai=this.prefs.label_color,l=this.prefs.block_color,r=this.mode,z=25,ae=(r==="Squish")||(r==="Dense")&&(r!=="Pack")||(r==="Auto"&&(I.extra_info==="no_detail")),W=this.left_offset,au,D,aw;var q=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(q)}q=$(q);if(I.dataset_type==="summary_tree"){D=this.summary_draw_height}else{if(r==="Dense"){D=z;aw=10}else{aw=(ae?this.vertical_nodetail_px:this.vertical_detail_px);var A=(av<0.0001?1/this.view.zoom_res:av);D=this.incremental_slots(A,I.data,ae,r)*aw+z;au=this.i
nc_slots[A]}}q.css({position:"absolute",top:0,left:(N-this.view.low)*av-W});q.get(0).width=a+W;q.get(0).height=D;s.parent().css("height",Math.max(this.height_px,D)+"px");var J=q.get(0).getContext("2d");J.fillStyle=l;J.font=this.default_font;J.textAlign="right";this.container_div.find(".yaxislabel").remove();if(I.dataset_type=="summary_tree"){var Y=I.data,L=I.max,b=Math.ceil(I.delta*av);var p=$("<div />").addClass("yaxislabel").text(L);p.css({position:"absolute",top:"22px",left:"10px"});p.prependTo(this.container_div);for(var ap=0,H=Y.length;ap<H;ap++){var aa=Math.floor((Y[ap][0]-N)*av);var Z=Y[ap][1];if(!Z){continue}var am=Z/L*this.summary_draw_height;J.fillStyle="black";J.fillRect(aa+W,this.summary_draw_height-am,b,am);if(this.prefs.show_counts&&J.measureText(Z).width<b){J.fillStyle="#bbb";J.textAlign="center";J.fillText(Z,aa+W+(b/2),this.summary_draw_height-5)}}e="Summary";s.append(q);return q}if(I.message){q.css({border:"solid red","border-width":"2px 2px 2px 0px"});J.fil
lStyle="red";J.textAlign="left";J.fillText(I.message,100+W,aw)}var ad=false;if(I.data){ad=true;for(var ar=0;ar<this.filters.length;ar++){if(!this.filters[ar].applies_to(I.data[0])){ad=false}}}if(ad){q.addClass(FILTERABLE_CLASS)}var at=I.data;var ao=0;for(var ap=0,H=at.length;ap<H;ap++){var S=at[ap],R=S[0],aq=S[1],ac=S[2],O=S[3];if(au[R]===undefined){continue}var ab=false;var U;for(var ar=0;ar<this.filters.length;ar++){U=this.filters[ar];U.update_attrs(S);if(!U.keep(S)){ab=true;break}}if(ab){continue}if(aq<=al&&ac>=N){var af=Math.floor(Math.max(0,(aq-N)*av)),K=Math.ceil(Math.min(a,Math.max(0,(ac-N)*av))),X=(r==="Dense"?1:(1+au[R]))*aw;var G,aj,P=null,ax=null;if(I.dataset_type==="bai"){var v=S[4];J.fillStyle=l;if(S[5] instanceof Array){var E=Math.floor(Math.max(0,(S[5][0]-N)*av)),Q=Math.ceil(Math.min(a,Math.max(0,(S[5][1]-N)*av))),C=Math.floor(Math.max(0,(S[6][0]-N)*av)),w=Math.ceil(Math.min(a,Math.max(0,(S[6][1]-N)*av)));if(S[5][1]>=N&&S[5][0]<=al){this.rect_or_text(J,av,N,al
,S[5][0],S[5][2],v,X)}if(S[6][1]>=N&&S[6][0]<=al){this.rect_or_text(J,av,N,al,S[6][0],S[6][2],v,X)}if(C>Q){J.fillStyle=CONNECTOR_COLOR;J.fillRect(Q+W,X+5,C-Q,1)}}else{J.fillStyle=l;this.rect_or_text(J,av,N,al,aq,O,v,X)}if(r!=="Dense"&&!ae&&aq>N){J.fillStyle=this.prefs.label_color;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(R,K+2+W,X+8)}else{J.textAlign="right";J.fillText(R,af-2+W,X+8)}J.fillStyle=l}}else{if(I.dataset_type==="interval_index"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var F=S[4],V=S[5],ah=S[6],h=S[7];if(V&&ah){P=Math.floor(Math.max(0,(V-N)*av));ax=Math.ceil(Math.min(a,Math.max(0,(ah-N)*av)))}if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}if(h){if(F){if(F=="+"){J.fillStyle=RIGHT_STRAND}else{if(F=="-"){J.fillStyle=LEFT_STRAND}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}for(var an
=0,g=h.length;an<g;an++){var u=h[an],d=Math.floor(Math.max(0,(u[0]-N)*av)),T=Math.ceil(Math.min(a,Math.max((u[1]-N)*av)));if(d>T){continue}G=5;aj=3;J.fillRect(d+W,X+aj,T-d,G);if(P!==undefined&&!(d>ax||T<P)){G=9;aj=1;var ak=Math.max(d,P),B=Math.min(T,ax);J.fillRect(ak+W,X+aj,B-ak,G)}}}else{G=9;aj=1;J.fillRect(af+W,X+aj,K-af,G);if(S.strand){if(S.strand=="+"){J.fillStyle=RIGHT_STRAND_INV}else{if(S.strand=="-"){J.fillStyle=LEFT_STRAND_INV}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}}}}else{if(I.dataset_type==="vcf"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var t=S[4],n=S[5],c=S[6];G=9;aj=1;J.fillRect(af+W,X,K-af,G);if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}var m=t+" / "+n;if(aq>N&&J.measureText(m).width<(K-af)){J.fillStyle="white";J.textAlign="center";J.fillText(m,W+af+(K-af)/2,X+8);J.fillStyle=l}}}}}ao++}}return q
},gen_options:function(i){var a=$("<div />").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label />").attr("for",e).text("Block color:"),l=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label />").attr("for",j).text("Text color:"),h=$("<input />").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(k).append(l).append(g).append(h).append(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_
counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,e,c){FeatureTrack.call(this,d,b,a,e,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
+var DENSITY=200,FEATURE_LEVELS=10,MAX_FEATURE_DEPTH=50,CONNECTOR_COLOR="#ccc",DATA_ERROR="There was an error in indexing this dataset.",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",FILTERABLE_CLASS="filterable",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=5,CACHED_DATA=5,DUMMY_CANVAS=document.createElement("canvas"),RIGHT_STRAND,LEFT_STRAND;if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(DUMMY_CANVAS)}CONTEXT=DUMMY_CANVAS.getContext("2d");PX_PER_CHAR=CONTEXT.measureText("A").width;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPa
ttern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONTEXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};function round_1000(a){return Math.round(a*1000)/1000}var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,d,c,b,e){this.container=a;this.vis_id=c;this.dbkey=b;this.
title=d;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.num_tracks=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init(e);this.reset()};$.extend(View.prototype,{init:function(d){var c=this.container,a=this;this.top_container=$("<div/>").addClass("top-container").appendTo(c);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(c);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(c);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.intro_div=$("<div/>").addClass("intro").text("Select a chrom from the dropdown below").hide();this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("nav-container").prependTo(this.top
_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a href='javascript:void(0);'>Close Overview</a>").addClass("overview-close").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div />").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>").attr("action",function(){}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-a
utocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);var b=function(f){if(f.type==="focusout"||(f.keyCode||f.which)===13||(f.keyCode||f.which)===27){if((f.keyCode||f.which)!==27){a.go_to($(this).val())}$(this).hide();a.location_span.show();a.chrom_select.show();return false}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keypress focusout",b).appendTo(this.chrom_form);this.location_span=$("<span/>").addClass("location").appendTo(this.chrom_form);this.location_span.bind("click",function(){a.location_span.hide();a.chrom_select.hide();a.nav_input.css("display","inline-block");a.nav_input.select();a.nav_input.focus()});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);this.zi_link=$("<a/>").click(funct
ion(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}),dataType:"json",success:function(f){if(f.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=f.chrom_info;var j='<option value="">Select Chrom/Contig</option>';for(var h=0,e=a.chrom_data.length;h<e;h++){var g=a.chrom_data[h].chrom;j+='<option value="'+g+'">'+g+"</option>"}a.chrom_select.html(j);a.intro_div.show();a.chrom_select.bind("change",function(){a.change_chrom(a.chrom_select.val())});if(d){d()}},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("dblclick",function(f){a.zoom_in(f.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(f){this.current_x=f.offsetX}).bind("drag",function(f){var h=f.offsetX-this.current_x;this.current_x=f.offsetX;var g=Math.round(h/a.viewport_container
.width()*(a.max_high-a.max_low));a.move_delta(-g)});this.overview_close.bind("click",function(){for(var f=0,e=a.tracks.length;f<e;f++){a.tracks[f].is_overview=false}$(this).siblings().filter("canvas").remove();$(this).parent().css("height",a.overview_box.height());a.overview_highlight.hide();$(this).hide()});this.viewport_container.bind("dragstart",function(f){this.original_low=a.low;this.current_height=f.clientY;this.current_x=f.offsetX;this.enable_pan=(f.clientX<a.viewport_container.width()-16)?true:false}).bind("drag",function(h){if(!this.enable_pan||this.in_reordering){return}var f=$(this);var j=h.offsetX-this.current_x;var g=f.scrollTop()-(h.clientY-this.current_height);f.scrollTop(g);this.current_height=h.clientY;this.current_x=h.offsetX;var i=Math.round(j/a.viewport_container.width()*(a.high-a.low));a.move_delta(i)});this.top_labeltrack.bind("dragstart",function(f){this.drag_origin_x=f.clientX;this.drag_origin_pos=f.clientX/a.viewport_container.width()*(a.high-a.low)+
a.low;this.drag_div=$("<div />").css({height:a.content_div.height()+a.top_labeltrack.height()+a.nav_labeltrack.height(),top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(j){var g=Math.min(j.clientX,this.drag_origin_x)-a.container.offset().left,f=Math.max(j.clientX,this.drag_origin_x)-a.container.offset().left,i=(a.high-a.low),h=a.viewport_container.width();a.update_location(Math.round(g/h*i)+a.low,Math.round(f/h*i)+a.low);this.drag_div.css({left:g+"px",width:(f-g)+"px"})}).bind("dragend",function(k){var g=Math.min(k.clientX,this.drag_origin_x),f=Math.max(k.clientX,this.drag_origin_x),i=(a.high-a.low),h=a.viewport_container.width(),j=a.low;a.low=Math.round(g/h*i)+j;a.high=Math.round(f/h*i)+j;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack));$(window).bind("resize",function(){a.resize_window(
)});$(document).bind("redraw",function(){a.redraw()});this.reset();$(window).trigger("resize")},update_location:function(a,b){this.location_span.text(commatize(a)+" - "+commatize(b));this.nav_input.val(this.chrom+":"+commatize(a)+"-"+commatize(b))},change_chrom:function(e,b,g){var d=this;var f=$.grep(d.chrom_data,function(j,k){return j.chrom===e})[0];if(f===undefined){return}if(e!==d.chrom){d.chrom=e;if(!d.chrom){d.intro_div.show()}else{d.intro_div.hide()}d.chrom_select.val(d.chrom);d.max_high=f.len;d.reset();d.redraw(true);for(var h=0,a=d.tracks.length;h<a;h++){var c=d.tracks[h];if(c.init){c.init()}}}if(b!==undefined&&g!==undefined){d.low=Math.max(b,0);d.high=Math.min(g,d.max_high)}d.reset_overview();d.redraw()},go_to:function(f){var j=this,a,d,b=f.split(":"),h=b[0],i=b[1];if(i!==undefined){try{var g=i.split("-");a=parseInt(g[0].replace(/,/g,""),10);d=parseInt(g[1].replace(/,/g,""),10)}catch(c){return false}}j.change_chrom(h,a,d)},move_fraction:function(c){var a=this;var b=
a.high-a.low;this.move_delta(c*b)},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1;this.num_tracks+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)];this.num_tracks-=1},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(h){var g=this.high-this.low,f=this.low,b=this.high;if(f<this.max_low){f=this.max_low}if(b>this.max_high){b=this.max_high}if(this.high!==0&&g<this.min_separation){b=f+this.
min_separation}this.low=Math.floor(f);this.high=Math.ceil(b);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));var a=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var e=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var j=13;this.overview_box.css({left:a,width:Math.max(j,e)}).show();if(e<j){this.overview_box.css("left",a-(j-e)/2)}if(this.overview_highlight){this.overview_highlight.css({left:a,width:e})}this.update_location(this.low,this.high);if(!h){for(var c=0,d=this.tracks.length;c<d;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(c=0,d=this.label_tracks.length;c<d;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+
this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);this.high=Math.round(c+a);this.redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.nav_container.width(this.container.width());this.redraw()},reset_overview:function(){this.overview_viewport.find("canvas").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide()}});var Filter=function(b,a,c){this.name=b;this.index=a;this.value=c};var NumberFilter=function(b,a){this.name=b;this.index=a;this.low=-Number.MAX_VALUE;this.high=Number.MAX_VALUE;this.sli
der_min=Number.MAX_VALUE;this.slider_max=-Number.MAX_VALUE;this.slider=null;this.slider_label=null};$.extend(NumberFilter.prototype,{applies_to:function(a){if(a.length>this.index){return true}return false},keep:function(a){if(!this.applies_to(a)){return true}return(a[this.index]>=this.low&&a[this.index]<=this.high)},update_attrs:function(b){var a=false;if(!this.applies_to(b)){return a}if(b[this.index]<this.slider_min){this.slider_min=b[this.index];a=true}if(b[this.index]>this.slider_max){this.slider_max=b[this.index];a=false}return a},update_ui_elt:function(){var b=this.slider.slider("option","min"),a=this.slider.slider("option","max");if(this.slider_min<b||this.slider_max>a){this.slider.slider("option","min",this.slider_min);this.slider.slider("option","max",this.slider_max);this.slider.slider("option","values",[this.slider_min,this.slider_max])}}});var get_filters=function(a){var g=[];for(var d=0;d<a.length;d++){var f=a[d];var c=f.name,e=f.type,b=f.index;if(e=="int"||e=="f
loat"){g[d]=new NumberFilter(c,b)}else{g[d]=new Filter(c,b,e)}}return g};var Track=function(b,a,d,c){this.name=b;this.view=a;this.parent_element=d;this.filters=(c!==undefined?get_filters(c):[]);this.init_global()};$.extend(Track.prototype,{init_global:function(){this.container_div=$("<div />").addClass("track").css("position","relative");if(!this.hidden){this.header_div=$("<div class='track-header' />").appendTo(this.container_div);if(this.view.editor){this.drag_div=$("<div class='draghandle' />").appendTo(this.header_div)}this.name_div=$("<div class='menubutton popup' />").appendTo(this.header_div);this.name_div.text(this.name);this.name_div.attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase())}this.filtering_div=$("<div class='track-filters'>").appendTo(this.container_div);this.filtering_div.hide();this.filtering_div.bind("drag",function(i){i.stopPropagation()});var b=$("<table class='filters'>").appendTo(this.filtering_div);var c=this;for(va
r e=0;e<this.filters.length;e++){var a=this.filters[e];var f=$("<tr>").appendTo(b);var g=$("<th class='filter-info'>").appendTo(f);var j=$("<span class='name'>").appendTo(g);j.text(a.name+" ");var d=$("<span class='values'>").appendTo(g);var h=$("<td>").appendTo(f);a.control_element=$("<div id='"+a.name+"-filter-control' style='width: 200px; position: relative'>").appendTo(h);a.control_element.slider({range:true,min:Number.MAX_VALUE,max:-Number.MIN_VALUE,values:[0,0],slide:function(k,l){var i=l.values;d.text("["+i[0]+"-"+i[1]+"]");a.low=i[0];a.high=i[1];c.draw(true)},change:function(i,k){a.control_element.slider("option","slide").call(a.control_element,i,k)}});a.slider=a.control_element;a.slider_label=d}this.content_div=$("<div class='track-content'>").appendTo(this.container_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();a.initial_canvas=undefined;a.content_di
v.css("height","auto");if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("<a href='javascript:void(0);'></a>").attr("id",f+"_error");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})});a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a
.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){var b=this,j=b.view;if(b.hidden){return}if(b.display_modes!==undefined){if(b.mode_div===undefined){b.mode_div=$("<div class='right-float menubutton popup' />").appendTo(b.header_div);var e=b.display_modes[0];b.mode=e;b.mode_div.text(e);var c=function(i){b.mode_div.text(i);b.mode=i;b.tile_cache.clear();b.draw()};var a={};for(var f=0,h=b.display_modes.length;f<h;f++){var g=b.display_modes[f];a[g]=function(i){return function(){c(i)}}(g)}make_popupmenu(b.mode_div,a)}else{b.mode_div.hide()}}var d={};d["Set as overview"]=function(){j.overview_viewport.find("canvas").remove();b.is_overview=true;b.set_overview();for(var i in j.tracks){if(j.tracks[i]!==b){j.tracks[i].is_overview=false}}};d["Edit configuration"]=function(){var l=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},i=function(){b.update_options(b.track_
id);hide_modal();$(window).unbind("keypress.check_enter_esc")},k=function(m){if((m.keyCode||m.which)===27){l()}else{if((m.keyCode||m.which)===13){i()}}};$(window).bind("keypress.check_enter_esc",k);show_modal("Configure Track",b.gen_options(b.track_id),{Cancel:l,OK:i})};if(b.filters.length>0){d["Show filters"]=function(){var i;if(!b.filtering_div.is(":visible")){i="Hide filters";b.filters_visible=true}else{i="Show filters";b.filters_visible=false}$("#"+b.name_div.attr("id")+"-menu").find("li").eq(2).text(i);b.filtering_div.toggle()}}d.Remove=function(){j.remove_track(b);if(j.num_tracks===0){$("#no-tracks").show()}};b.popup_menu=make_popupmenu(b.name_div,d);show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters",false)};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(a){var k=this.view.low,g=this.view.high,h=g-k,f=this.view.resolution;var n=$("<div style='position: relative;'></div>"),o=this.content_div.width()/h;this.content_div.append(n);this.max_height=
0;var b=Math.floor(k/f/DENSITY);var j={};while((b*DENSITY*f)<g){var l=this.content_div.width()+"_"+o+"_"+b;var e=this.tile_cache.get(l);if(!a&&e){var i=b*DENSITY*f;var d=(i-k)*o;if(this.left_offset){d-=this.left_offset}e.css({left:d});this.show_tile(e,n)}else{this.delayed_draw(this,l,k,g,b,f,n,o,j)}b+=1}var c=this;var m=setInterval(function(){if(obj_length(j)===0){if(c.content_div.children().length>1){c.content_div.children(":first").remove()}for(var p=0;p<c.filters.length;p++){c.filters[p].update_ui_elt()}clearInterval(m)}},50)},delayed_draw:function(c,h,g,e,b,d,i,j,f){var a=setTimeout(function(){if(g<=c.view.high&&e>=c.view.low){var k=c.draw_tile(d,b,i,j);if(k){if(!c.initial_canvas&&!window.G_vmlCanvasManager){c.initial_canvas=$(k).clone();var n=k.get(0).getContext("2d");var l=c.initial_canvas.get(0).getContext("2d");var m=n.getImageData(0,0,n.canvas.width,n.canvas.height);l.putImageData(m,0,0);c.set_overview()}c.tile_cache.set(h,k);c.show_tile(k,i)}}delete f[a]},50);f[a]=
true},show_tile:function(a,c){var b=this;c.append(a);b.max_height=Math.max(b.max_height,a.height());b.content_div.css("height",b.max_height+"px");if(a.hasClass(FILTERABLE_CLASS)){show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters");if(b.filters_visible){b.filtering_div.show()}}else{show_hide_popupmenu_options(b.popup_menu,"(Show|Hide) filters",false);b.filtering_div.hide()}},set_overview:function(){var a=this.view;if(this.initial_canvas&&this.is_overview){a.overview_close.show();a.overview_viewport.append(this.initial_canvas);a.overview_highlight.show().height(this.initial_canvas.height());a.overview_viewport.height(this.initial_canvas.height()+a.overview_box.height())}$(window).trigger("resize")}});var LabelTrack=function(a,b){this.track_type="LabelTrack";this.hidden=true;Track.call(this,null,a,b);this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.
floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";this.hidden=true;Track.call(this,null,a,a.top_labeltrack);TiledTrack.call(this);this.left_offset=200;this.height_px=12;this.container_div.addClass("reference-track");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g)
{c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,j=f+"_"+b;var e=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(e)}e=$(e);var n=e.get(0).getContext("2d");if(o>PX_PER_CHAR){if(this.data_cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){this.content_div.css("height","0px");return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o-this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o),i=Math.round(o/2);n.fillText(m[h],a+this.left_offset+i,10)}k.append(e);return e}this.content_div.css("height","0px")}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";Track.call(this,d,b,b.viewport_conta
iner);TiledTrack.call(this);this.height_px=80;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={color:"black",min_value:undefined,max_value:undefined,mode:this.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");var e=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=e.min;a.prefs.max_value=e.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=e.total_frequency;a.container_div.find(".yaxislabel").remove();var f=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(round_1000(a.prefs.min_value));v
ar d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(round_1000(a.prefs.max_value));d.css({position:"absolute",top:"22px",left:"10px"});d.prependTo(a.container_div);f.css({position:"absolute",top:a.height_px+11+"px",left:"10px"});f.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){var h=g.data;c.data_cache.set(e,h);delete c.data_queue[e];c.draw()},error:function(h,g,i){console.log(h,g,i)}})}},draw_tile:function(o,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*o,a=DENSITY*o,w=o+"_"+r;var b=document.createElement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(b)}b=$(b);if(this.data_cache.get(w)===undefined){this.get_data(o,r);return}var v=this.data_cache.
get(w);if(!v){return}b.css({position:"absolute",top:0,left:(s-this.view.low)*e});b.get(0).width=Math.ceil(a*e);b.get(0).height=this.height_px;var n=b.get(0).getContext("2d"),j=false,k=this.prefs.min_value,g=this.prefs.max_value,m=this.vertical_range,t=this.total_frequency,d=this.height_px,l=this.mode;n.beginPath();n.fillStyle=this.prefs.color;var u,h,f;if(v.length>1){f=Math.ceil((v[1][0]-v[0][0])*e)}else{f=10}for(var p=0,q=v.length;p<q;p++){u=Math.round((v[p][0]-s)*e);h=v[p][1];if(h===null){if(j&&l==="Filled"){n.lineTo(u,d)}j=false;continue}if(h<k){h=k}else{if(h>g){h=g}}if(l==="Histogram"){h=Math.round(d-(h-k)/m*d);n.fillRect(u,h,f,d-h)}else{if(l==="Intensity"){h=255-Math.floor((h-k)/m*255);n.fillStyle="rgb("+h+","+h+","+h+")";n.fillRect(u,0,f,d)}else{h=Math.round(d-(h-k)/m*d);if(j){n.lineTo(u,h)}else{j=true;if(l==="Filled"){n.moveTo(u,d);n.lineTo(u,h)}else{n.moveTo(u,h)}}}}}if(l==="Filled"){if(j){n.lineTo(u,d)}n.fill()}else{n.stroke()}c.append(b);return b},gen_options:funct
ion(m){var a=$("<div />").addClass("form-row");var e="track_"+m+"_color",b=$("<label />").attr("for",e).text("Color:"),c=$("<input />").attr("id",e).attr("name",e).val(this.prefs.color),h="track_"+m+"_minval",l=$("<label></label>").attr("for",h).text("Min value:"),d=(this.prefs.min_value===undefined?"":this.prefs.min_value),k=$("<input></input>").attr("id",h).val(d),j="track_"+m+"_maxval",g=$("<label></label>").attr("for",j).text("Max value:"),i=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",j).val(i);return a.append(l).append(k).append(g).append(f).append(b).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_color").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!==this.prefs.color){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.color=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetr
ack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,e,c){this.track_type="FeatureTrack";this.display_modes=["Auto","Dense","Squish","Pack"];Track.call(this,d,b,b.viewport_container,e);TiledTrack.call(this);this.height_px=0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.summary_draw_height=30;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.left_offset=200;this.prefs={block_color:"#444",label_color:"black",show_counts:true}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b="initial";this.init_each({low:a.view.max_low,high:a.view.m
ax_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution,mode:a.mode},function(c){a.mode_div.show();a.data_cache.set(b,c);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,g,b,q){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=a;this.inc_slots[a].mode=q;this.s_e_by_tile[a]={}}var m=this.inc_slots[a].w_scale,y=[],h=0,n=this.view.max_low;var A=[];if(this.inc_slots[a].mode!==q){delete this.inc_slots[a];this.inc_slots[a]={mode:q,w_scale:m};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var v=0,w=g.length;v<w;v++){var f=g[v],l=f[0];if(this.inc_slots[a][l]!==undefined){h=Math.max(h,this.inc_slots[a][l]);A.push(this.inc_slots[a][l])}else{y.push(v)}}for(var v=0,w
=y.length;v<w;v++){var f=g[y[v]],l=f[0],r=f[1],c=f[2],p=f[3],d=Math.floor((r-n)*m),e=Math.ceil((c-n)*m);if(p!==undefined&&!b){var s=CONTEXT.measureText(p).width;if(d-s<0){e+=s}else{d-=s}}var u=0;while(u<=MAX_FEATURE_DEPTH){var o=true;if(this.s_e_by_tile[a][u]!==undefined){for(var t=0,z=this.s_e_by_tile[a][u].length;t<z;t++){var x=this.s_e_by_tile[a][u][t];if(e>x[0]&&d<x[1]){o=false;break}}}if(o){if(this.s_e_by_tile[a][u]===undefined){this.s_e_by_tile[a][u]=[]}this.s_e_by_tile[a][u].push([d,e]);this.inc_slots[a][l]=u;h=Math.max(h,u);break}u++}}return h},rect_or_text:function(r,l,t,b,q,f,i,e){r.textAlign="center";var k=0,p=Math.round(l/2);for(var m=0,s=i.length;m<s;m++){var j=i[m],d="MIDNSHP"[j[0]],n=j[1];if(d==="H"||d==="S"){k-=n}var g=q+k,w=Math.floor(Math.max(0,(g-t)*l)),h=Math.floor(Math.max(0,(g+n-t)*l));switch(d){case"S":case"H":case"M":var o=f.slice(k,n);if((this.mode==="Pack"||this.mode==="Auto")&&f!==undefined&&l>PX_PER_CHAR){r.fillStyle=this.prefs.block_color;r.fillR
ect(w+this.left_offset,e+1,h-w,9);r.fillStyle=CONNECTOR_COLOR;for(var u=0,a=o.length;u<a;u++){if(g+u>=t&&g+u<=b){var v=Math.floor(Math.max(0,(g+u-t)*l));r.fillText(o[u],v+this.left_offset+p,e+9)}}}else{r.fillStyle=this.prefs.block_color;r.fillRect(w+this.left_offset,e+4,h-w,3)}break;case"N":r.fillStyle=CONNECTOR_COLOR;r.fillRect(w+this.left_offset,e+5,h-w,1);break;case"D":r.fillStyle="red";r.fillRect(w+this.left_offset,e+4,h-w,3);break;case"P":case"I":break}k+=n}},draw_tile:function(ag,o,s,av){var N=o*DENSITY*ag,al=(o+1)*DENSITY*ag,M=al-N;var an=(!this.initial_canvas?"initial":N+"_"+al);var I=this.data_cache.get(an);var e;if(I===undefined||(this.mode!=="Auto"&&I.dataset_type==="summary_tree")){this.data_queue[[N,al]]=true;this.get_data(N,al);return}var a=Math.ceil(M*av),ai=this.prefs.label_color,l=this.prefs.block_color,r=this.mode,z=25,ae=(r==="Squish")||(r==="Dense")&&(r!=="Pack")||(r==="Auto"&&(I.extra_info==="no_detail")),W=this.left_offset,au,D,aw;var q=document.createE
lement("canvas");if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(q)}q=$(q);if(I.dataset_type==="summary_tree"){D=this.summary_draw_height}else{if(r==="Dense"){D=z;aw=10}else{aw=(ae?this.vertical_nodetail_px:this.vertical_detail_px);var A=(av<0.0001?1/this.view.zoom_res:av);D=this.incremental_slots(A,I.data,ae,r)*aw+z;au=this.inc_slots[A]}}q.css({position:"absolute",top:0,left:(N-this.view.low)*av-W});q.get(0).width=a+W;q.get(0).height=D;s.parent().css("height",Math.max(this.height_px,D)+"px");var J=q.get(0).getContext("2d");J.fillStyle=l;J.font=this.default_font;J.textAlign="right";this.container_div.find(".yaxislabel").remove();if(I.dataset_type=="summary_tree"){var Y=I.data,L=I.max,b=Math.ceil(I.delta*av);var p=$("<div />").addClass("yaxislabel").text(L);p.css({position:"absolute",top:"22px",left:"10px"});p.prependTo(this.container_div);for(var ap=0,H=Y.length;ap<H;ap++){var aa=Math.floor((Y[ap][0]-N)*av);var Z=Y[ap][1];if(!Z){continue}var am=Z/L*this.summary_
draw_height;J.fillStyle="black";J.fillRect(aa+W,this.summary_draw_height-am,b,am);if(this.prefs.show_counts&&J.measureText(Z).width<b){J.fillStyle="#bbb";J.textAlign="center";J.fillText(Z,aa+W+(b/2),this.summary_draw_height-5)}}e="Summary";s.append(q);return q}if(I.message){q.css({border:"solid red","border-width":"2px 2px 2px 0px"});J.fillStyle="red";J.textAlign="left";J.fillText(I.message,100+W,aw)}var ad=false;if(I.data){ad=true;for(var ar=0;ar<this.filters.length;ar++){if(!this.filters[ar].applies_to(I.data[0])){ad=false}}}if(ad){q.addClass(FILTERABLE_CLASS)}var at=I.data;var ao=0;for(var ap=0,H=at.length;ap<H;ap++){var S=at[ap],R=S[0],aq=S[1],ac=S[2],O=S[3];if(au[R]===undefined){continue}var ab=false;var U;for(var ar=0;ar<this.filters.length;ar++){U=this.filters[ar];U.update_attrs(S);if(!U.keep(S)){ab=true;break}}if(ab){continue}if(aq<=al&&ac>=N){var af=Math.floor(Math.max(0,(aq-N)*av)),K=Math.ceil(Math.min(a,Math.max(0,(ac-N)*av))),X=(r==="Dense"?1:(1+au[R]))*aw;var G,
aj,P=null,ax=null;if(I.dataset_type==="bai"){var v=S[4];J.fillStyle=l;if(S[5] instanceof Array){var E=Math.floor(Math.max(0,(S[5][0]-N)*av)),Q=Math.ceil(Math.min(a,Math.max(0,(S[5][1]-N)*av))),C=Math.floor(Math.max(0,(S[6][0]-N)*av)),w=Math.ceil(Math.min(a,Math.max(0,(S[6][1]-N)*av)));if(S[5][1]>=N&&S[5][0]<=al){this.rect_or_text(J,av,N,al,S[5][0],S[5][2],v,X)}if(S[6][1]>=N&&S[6][0]<=al){this.rect_or_text(J,av,N,al,S[6][0],S[6][2],v,X)}if(C>Q){J.fillStyle=CONNECTOR_COLOR;J.fillRect(Q+W,X+5,C-Q,1)}}else{J.fillStyle=l;this.rect_or_text(J,av,N,al,aq,O,v,X)}if(r!=="Dense"&&!ae&&aq>N){J.fillStyle=this.prefs.label_color;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(R,K+2+W,X+8)}else{J.textAlign="right";J.fillText(R,af-2+W,X+8)}J.fillStyle=l}}else{if(I.dataset_type==="interval_index"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var F=S[4],V=S[5],ah=S[6],h=S[7];if(V&&ah){P=Math.floor(Math.max(0,(V-N)*av));ax=Math.ceil(Math.min(a,Math.max(0,(ah-N)*av)
))}if(r!=="Dense"&&O!==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}if(h){if(F){if(F=="+"){J.fillStyle=RIGHT_STRAND}else{if(F=="-"){J.fillStyle=LEFT_STRAND}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}for(var an=0,g=h.length;an<g;an++){var u=h[an],d=Math.floor(Math.max(0,(u[0]-N)*av)),T=Math.ceil(Math.min(a,Math.max((u[1]-N)*av)));if(d>T){continue}G=5;aj=3;J.fillRect(d+W,X+aj,T-d,G);if(P!==undefined&&!(d>ax||T<P)){G=9;aj=1;var ak=Math.max(d,P),B=Math.min(T,ax);J.fillRect(ak+W,X+aj,B-ak,G)}}}else{G=9;aj=1;J.fillRect(af+W,X+aj,K-af,G);if(S.strand){if(S.strand=="+"){J.fillStyle=RIGHT_STRAND_INV}else{if(S.strand=="-"){J.fillStyle=LEFT_STRAND_INV}}J.fillRect(af+W,X,K-af,10);J.fillStyle=l}}}}else{if(I.dataset_type==="vcf"){if(ae){J.fillStyle=l;J.fillRect(af+W,X+5,K-af,1)}else{var t=S[4],n=S[5],c=S[6];G=9;aj=1;J.fillRect(af+W,X,K-af,G);if(r!=="Dense"&&O!
==undefined&&aq>N){J.fillStyle=ai;if(o===0&&af-J.measureText(O).width<0){J.textAlign="left";J.fillText(O,K+2+W,X+8)}else{J.textAlign="right";J.fillText(O,af-2+W,X+8)}J.fillStyle=l}var m=t+" / "+n;if(aq>N&&J.measureText(m).width<(K-af)){J.fillStyle="white";J.textAlign="center";J.fillText(m,W+af+(K-af)/2,X+8);J.fillStyle=l}}}}}ao++}}return q},gen_options:function(i){var a=$("<div />").addClass("form-row");var e="track_"+i+"_block_color",k=$("<label />").attr("for",e).text("Block color:"),l=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),j="track_"+i+"_label_color",g=$("<label />").attr("for",j).text("Text color:"),h=$("<input />").attr("id",j).attr("name",j).val(this.prefs.label_color),f="track_"+i+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(k).append(
l).append(g).append(h).append(d)},update_options:function(d){var b=$("#track_"+d+"_block_color").val(),c=$("#track_"+d+"_label_color").val(),a=$("#track_"+d+"_show_count").attr("checked");if(b!==this.prefs.block_color||c!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=c;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,e,c){FeatureTrack.call(this,d,b,a,e,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
1
0

galaxy-dist commit 591c53b44ae4: Fixes for links that direct admin and regular users to different views of selected or transferred sample dataset files.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1289487850 18000
# Node ID 591c53b44ae4a6237a841adaa3abfe59829beebe
# Parent bbc0f56e3e16f93bf3c81d09b0fa12876a3f2579
Fixes for links that direct admin and regular users to different views of selected or transferred sample dataset files.
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -125,7 +125,7 @@
can_delete_samples = not is_complete
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
- display_datasets = request.samples and ( is_complete or is_rejected or is_submitted )
+ display_datasets = request.samples and ( is_complete or is_submitted )
else:
is_complete = False
is_submitted = False
@@ -175,33 +175,44 @@
<td valign="top">
## An admin can select the datasets to transfer, while a non-admin can only view what has been selected
%if is_admin:
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
+ ## This link will direct the admin to a page allowing them to select datasets.
+ <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id= trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%elif sample.datasets:
- ## Only display a link if there is at least 1 selected dataset for the sample
- <a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a></td>
+ ## Since this is a regular user, only display a link if there is at least 1
+ ## selected dataset for the sample.
+ <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%else:
+ ## Since this is a regular user, do not display a link if there are no datasets.
${len( sample.datasets )}
%endif
</td><td valign="top">
%if is_admin:
- %if sample.untransferred_dataset_files:
+ <%
+ if sample.transferred_dataset_files:
+ transferred_dataset_files = sample.transferred_dataset_files
+ else:
+ transferred_dataset_files = []
+ %>
+ %if not sample.datasets:
+ ## No datasets have been selected for this sample, so don't include a link
+ ${len( sample.transferred_dataset_files )}
+ %elif len( sample.datasets ) > len( transferred_dataset_files ):
## At least 1 selected dataset is not yet transferred, so this link
## will direct the admin to a page allowing them to transfer datasets.
- <a href="${h.url_for( controller='requests_common', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
- %else:
+ <a href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %elif len( sample.datasets ) == len( transferred_dataset_files ):
## All selected datasets have successfully transferred, so this link
## will direct the admin to a page displaying all transferred datasets.
<a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=trans.model.SampleDataset.transfer_status.COMPLETE )}">${len( sample.transferred_dataset_files )}</a>
%endif
%else:
%if sample.transferred_dataset_files:
- ## The cuurent user is not an admin, so this link will direct the
- ## user to the target data library containing those datasets that
- ## were successfully transferred.
+ ## Since this is a regular user, this link will direct them to the target
+ ## data library containing those datasets that were successfully transferred.
<a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">${len( sample.transferred_dataset_files )}</a>
%else:
- ## Display a 0 with no link.
+ ## Since this is a regular user, do not display a link.
${len( sample.transferred_dataset_files )}
%endif
%endif
@@ -228,7 +239,7 @@
can_select_datasets = is_admin and current_samples and ( is_submitted or is_complete )
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
- display_datasets = request.samples and ( is_complete or is_rejected or is_submitted )
+ display_datasets = request.samples and ( is_complete or is_submitted )
%>
${grid_header}
%if render_buttons and ( can_add_samples or can_edit_samples ):
@@ -314,39 +325,44 @@
<td>
## An admin can select the datasets to transfer, while a non-admin can only view what has been selected
%if is_admin:
- %if not sample.datasets:
- ## If there are no selected datasets, display a page alowing the admin to select some.
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id= trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
- %else:
- ## If there are selected datasets, display them
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
- %endif
+ ## This link will direct the admin to a page allowing them to select datasets.
+ <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id= trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%elif sample.datasets:
- ## Only display a link if there is at least 1 selected dataset for the sample
+ ## Since this is a regular user, only display a link if there is at least 1
+ ## selected dataset for the sample.
<a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%else:
+ ## Since this is a regular user, do not display a link if there are no datasets.
${len( sample.datasets )}
%endif
</td><td>
%if is_admin:
- %if sample.untransferred_dataset_files:
+ <%
+ if sample.transferred_dataset_files:
+ transferred_dataset_files = sample.transferred_dataset_files
+ else:
+ transferred_dataset_files = []
+ %>
+ %if not sample.datasets:
+ ## No datasets have been selected for this sample, so don't include a link
+ ${len( sample.transferred_dataset_files )}
+ %elif len( sample.datasets ) > len( transferred_dataset_files ):
## At least 1 selected dataset is not yet transferred, so this link
## will direct the admin to a page allowing them to transfer datasets.
- <a href="${h.url_for( controller='requests_common', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
- %else:
+ <a href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %elif len( sample.datasets ) == len( transferred_dataset_files ):
## All selected datasets have successfully transferred, so this link
## will direct the admin to a page displaying all transferred datasets.
<a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=trans.model.SampleDataset.transfer_status.COMPLETE )}">${len( sample.transferred_dataset_files )}</a>
%endif
%else:
%if sample.transferred_dataset_files:
- ## The cuurent user is not an admin, so this link will direct the
- ## user to the target data library containing those datasets that
- ## were successfully transferred.
+ ## Since this is a regular user, this link will direct them to the target
+ ## data library containing those datasets that were successfully transferred.
<a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">${len( sample.transferred_dataset_files )}</a>
%else:
- ## Display a 0 with no link.
+ ## Since this is a regular user, do not display a link.
${len( sample.transferred_dataset_files )}
%endif
%endif
--- a/templates/requests/common/view_sample_datasets.mako
+++ b/templates/requests/common/view_sample_datasets.mako
@@ -37,7 +37,7 @@
${render_sample_datasets( cntrller, sample, sample_datasets, title )}
%else:
%if transfer_status:
- No datasets with status ${transfer_status}" belong to this sample
+ No datasets with status "${transfer_status}" belong to this sample
%else:
No datasets have been selected for this sample.
%endif
1
0

galaxy-dist commit d56f296aaa61: Minimally functional splitting.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dannon Baker <dannonbaker(a)me.com>
# Date 1289408765 18000
# Node ID d56f296aaa610a537d35cb7d235eac9d8f596464
# Parent d6a0dd8e55e2f7d2077bc282bca3e42d98fbb7f2
Minimally functional splitting.
Disabled by default, not advisable to enable on a production server (or main!) until scheduling issues are looked at and performance analysis has been done.
Tested 'basic' splitting with many basic tools (bowtie, bwa, filter sam, others). This style of splitting should work for most 'embarassingly parallel' one input, one output tools (no dependence between parallel tasks).
--- a/tools/sr_mapping/bowtie_wrapper.xml
+++ b/tools/sr_mapping/bowtie_wrapper.xml
@@ -1,6 +1,7 @@
<tool id="bowtie_wrapper" name="Map with Bowtie for Illumina" version="1.1.0"><requirements><requirement type='package'>bowtie</requirement></requirements><description></description>
+ <parallelism method="basic"></parallelism><command interpreter="python">
bowtie_wrapper.py
--threads="4"
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1,10 +1,11 @@
-import logging, threading, sys, os, time, subprocess, string, tempfile, re, traceback, shutil
+import logging, threading, sys, os, time, traceback, shutil
import galaxy
from galaxy import util, model
from galaxy.model.orm import lazyload
from galaxy.datatypes.tabular import *
from galaxy.datatypes.interval import *
+# tabular/interval imports appear to be unused. Clean up?
from galaxy.datatypes import metadata
from galaxy.util.json import from_json_string
from galaxy.util.expressions import ExpressionContext
@@ -13,8 +14,6 @@ from galaxy.jobs.actions.post import Act
import pkg_resources
pkg_resources.require( "PasteDeploy" )
-from paste.deploy.converters import asbool
-
from Queue import Queue, Empty
log = logging.getLogger( __name__ )
@@ -83,11 +82,9 @@ class JobQueue( object ):
self.parent_pid = os.getpid()
# Contains new jobs. Note this is not used if track_jobs_in_database is True
self.queue = Queue()
-
# Contains jobs that are waiting (only use from monitor thread)
## This and jobs_to_check[] are closest to a "Job Queue"
self.waiting_jobs = []
-
# Helper for interruptable sleep
self.sleeper = Sleeper()
self.running = True
@@ -104,7 +101,7 @@ class JobQueue( object ):
the database and requeues or cleans up as necessary. Only run as the
job manager starts.
"""
- model = self.app.model
+ model = self.app.model # DBTODO Why?
for job in self.sa_session.query( model.Job ).filter( model.Job.state == model.Job.states.NEW ):
if job.tool_id not in self.app.toolbox.tools_by_id:
log.warning( "Tool '%s' removed from tool config, unable to recover job: %s" % ( job.tool_id, job.id ) )
@@ -294,7 +291,10 @@ class JobWrapper( object ):
self.tool_provided_job_metadata = None
# Wrapper holding the info required to restore and clean up from files used for setting metadata externally
self.external_output_metadata = metadata.JobExternalOutputMetadataWrapper( job )
-
+
+ def get_job( self ):
+ return self.sa_session.query( model.Job ).get( self.job_id )
+
def get_param_dict( self ):
"""
Restore the dictionary of parameters from the database.
@@ -479,9 +479,9 @@ class JobWrapper( object ):
self.fail( job.info )
return
if stderr:
- job.state = "error"
+ job.state = job.states.ERROR
else:
- job.state = 'ok'
+ job.state = job.states.OK
if self.app.config.outputs_to_working_directory:
for dataset_path in self.get_output_fnames():
try:
@@ -761,6 +761,215 @@ class JobWrapper( object ):
else:
return 'anonymous@unknown'
+class TaskWrapper(JobWrapper):
+ """
+ Extension of JobWrapper intended for running tasks.
+ Should be refactored into a generalized executable unit wrapper parent, then jobs and tasks.
+ """
+ # Abstract this to be more useful for running tasks that *don't* necessarily compose a job.
+
+ def __init__(self, task, queue):
+ super(TaskWrapper, self).__init__(task.job, queue)
+ self.task_id = task.id
+ self.parallelism = None
+ if task.part_file:
+ #do this better
+ self.working_directory = os.path.dirname(task.part_file)
+ else:
+ self.working_directory = None
+ self.status = task.states.NEW
+
+ def get_job( self ):
+ if self.job_id:
+ return self.sa_session.query( model.Job ).get( self.job_id )
+ else:
+ return None
+
+ def get_task( self ):
+ return self.sa_session.query(model.Task).get(self.task_id)
+
+ def get_param_dict( self ):
+ """
+ Restore the dictionary of parameters from the database.
+ """
+ job = self.sa_session.query( model.Job ).get( self.job_id )
+ param_dict = dict( [ ( p.name, p.value ) for p in job.parameters ] )
+ param_dict = self.tool.params_from_strings( param_dict, self.app )
+ return param_dict
+
+ def prepare( self ):
+ """
+ Prepare the job to run by creating the working directory and the
+ config files.
+ """
+ # Restore parameters from the database
+ job = self.get_job()
+ task = self.get_task()
+ if job.user is None and job.galaxy_session is None:
+ raise Exception( 'Job %s has no user and no session.' % job.id )
+ incoming = dict( [ ( p.name, p.value ) for p in job.parameters ] )
+ incoming = self.tool.params_from_strings( incoming, self.app )
+ # Do any validation that could not be done at job creation
+ self.tool.handle_unvalidated_param_values( incoming, self.app )
+ # Restore input / output data lists
+ inp_data = dict( [ ( da.name, da.dataset ) for da in job.input_datasets ] )
+ # DBTODO New method for generating command line for a task?
+ out_data = dict( [ ( da.name, da.dataset ) for da in job.output_datasets ] )
+ out_data.update( [ ( da.name, da.dataset ) for da in job.output_library_datasets ] )
+ # These can be passed on the command line if wanted as $userId $userEmail
+ if job.history and job.history.user: # check for anonymous user!
+ userId = '%d' % job.history.user.id
+ userEmail = str(job.history.user.email)
+ else:
+ userId = 'Anonymous'
+ userEmail = 'Anonymous'
+ incoming['userId'] = userId
+ incoming['userEmail'] = userEmail
+ # Build params, done before hook so hook can use
+ param_dict = self.tool.build_param_dict( incoming, inp_data, out_data, self.get_output_fnames(), self.working_directory )
+ fnames = {}
+ for v in self.get_input_fnames():
+ fnames[v] = os.path.join(self.working_directory, os.path.basename(v))
+ for dp in [x.real_path for x in self.get_output_fnames()]:
+ fnames[dp] = os.path.join(self.working_directory, os.path.basename(dp))
+ # Certain tools require tasks to be completed prior to job execution
+ # ( this used to be performed in the "exec_before_job" hook, but hooks are deprecated ).
+ self.tool.exec_before_job( self.queue.app, inp_data, out_data, param_dict )
+ # Run the before queue ("exec_before_job") hook
+ self.tool.call_hook( 'exec_before_job', self.queue.app, inp_data=inp_data,
+ out_data=out_data, tool=self.tool, param_dict=incoming)
+ self.sa_session.flush()
+ # Build any required config files
+ config_filenames = self.tool.build_config_files( param_dict, self.working_directory )
+ # FIXME: Build the param file (might return None, DEPRECATED)
+ param_filename = self.tool.build_param_file( param_dict, self.working_directory )
+ # Build the job's command line
+ self.command_line = self.tool.build_command_line( param_dict )
+ # HACK, Fix this when refactored.
+ for k, v in fnames.iteritems():
+ self.command_line = self.command_line.replace(k, v)
+ # FIXME: for now, tools get Galaxy's lib dir in their path
+ if self.command_line and self.command_line.startswith( 'python' ):
+ self.galaxy_lib_dir = os.path.abspath( "lib" ) # cwd = galaxy root
+ # Shell fragment to inject dependencies
+ if self.app.config.use_tool_dependencies:
+ self.dependency_shell_commands = self.tool.build_dependency_shell_commands()
+ else:
+ self.dependency_shell_commands = None
+ # We need command_line persisted to the db in order for Galaxy to re-queue the job
+ # if the server was stopped and restarted before the job finished
+ task.command_line = self.command_line
+ self.sa_session.add( task )
+ self.sa_session.flush()
+ # # Return list of all extra files
+ extra_filenames = config_filenames
+ if param_filename is not None:
+ extra_filenames.append( param_filename )
+ self.param_dict = param_dict
+ self.extra_filenames = extra_filenames
+ self.status = 'prepared'
+ return extra_filenames
+
+ def fail( self, message, exception=False ):
+ log.error("TaskWrapper Failure %s" % message)
+ self.status = 'error'
+ # How do we want to handle task failure? Fail the job and let it clean up?
+
+ def change_state( self, state, info = False ):
+ task = self.get_task()
+ self.sa_session.refresh( task )
+ if info:
+ task.info = info
+ task.state = state
+ self.sa_session.add( task )
+ self.sa_session.flush()
+
+ def get_state( self ):
+ task = self.get_task()
+ self.sa_session.refresh( task )
+ return task.state
+
+ def set_runner( self, runner_url, external_id ):
+ task = self.get_task()
+ self.sa_session.refresh( task )
+ task.task_runner_name = runner_url
+ task.task_runner_external_id = external_id
+ # DBTODO Check task job_runner_stuff
+ self.sa_session.add( task )
+ self.sa_session.flush()
+
+ def finish( self, stdout, stderr ):
+ # DBTODO integrate previous finish logic.
+ # Simple finish for tasks. Just set the flag OK.
+ log.debug( 'task %s for job %d ended' % (self.task_id, self.job_id) )
+ """
+ Called to indicate that the associated command has been run. Updates
+ the output datasets based on stderr and stdout from the command, and
+ the contents of the output files.
+ """
+ # default post job setup_external_metadata
+ self.sa_session.expunge_all()
+ task = self.get_task()
+ # if the job was deleted, don't finish it
+ if task.state == task.states.DELETED:
+ self.cleanup()
+ return
+ elif task.state == task.states.ERROR:
+ # Job was deleted by an administrator
+ self.fail( task.info )
+ return
+ if stderr:
+ task.state = task.states.ERROR
+ else:
+ task.state = task.states.OK
+ # Save stdout and stderr
+ if len( stdout ) > 32768:
+ log.error( "stdout for task %d is greater than 32K, only first part will be logged to database" % task.id )
+ task.stdout = stdout[:32768]
+ if len( stderr ) > 32768:
+ log.error( "stderr for job %d is greater than 32K, only first part will be logged to database" % task.id )
+ task.stderr = stderr[:32768]
+ task.command_line = self.command_line
+ self.sa_session.flush()
+ log.debug( 'task %d ended' % self.task_id )
+
+ def cleanup( self ):
+ # There is no task cleanup. The job cleans up for all tasks.
+ pass
+
+ def get_command_line( self ):
+ return self.command_line
+
+ def get_session_id( self ):
+ return self.session_id
+
+ def get_output_file_id( self, file ):
+ # There is no permanent output file for tasks.
+ return None
+
+ def get_tool_provided_job_metadata( self ):
+ # DBTODO Handle this as applicable for tasks.
+ return None
+
+ def get_dataset_finish_context( self, job_context, dataset ):
+ # Handled at the parent job level. Do nothing here.
+ pass
+
+ def check_output_sizes( self ):
+ sizes = []
+ output_paths = self.get_output_fnames()
+ for outfile in [ str( o ) for o in output_paths ]:
+ sizes.append( ( outfile, os.stat( outfile ).st_size ) )
+ return sizes
+
+ def setup_external_metadata( self, exec_dir = None, tmp_dir = None, dataset_files_path = None, config_root = None, datatypes_config = None, set_extension = True, **kwds ):
+ # There is no metadata setting for tasks. This is handled after the merge, at the job level.
+ pass
+
+ @property
+ def user( self ):
+ pass
+
class DefaultJobDispatcher( object ):
def __init__( self, app ):
self.app = app
@@ -768,10 +977,15 @@ class DefaultJobDispatcher( object ):
start_job_runners = ["local"]
if app.config.start_job_runners is not None:
start_job_runners.extend( app.config.start_job_runners.split(",") )
+ if app.config.use_tasked_jobs:
+ start_job_runners.append("tasks")
for runner_name in start_job_runners:
if runner_name == "local":
import runners.local
self.job_runners[runner_name] = runners.local.LocalJobRunner( app )
+ elif runner_name == "tasks":
+ import runners.tasks
+ self.job_runners[runner_name] = runners.tasks.TaskedJobRunner( app )
elif runner_name == "pbs":
import runners.pbs
self.job_runners[runner_name] = runners.pbs.PBSJobRunner( app )
@@ -782,12 +996,17 @@ class DefaultJobDispatcher( object ):
import runners.drmaa
self.job_runners[runner_name] = runners.drmaa.DRMAAJobRunner( app )
else:
- log.error( "Unable to start unknown job runner: %s" %runner_name )
+ log.error( "Unable to start unknown job runner: '%s'" %runner_name )
def put( self, job_wrapper ):
- runner_name = ( job_wrapper.tool.job_runner.split(":", 1) )[0]
- log.debug( "dispatching job %d to %s runner" %( job_wrapper.job_id, runner_name ) )
- self.job_runners[runner_name].put( job_wrapper )
+ if self.app.config.use_tasked_jobs and job_wrapper.tool.parallelism is not None and not isinstance(job_wrapper, TaskWrapper):
+ runner_name = "tasks"
+ log.debug( "dispatching job %d to %s runner" %( job_wrapper.job_id, runner_name ) )
+ self.job_runners[runner_name].put( job_wrapper )
+ else:
+ runner_name = ( job_wrapper.tool.job_runner.split(":", 1) )[0]
+ log.debug( "dispatching job %d to %s runner" %( job_wrapper.job_id, runner_name ) )
+ self.job_runners[runner_name].put( job_wrapper )
def stop( self, job ):
runner_name = ( job.job_runner_name.split(":", 1) )[0]
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -176,6 +176,44 @@ class Job( object ):
dataset.peek = 'Job deleted'
dataset.info = 'Job output deleted by user before job completed'
+class Task( object ):
+ """
+ A task represents a single component of a job.
+ """
+ states = Bunch( NEW = 'new',
+ WAITING = 'waiting',
+ QUEUED = 'queued',
+ RUNNING = 'running',
+ OK = 'ok',
+ ERROR = 'error',
+ DELETED = 'deleted' )
+
+ def __init__( self, job, part_file = None ):
+ self.command_line = None
+ self.parameters = []
+ self.state = Task.states.NEW
+ self.info = None
+ self.part_file = part_file
+ self.task_runner_name = None
+ self.task_runner_external_id = None
+ self.job = job
+ self.stdout = None
+ self.stderr = None
+
+ def set_state( self, state ):
+ self.state = state
+
+ def get_param_values( self, app ):
+ """
+ Read encoded parameter values from the database and turn back into a
+ dict of tool parameter values.
+ """
+ param_dict = dict( [ ( p.name, p.value ) for p in self.parent_job.parameters ] )
+ tool = app.toolbox.tools_by_id[self.tool_id]
+ param_dict = tool.params_from_strings( param_dict, app )
+ return param_dict
+
+
class JobParameter( object ):
def __init__( self, name, value ):
self.name = name
--- a/tools/samtools/sam_bitwise_flag_filter.xml
+++ b/tools/samtools/sam_bitwise_flag_filter.xml
@@ -1,5 +1,6 @@
<tool id="sam_bw_filter" name="Filter SAM" version="1.0.0"><description>on bitwise flag values</description>
+ <parallelism method="basic"></parallelism><command interpreter="python">
sam_bitwise_flag_filter.py
--input_sam_file=$input1
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -367,7 +367,12 @@ class Tool:
self.redirect_url_params = ''
# Short description of the tool
self.description = util.xml_text(root, "description")
- # Job runner
+ # Parallelism for tasks, read from tool config.
+ parallelism = root.find("parallelism")
+ if parallelism is not None and parallelism.get("method"):
+ self.parallelism = parallelism.get("method")
+ else:
+ self.parallelism = None
if self.app.config.start_job_runners is None:
# Jobs are always local regardless of tool config if no additional
# runners are started
--- a/tools/sr_mapping/bwa_wrapper.xml
+++ b/tools/sr_mapping/bwa_wrapper.xml
@@ -1,5 +1,6 @@
<tool id="bwa_wrapper" name="Map with BWA" version="1.1.0"><description></description>
+ <parallelism method="basic"></parallelism><command interpreter="python">
bwa_wrapper.py
--threads="4"
--- /dev/null
+++ b/lib/galaxy/jobs/runners/tasks.py
@@ -0,0 +1,206 @@
+import logging
+import subprocess
+from Queue import Queue
+import threading
+
+from galaxy import model
+
+import os, errno
+from time import sleep
+
+from galaxy.jobs import TaskWrapper
+
+log = logging.getLogger( __name__ )
+
+class TaskedJobRunner( object ):
+ """
+ Job runner backed by a finite pool of worker threads. FIFO scheduling
+ """
+ STOP_SIGNAL = object()
+ def __init__( self, app ):
+ """Start the job runner with 'nworkers' worker threads"""
+ self.app = app
+ self.sa_session = app.model.context
+ # start workers
+ self.queue = Queue()
+ self.threads = []
+ nworkers = app.config.local_task_queue_workers
+ log.info( "Starting tasked-job runners" )
+ for i in range( nworkers ):
+ worker = threading.Thread( target=self.run_next )
+ worker.start()
+ self.threads.append( worker )
+ log.debug( "%d workers ready", nworkers )
+
+ def run_next( self ):
+ """Run the next job, waiting until one is available if neccesary"""
+ while 1:
+ job_wrapper = self.queue.get()
+ if job_wrapper is self.STOP_SIGNAL:
+ return
+ try:
+ self.run_job( job_wrapper )
+ except:
+ log.exception( "Uncaught exception running tasked job" )
+
+ def run_job( self, job_wrapper ):
+ job_wrapper.set_runner( 'tasks:///', None )
+ stderr = stdout = command_line = ''
+ # Prepare the job to run
+ try:
+ job_wrapper.prepare()
+ command_line = job_wrapper.get_command_line()
+ except:
+ job_wrapper.fail( "failure preparing job", exception=True )
+ log.exception("failure running job %d" % job_wrapper.job_id)
+ return
+ # If we were able to get a command line, run the job. ( must be passed to tasks )
+ if command_line:
+ try:
+ # DBTODO read tool info and use the right kind of parallelism.
+ # For now, the only splitter is the 'basic' one, n-ways split on one input, one output.
+ # This is incredibly simplified. Parallelism ultimately needs to describe which inputs, how, etc.
+ job_wrapper.change_state( model.Job.states.RUNNING )
+ self.sa_session.flush()
+ parent_job = job_wrapper.get_job()
+ # Split with the tool-defined method.
+ if job_wrapper.tool.parallelism == "basic":
+ from galaxy.jobs.splitters import basic
+ if len(job_wrapper.get_input_fnames()) > 1 or len(job_wrapper.get_output_fnames()) > 1:
+ log.error("The basic splitter is not capable of handling jobs with multiple inputs or outputs.")
+ job_wrapper.change_state( model.Job.states.ERROR )
+ job_wrapper.fail("Job Splitting Failed, the basic splitter only handles tools with one input and one output")
+ # Requeue as a standard job?
+ return
+ input_file = job_wrapper.get_input_fnames()[0]
+ working_directory = job_wrapper.working_directory
+ # DBTODO execute an external task to do the splitting, this should happen at refactor.
+ # Regarding number of ways split, use "hints" in tool config?
+ # If the number of tasks is sufficiently high, we can use it to calculate job completion % and give a running status.
+ basic.split(input_file, working_directory,
+ 20, #Needs serious experimentation to find out what makes the most sense.
+ parent_job.input_datasets[0].dataset.ext)
+ # Tasks in this parts list are in alphabetical listdir order (15 before 5), but that should not matter.
+ parts = [os.path.join(os.path.abspath(job_wrapper.working_directory), p, os.path.basename(input_file))
+ for p in os.listdir(job_wrapper.working_directory)
+ if p.startswith('task_')]
+ else:
+ job_wrapper.change_state( model.Job.states.ERROR )
+ job_wrapper.fail("Job Splitting Failed, no match for '%s'" % job_wrapper.tool.parallelism)
+ # Assemble parts into task_wrappers
+
+ # Not an option for now. Task objects don't *do* anything useful yet, but we'll want them tracked outside this thread to do anything.
+ # if track_tasks_in_database:
+ tasks = []
+ task_wrappers = []
+ for part in parts:
+ task = model.Task(parent_job, part)
+ self.sa_session.add(task)
+ tasks.append(task)
+ self.sa_session.flush()
+ # Must flush prior to the creation and queueing of task wrappers.
+ for task in tasks:
+ tw = TaskWrapper(task, job_wrapper.queue)
+ task_wrappers.append(tw)
+ self.app.job_manager.dispatcher.put(tw)
+ tasks_incomplete = False
+ sleep_time = 1
+ while tasks_incomplete is False:
+ tasks_incomplete = True
+ for tw in task_wrappers:
+ if not tw.get_state() == model.Task.states.OK:
+ tasks_incomplete = False
+ sleep( sleep_time )
+ if sleep_time < 8:
+ sleep_time *= 2
+ output_filename = job_wrapper.get_output_fnames()[0].real_path
+ basic.merge(working_directory, output_filename)
+ log.debug('execution finished: %s' % command_line)
+ for tw in task_wrappers:
+ stdout += tw.get_task().stdout
+ stderr += tw.get_task().stderr
+ except Exception:
+ job_wrapper.fail( "failure running job", exception=True )
+ log.exception("failure running job %d" % job_wrapper.job_id)
+ return
+
+ #run the metadata setting script here
+ #this is terminate-able when output dataset/job is deleted
+ #so that long running set_meta()s can be canceled without having to reboot the server
+ if job_wrapper.get_state() not in [ model.Job.states.ERROR, model.Job.states.DELETED ] and self.app.config.set_metadata_externally and job_wrapper.output_paths:
+ external_metadata_script = job_wrapper.setup_external_metadata( output_fnames = job_wrapper.get_output_fnames(),
+ set_extension = True,
+ kwds = { 'overwrite' : False } ) #we don't want to overwrite metadata that was copied over in init_meta(), as per established behavior
+ log.debug( 'executing external set_meta script for job %d: %s' % ( job_wrapper.job_id, external_metadata_script ) )
+ external_metadata_proc = subprocess.Popen( args = external_metadata_script,
+ shell = True,
+ env = os.environ,
+ preexec_fn = os.setpgrp )
+ job_wrapper.external_output_metadata.set_job_runner_external_pid( external_metadata_proc.pid, self.sa_session )
+ external_metadata_proc.wait()
+ log.debug( 'execution of external set_meta finished for job %d' % job_wrapper.job_id )
+
+ # Finish the job
+ try:
+ job_wrapper.finish( stdout, stderr )
+ except:
+ log.exception("Job wrapper finish method failed")
+ job_wrapper.fail("Unable to finish job", exception=True)
+
+ def put( self, job_wrapper ):
+ """Add a job to the queue (by job identifier)"""
+ # Change to queued state before handing to worker thread so the runner won't pick it up again
+ job_wrapper.change_state( model.Job.states.QUEUED )
+ self.queue.put( job_wrapper )
+
+ def shutdown( self ):
+ """Attempts to gracefully shut down the worker threads"""
+ log.info( "sending stop signal to worker threads" )
+ for i in range( len( self.threads ) ):
+ self.queue.put( self.STOP_SIGNAL )
+ log.info( "local job runner stopped" )
+
+ def check_pid( self, pid ):
+ # DBTODO Need to check all subtask pids and return some sort of cumulative result.
+ return True
+ try:
+ os.kill( pid, 0 )
+ return True
+ except OSError, e:
+ if e.errno == errno.ESRCH:
+ log.debug( "check_pid(): PID %d is dead" % pid )
+ else:
+ log.warning( "check_pid(): Got errno %s when attempting to check PID %d: %s" %( errno.errorcode[e.errno], pid, e.strerror ) )
+ return False
+
+ def stop_job( self, job ):
+ # DBTODO Call stop on all of the tasks.
+ #if our local job has JobExternalOutputMetadata associated, then our primary job has to have already finished
+ if job.external_output_metadata:
+ pid = job.external_output_metadata[0].job_runner_external_pid #every JobExternalOutputMetadata has a pid set, we just need to take from one of them
+ else:
+ pid = job.job_runner_external_id
+ if pid in [ None, '' ]:
+ log.warning( "stop_job(): %s: no PID in database for job, unable to stop" % job.id )
+ return
+ pid = int( pid )
+ if not self.check_pid( pid ):
+ log.warning( "stop_job(): %s: PID %d was already dead or can't be signaled" % ( job.id, pid ) )
+ return
+ for sig in [ 15, 9 ]:
+ try:
+ os.killpg( pid, sig )
+ except OSError, e:
+ log.warning( "stop_job(): %s: Got errno %s when attempting to signal %d to PID %d: %s" % ( job.id, errno.errorcode[e.errno], sig, pid, e.strerror ) )
+ return # give up
+ sleep( 2 )
+ if not self.check_pid( pid ):
+ log.debug( "stop_job(): %s: PID %d successfully killed with signal %d" %( job.id, pid, sig ) )
+ return
+ else:
+ log.warning( "stop_job(): %s: PID %d refuses to die after signaling TERM/KILL" %( job.id, pid ) )
+
+ def recover( self, job, job_wrapper ):
+ # DBTODO Task Recovery, this should be possible.
+ job_wrapper.change_state( model.Job.states.ERROR, info = "This job was killed when Galaxy was restarted. Please retry the job." )
+
--- a/universe_wsgi.ini.sample
+++ b/universe_wsgi.ini.sample
@@ -347,6 +347,11 @@ use_interactive = True
# Necessary if you're running the load balanced setup.
#track_jobs_in_database = False
+# This enables splitting of jobs into tasks, if specified by the particular tool config.
+# This is a new feature and not recommended for production servers yet.
+#use_tasked_jobs = True
+#local_task_queue_workers = 2
+
# Enable job recovery (if Galaxy is restarted while cluster jobs are running,
# it can "recover" them when it starts). This is not safe to use if you are
# running more than one Galaxy server using the same database.
--- a/lib/galaxy/model/mapping.py
+++ b/lib/galaxy/model/mapping.py
@@ -391,7 +391,24 @@ JobImportHistoryArchive.table = Table( "
Column( "history_id", Integer, ForeignKey( "history.id" ), index=True ),
Column( "archive_dir", TEXT )
)
-
+
+Task.table = Table( "task", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "execution_time", DateTime ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "state", String( 64 ), index=True ),
+ Column( "command_line", TEXT ),
+ Column( "param_filename", String( 1024 ) ),
+ Column( "runner_name", String( 255 ) ),
+ Column( "stdout", TEXT ),
+ Column( "stderr", TEXT ),
+ Column( "traceback", TEXT ),
+ Column( "job_id", Integer, ForeignKey( "job.id" ), index=True, nullable=False ),
+ Column( "part_file", String(1024)),
+ Column( "task_runner_name", String( 255 ) ),
+ Column( "task_runner_external_id", String( 255 ) ) )
+
PostJobAction.table = Table("post_job_action", metadata,
Column("id", Integer, primary_key=True),
Column("workflow_step_id", Integer, ForeignKey( "workflow_step.id" ), index=True, nullable=False),
@@ -1251,6 +1268,10 @@ assign_mapper( context, Job, Job.table,
output_library_datasets=relation( JobToOutputLibraryDatasetAssociation, lazy=False ),
external_output_metadata = relation( JobExternalOutputMetadata, lazy = False ) ) )
+assign_mapper( context, Task, Task.table,
+ properties=dict( job = relation( Job )))
+
+
assign_mapper( context, Event, Event.table,
properties=dict( history=relation( History ),
galaxy_session=relation( GalaxySession ),
--- a/lib/galaxy/config.py
+++ b/lib/galaxy/config.py
@@ -4,7 +4,6 @@ Universe configuration builder.
import sys, os
import logging, logging.config
-from optparse import OptionParser
import ConfigParser
from galaxy.util import string_as_bool
@@ -76,6 +75,9 @@ class Configuration( object ):
self.error_email_to = kwargs.get( 'error_email_to', None )
self.smtp_server = kwargs.get( 'smtp_server', None )
self.start_job_runners = kwargs.get( 'start_job_runners', None )
+ # Tasked job runner.
+ self.use_tasked_jobs = string_as_bool( kwargs.get( 'use_tasked_jobs', False ) )
+ self.local_task_queue_workers = int(kwargs.get("local_task_queue_workers", 2))
self.default_cluster_job_runner = kwargs.get( 'default_cluster_job_runner', 'local:///' )
self.pbs_application_server = kwargs.get('pbs_application_server', "" )
self.pbs_dataset_server = kwargs.get('pbs_dataset_server', "" )
--- /dev/null
+++ b/lib/galaxy/model/migrate/versions/0061_tasks.py
@@ -0,0 +1,49 @@
+"""
+Migration script to create tables task management.
+"""
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import datetime
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+now = datetime.datetime.utcnow
+
+Task_table = Table( "task", metadata,
+ Column( "id", Integer, primary_key=True ),
+ Column( "create_time", DateTime, default=now ),
+ Column( "execution_time", DateTime ),
+ Column( "update_time", DateTime, default=now, onupdate=now ),
+ Column( "state", String( 64 ), index=True ),
+ Column( "command_line", TEXT ),
+ Column( "param_filename", String( 1024 ) ),
+ Column( "runner_name", String( 255 ) ),
+ Column( "stdout", TEXT ),
+ Column( "stderr", TEXT ),
+ Column( "traceback", TEXT ),
+ Column( "job_id", Integer, ForeignKey( "job.id" ), index=True, nullable=False ),
+ Column( "part_file", String(1024)),
+ Column( "task_runner_name", String( 255 ) ),
+ Column( "task_runner_external_id", String( 255 ) ) )
+
+tables = [Task_table]
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+ for table in tables:
+ try:
+ table.create()
+ except:
+ log.warn( "Failed to create table '%s', ignoring (might result in wrong schema)" % table.name )
+
+def downgrade():
+ metadata.reflect()
+ for table in tables:
+ table.drop()
--- /dev/null
+++ b/lib/galaxy/jobs/splitters/basic.py
@@ -0,0 +1,85 @@
+import os, logging
+log = logging.getLogger( __name__ )
+
+def _file_len(fname):
+ i = 0
+ with open(fname) as f:
+ for i, l in enumerate(f):
+ pass
+ return i + 1
+
+def _fq_seq_count(fname):
+ count = 0
+ with open(fname) as f:
+ for i, l in enumerate(f):
+ if l.startswith('@'):
+ count += 1
+ return count
+
+def split_fq(input_file, working_directory, parts):
+ # Temporary, switch this to use the fq reader in lib/galaxy_utils/sequence.
+ outputs = []
+ length = _fq_seq_count(input_file)
+ if length < 1:
+ return outputs
+ if length < parts:
+ parts = length
+ len_each, remainder = divmod(length, parts)
+ with open(input_file, 'rt') as f:
+ for p in range(0, parts):
+ part_dir = os.path.join( os.path.abspath(working_directory), 'task_%s' % p)
+ if not os.path.exists( part_dir ):
+ os.mkdir( part_dir )
+ part_path = os.path.join(part_dir, os.path.basename(input_file))
+ with open(part_path, 'w') as part_file:
+ for l in range(0, len_each):
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ if remainder > 0:
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ part_file.write(f.readline())
+ remainder -= 1
+ outputs.append(part_path)
+ return outputs
+
+def split_txt(input_file, working_directory, parts):
+ outputs = []
+ length = _file_len(input_file)
+ if length < parts:
+ parts = length
+ len_each, remainder = divmod(length, parts)
+ with open(input_file, 'rt') as f:
+ for p in range(0, parts):
+ part_dir = os.path.join( os.path.abspath(working_directory), 'task_%s' % p)
+ if not os.path.exists( part_dir ):
+ os.mkdir( part_dir )
+ part_path = os.path.join(part_dir, os.path.basename(input_file))
+ with open(part_path, 'w') as part_file:
+ for l in range(0, len_each):
+ part_file.write(f.readline())
+ if remainder > 0:
+ part_file.write(f.readline())
+ remainder -= 1
+ outputs.append(part_path)
+ return outputs
+
+def split( input_file, working_directory, parts, file_type = None):
+ #Implement a better method for determining how to split.
+ if file_type.startswith('fastq'):
+ return split_fq(input_file, working_directory, parts)
+ else:
+ return split_txt(input_file, working_directory, parts)
+
+def merge( working_directory, output_file ):
+ output_file_name = os.path.basename(output_file)
+ task_dirs = [os.path.join(working_directory, x) for x in os.listdir(working_directory) if x.startswith('task_')]
+ task_dirs.sort(key = lambda x: int(x.split('task_')[-1]))
+ for task_dir in task_dirs:
+ try:
+ os.system( 'cat %s >> %s' % ( os.path.join(task_dir, output_file_name), output_file ) )
+ except Exception, e:
+ log.error(str(e))
1
0

galaxy-dist commit b1813ff5bb4e: Bug fixes and more UI streamlining for sample tracking.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1289426620 18000
# Node ID b1813ff5bb4ef20d0b5d5a1fdcfc16cf6ec3ba53
# Parent 0e5144e49c14eb2a77e1d3182a33b4f9c8de98fc
Bug fixes and more UI streamlining for sample tracking.
--- a/templates/requests/common/sample_datasets.mako
+++ /dev/null
@@ -1,5 +0,0 @@
-<%def name="render_sample_datasets( sample )">
- ${len( sample.datasets )} / ${len( sample.transferred_dataset_files )}
-</%def>
-
-${render_sample_datasets( sample )}
--- /dev/null
+++ b/templates/requests/common/view_sample_datasets.mako
@@ -0,0 +1,43 @@
+<%inherit file="/base.mako"/>
+<%namespace file="/message.mako" import="render_msg" />
+<%namespace file="/requests/common/common.mako" import="render_sample_datasets" />
+
+<%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
+ is_complete = sample.request.is_complete
+ is_submitted = sample.request.is_submitted
+ can_select_datasets = is_admin and ( is_complete or is_submitted )
+ can_transfer_datasets = is_admin and sample.untransferred_dataset_files
+%>
+
+<br/><br/>
+
+<ul class="manage-table-actions">
+ %if can_transfer_datasets:
+ <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Transfer datasets</a></li>
+ %endif
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=transfer_status )}">Refresh page</a></li>
+ <li><a class="action-button" id="sample-${sample.id}-popup" class="menubutton">Dataset Actions</a></li>
+ <div popupmenu="sample-${sample.id}-popup">
+ %if can_select_datasets:
+ <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( sample.request.id ), sample_id=trans.security.encode_id( sample.id ) )}">Select more datasets</a></li>
+ %endif
+ <li><a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( sample.library.id ) )}">View target Data Library</a></li>
+ <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
+ </div>
+</ul>
+
+%if message:
+ ${render_msg( message, status )}
+%endif
+
+%if sample and sample_datasets:
+ ## The list of sample_datasets may not be the same as sample.datasets because it may be
+ ## filtered by a transfer_status value. The value of title changes based on this filter.
+ ${render_sample_datasets( cntrller, sample, sample_datasets, title )}
+%else:
+ %if transfer_status:
+ No datasets with status ${transfer_status}" belong to this sample
+ %else:
+ No datasets have been selected for this sample.
+%endif
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -41,15 +41,15 @@
%if can_submit:
<li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
%endif
- <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li><div popupmenu="request-${request.id}-popup"><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
%if can_edit_request:
- <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
%endif
<a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
%if can_reject:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
</div></ul>
@@ -118,7 +118,7 @@
## Render the other grids
<% trans.sa_session.refresh( request.type.sample_form ) %>
%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), editing_samples=editing_samples )}
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), current_samples=current_samples, editing_samples=editing_samples )}
%endfor
%else:
<label>There are no samples.</label>
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -1831,12 +1831,12 @@ class Sample( object ):
return self.events[0]
return None
@property
- def untransferred_dataset_files( self ):
- untransferred_datasets = []
+ def adding_to_library_dataset_files( self ):
+ adding_to_library_datasets = []
for dataset in self.datasets:
- if dataset.status == SampleDataset.transfer_status.NOT_STARTED:
- untransferred_datasets.append( dataset )
- return untransferred_datasets
+ if dataset.status == SampleDataset.transfer_status.ADD_TO_LIBRARY:
+ adding_to_library_datasets.append( dataset )
+ return adding_to_library_datasets
@property
def inprogress_dataset_files( self ):
inprogress_datasets = []
@@ -1845,12 +1845,40 @@ class Sample( object ):
inprogress_datasets.append( dataset )
return inprogress_datasets
@property
+ def queued_dataset_files( self ):
+ queued_datasets = []
+ for dataset in self.datasets:
+ if dataset.status == SampleDataset.transfer_status.IN_QUEUE:
+ queued_datasets.append( dataset )
+ return queued_datasets
+ @property
+ def transfer_error_dataset_files( self ):
+ transfer_error_datasets = []
+ for dataset in self.datasets:
+ if dataset.status == SampleDataset.transfer_status.ERROR:
+ transfer_error_datasets.append( dataset )
+ return transfer_error_datasets
+ @property
def transferred_dataset_files( self ):
transferred_datasets = []
for dataset in self.datasets:
if dataset.status == SampleDataset.transfer_status.COMPLETE:
transferred_datasets.append( dataset )
return transferred_datasets
+ @property
+ def transferring_dataset_files( self ):
+ transferring_datasets = []
+ for dataset in self.datasets:
+ if dataset.status == SampleDataset.transfer_status.TRANSFERRING:
+ transferring_datasets.append( dataset )
+ return transferring_datasets
+ @property
+ def untransferred_dataset_files( self ):
+ untransferred_datasets = []
+ for dataset in self.datasets:
+ if dataset.status != SampleDataset.transfer_status.COMPLETE:
+ untransferred_datasets.append( dataset )
+ return untransferred_datasets
def get_untransferred_dataset_size( self, filepath ):
# TODO: RC: If rsh keys are not set, this method will return something like the following:
# greg(a)scofield.bx.psu.edu's password: 46M /afs/bx.psu.edu/home/greg/chr22/chr21.fa
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -109,10 +109,7 @@ class RequestsCommon( BaseController, Us
"datasets": len( sample.datasets ),
"html_state": unicode( trans.fill_template( "requests/common/sample_state.mako",
sample=sample),
- 'utf-8' ),
- "html_datasets": unicode( trans.fill_template( "requests/common/sample_datasets.mako",
- sample=sample ),
- 'utf-8' ) }
+ 'utf-8' ) }
return rval
@web.expose
@web.require_login( "create sequencing requests" )
@@ -455,7 +452,7 @@ class RequestsCommon( BaseController, Us
samples.append( sample )
else:
samples.append( None )
- # The __save_samples method requires samples widgets, not sample objects
+ # The __save_samples method requires sample_widgets, not sample objects
samples = self.__get_sample_widgets( trans, request, samples, **kwd )
else:
samples = current_samples
@@ -699,9 +696,9 @@ class RequestsCommon( BaseController, Us
# are in this state.
retval = request.send_email_notification( trans, common_state, final_state )
if retval:
- message = comments + retval
+ message = comment + retval
else:
- message = comments
+ message = comment
if cntrller == 'api':
return 200, message
return trans.response.send_redirect( web.url_for( controller='requests_common',
@@ -897,7 +894,7 @@ class RequestsCommon( BaseController, Us
message=message ) )
@web.expose
@web.require_login( "view data transfer page" )
- def view_selected_datasets( self, trans, cntrller, **kwd ):
+ def view_sample_datasets( self, trans, cntrller, **kwd ):
# The link on the number of selected datasets will only appear if there is at least 1 selected dataset.
# If there are 0 selected datasets, there is no link, so this method will only be reached from the requests
# controller if there are selected datasets.
@@ -930,13 +927,34 @@ class RequestsCommon( BaseController, Us
if folder_path and folder_path[-1] != os.sep:
folder_path += os.sep
if not sample.request.type.datatx_info['host'] \
- or not sample.request.type.datatx_info['username'] \
- or not sample.request.type.datatx_info['password']:
+ or not sample.request.type.datatx_info[ 'username' ] \
+ or not sample.request.type.datatx_info[ 'password' ]:
status = 'error'
message = 'The sequencer login information is incomplete. Click sequencer information to add login details.'
- return trans.fill_template( '/requests/common/view_selected_datasets.mako',
+ transfer_status = params.get( 'transfer_status', None )
+ if transfer_status in [ None, 'None' ]:
+ title = 'All selected datasets for "%s"' % sample.name
+ sample_datasets = sample.datasets
+ elif transfer_status == trans.model.SampleDataset.transfer_status.IN_QUEUE:
+ title = 'Datasets of "%s" that are in the transfer queue' % sample.name
+ sample_datasets = sample.queued_dataset_files
+ elif transfer_status == trans.model.SampleDataset.transfer_status.TRANSFERRING:
+ title = 'Datasets of "%s" that are being transferred' % sample.name
+ sample_datasets = sample.transferring_dataset_files
+ elif transfer_status == trans.model.SampleDataset.transfer_status.ADD_TO_LIBRARY:
+ title = 'Datasets of "%s" that are being added to the target data library' % sample.name
+ sample_datasets = sample.adding_to_library_dataset_files
+ elif transfer_status == trans.model.SampleDataset.transfer_status.COMPLETE:
+ title = 'Datasets of "%s" that are available in the target data library' % sample.name
+ sample_datasets = sample.transferred_dataset_files
+ elif transfer_status == trans.model.SampleDataset.transfer_status.ERROR:
+ title = 'Datasets of "%s" that resulted in a transfer error' % sample.name
+ sample_datasets = sample.transfer_error_dataset_files
+ return trans.fill_template( '/requests/common/view_sample_datasets.mako',
cntrller=cntrller,
sample=sample,
+ sample_datasets=sample_datasets,
+ transfer_status=transferr_status,
message=message,
status=status,
files=[],
@@ -1129,60 +1147,48 @@ class RequestsCommon( BaseController, Us
# on a set of samples.
library_id = params.get( 'sample_0_library_id', 'none' )
folder_id = params.get( 'sample_0_folder_id', 'none' )
- for index, obj in enumerate( sample_widgets ):
- if obj is not None:
- # obj will be None if the user checked sample check boxes and selected an action
+ for index, sample_widget in enumerate( sample_widgets ):
+ if sample_widget is not None:
+ # sample_widget will be None if the user checked sample check boxes and selected an action
# to perform on multiple samples, but did not select certain samples.
sample = request.samples[ index ]
- # See if any values in kwd are different from the values already associated with this sample.
- id_index = index + 1
- if sample_operation == 'none':
- # We are handling changes to a single sample.
- library_id = params.get( 'sample_%i_library_id' % id_index, 'none' )
- folder_id = params.get( 'sample_%i_folder_id' % id_index, 'none' )
- # Update the corresponding sample's values as well as the sample_widget.
- name = util.restore_text( params.get( 'sample_%i_name' % index, '' ) )
- # The bar_code field requires special handling because after a request is submitted, the
- # state of a sample cannot be changed without a bar_code associated with the sample. Bar
- # codes can only be added to a sample after the request is submitted. Also, a samples will
- # not have an associated SampleState until the request is submitted, at which time the sample
- # is automatically associated with the first SamplesState configured by the admin for the
- # request's RequestType.
- bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, '' ) )
- if bar_code:
- bc_message = self.__validate_barcode( trans, sample, bar_code )
- if bc_message:
- kwd[ 'message' ] = bc_message
- del kwd[ 'save_samples_button' ]
- handle_error( **kwd )
- if not sample.bar_code:
- # If the sample's associated SampleState is still the initial state
- # configured by the admin for the request's RequestType, this must be
- # the first time a bar code was added to the sample, so change it's state
- # to the next associated SampleState.
- if sample.state.id == request.type.states[0].id:
- event = trans.app.model.SampleEvent(sample,
- request.type.states[1],
- 'Bar code associated with the sample' )
- trans.sa_session.add( event )
- trans.sa_session.flush()
- library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
- field_values = []
- for field_index in range( len( request.type.sample_form.fields ) ):
- field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ # Get the sample's form values to see if they have changed.
form_values = trans.sa_session.query( trans.model.FormValues ).get( sample.values.id )
- form_values.content = field_values
- if sample.name != name or \
- sample.bar_code != bar_code or \
- sample.library != library or \
- sample.folder != folder or \
- form_values.content != field_values:
+ if sample.name != sample_widget[ 'name' ] or \
+ sample.bar_code != sample_widget[ 'barcode' ] or \
+ sample.library != sample_widget[ 'library' ] or \
+ sample.folder != sample_widget[ 'folder' ] or \
+ form_values.content != sample_widget[ 'field_values' ]:
# Information about this sample has been changed.
- sample.name = name
- sample.bar_code = bar_code
- sample.library = library
- sample.folder = folder
- form_values.content = field_values
+ sample.name = sample_widget[ 'name' ]
+ barcode = sample_widget[ 'barcode' ]
+ # The bar_code field requires special handling because after a request is submitted, the
+ # state of a sample cannot be changed without a bar_code associated with the sample. Bar
+ # codes can only be added to a sample after the request is submitted. Also, a samples will
+ # not have an associated SampleState until the request is submitted, at which time the sample
+ # is automatically associated with the first SamplesState configured by the admin for the
+ # request's RequestType.
+ if barcode:
+ bc_message = self.__validate_barcode( trans, sample, bar_code )
+ if bc_message:
+ kwd[ 'message' ] = bc_message
+ del kwd[ 'save_samples_button' ]
+ handle_error( **kwd )
+ if not sample.bar_code:
+ # If the sample's associated SampleState is still the initial state
+ # configured by the admin for the request's RequestType, this must be
+ # the first time a bar code was added to the sample, so change it's state
+ # to the next associated SampleState.
+ if sample.state.id == request.type.states[0].id:
+ event = trans.app.model.SampleEvent(sample,
+ request.type.states[1],
+ 'Bar code associated with the sample' )
+ trans.sa_session.add( event )
+ trans.sa_session.flush()
+ sample.bar_code = barcode
+ sample.library = sample_widget[ 'library' ]
+ sample.folder = sample_widget[ 'folder' ]
+ form_values.content = sample_widget[ 'field_values' ]
trans.sa_session.add_all( ( sample, form_values ) )
trans.sa_session.flush()
def __get_library_and_folder( self, trans, library_id, folder_id ):
@@ -1232,8 +1238,8 @@ class RequestsCommon( BaseController, Us
"""
Returns a list of dictionaries, each representing the widgets that define a sample on a form.
The widgets are populated from kwd based on the set of samples received. The set of samples
- corresponds to a reques.samples list, but if the user checked specific check boxes on the form,
- those samples that were not check will have None objects in the list of samples. In this case,
+ corresponds to a request.samples list, but if the user checked specific check boxes on the form,
+ those samples that were not checked will have None objects in the list of samples. In this case,
the corresponding sample_widget is populated from the db rather than kwd.
"""
params = util.Params( kwd )
@@ -1264,7 +1270,7 @@ class RequestsCommon( BaseController, Us
bar_code = sample.bar_code
library = sample.library
folder = sample.folder
- field_values = sample.values.content,
+ field_values = sample.values.content
else:
# Update the sample attributes from kwd
name = util.restore_text( params.get( 'sample_%i_name' % index, sample.name ) )
@@ -1278,7 +1284,8 @@ class RequestsCommon( BaseController, Us
library, folder = self.__get_library_and_folder( trans, library_id, folder_id )
field_values = []
for field_index in range( len( request.type.sample_form.fields ) ):
- field_values.append( util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), '' ) ) )
+ field_value = util.restore_text( params.get( 'sample_%i_field_%i' % ( index, field_index ), sample.values.content[ field_index ] ) )
+ field_values.append( field_value )
library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans=trans,
user=request.user,
sample_index=id_index,
--- a/templates/requests/common/find_samples.mako
+++ b/templates/requests/common/find_samples.mako
@@ -71,7 +71,7 @@
%else:
State: ${sample.state.name}<br/>
%endif
- Datasets: <a href="${h.url_for( controller='requests_common', action='view_selected_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}/${len( sample.datasets )}</a><br/>
+ Datasets: <a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a><br/>
%if is_admin:
<i>User: ${sample.request.user.email}</i>
%endif
--- a/templates/requests/common/view_selected_datasets.mako
+++ /dev/null
@@ -1,37 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-<%namespace file="/requests/common/common.mako" import="render_sample_datasets" />
-
-<%
- is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
- is_complete = sample.request.is_complete
- is_submitted = sample.request.is_submitted
- can_select_datasets = is_admin and ( is_complete or is_submitted )
- can_transfer_datasets = is_admin and sample.untransferred_dataset_files
-%>
-
-<br/><br/>
-
-<ul class="manage-table-actions">
- %if can_transfer_datasets:
- <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Transfer datasets</a></li>
- %endif
- <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_selected_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">Refresh page</a></li>
- <li><a class="action-button" id="sample-${sample.id}-popup" class="menubutton">Dataset Actions</a></li>
- <div popupmenu="sample-${sample.id}-popup">
- %if can_select_datasets:
- <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( sample.request.id ), sample_id=trans.security.encode_id( sample.id ) )}">Select more datasets</a></li>
- %endif
- <li><a class="action-button" href="${h.url_for( controller='library_common', action='browse_library', cntrller=cntrller, id=trans.security.encode_id( sample.library.id ) )}">View target Data Library</a></li>
- <li><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( sample.request.id ) )}">Browse this request</a></li>
- </div>
-</ul>
-
-%if message:
- ${render_msg( message, status )}
-%endif
-
-%if sample and sample.datasets:
- <% title = 'Datasets currently selected for "sample.name"' %>
- ${render_sample_datasets( cntrller, sample, sample.datasets, title )}
-%endif
--- a/templates/admin/requests/select_datasets_to_transfer.mako
+++ b/templates/admin/requests/select_datasets_to_transfer.mako
@@ -127,7 +127,7 @@
</div>
%if sample and sample.datasets:
- <% title = 'Datasets currently selected for "sample.name"' %>
+ <% title = 'Datasets currently selected for "%s"' % sample.name %><p/>
${render_sample_datasets( 'requests_admin', sample, sample.datasets, title )}
%endif
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -100,8 +100,6 @@
// Replace HTML
var cell1 = $("#sampleState-" + id);
cell1.html( val.html_state );
- var cell2 = $("#sampleDatasets-" + id);
- cell2.html( val.html_datasets );
sample_states[ parseInt( id ) ] = val.state;
});
updater( sample_states );
@@ -115,14 +113,16 @@
</script></%def>
-<%def name="render_editable_sample_row( is_admin, sample, current_sample_index, current_sample, encoded_selected_sample_ids )">
+<%def name="render_editable_sample_row( cntrller, sample, current_sample_index, current_sample, encoded_selected_sample_ids )"><%
+ is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
if sample:
trans.sa_session.refresh( sample.request )
is_complete = sample.request.is_complete
is_rejected = request.is_rejected
is_submitted = sample.request.is_submitted
is_unsubmitted = sample.request.is_unsubmitted
+ can_delete_samples = not is_complete
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
display_datasets = request.samples and ( is_complete or is_rejected or is_submitted )
@@ -130,6 +130,7 @@
is_complete = False
is_submitted = False
is_unsubmitted = False
+ can_delete_samples = False
display_checkboxes = False
display_bar_code = False
display_datasets = False
@@ -177,20 +178,36 @@
<a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%elif sample.datasets:
## Only display a link if there is at least 1 selected dataset for the sample
- <a href="${h.url_for( controller='requests_common', action='view_selected_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a></td>
+ <a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a></td>
%else:
${len( sample.datasets )}
%endif
</td><td valign="top">
- %if is_admin and sample.untransferred_dataset_files:
- <a href="${h.url_for( controller='requests_common', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %if is_admin:
+ %if sample.untransferred_dataset_files:
+ ## At least 1 selected dataset is not yet transferred, so this link
+ ## will direct the admin to a page allowing them to transfer datasets.
+ <a href="${h.url_for( controller='requests_common', action='manage_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %else:
+ ## All selected datasets have successfully transferred, so this link
+ ## will direct the admin to a page displaying all transferred datasets.
+ <a href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ), transfer_status=trans.model.SampleDataset.transfer_status.COMPLETE )}">${len( sample.transferred_dataset_files )}</a>
+ %endif
%else:
- ${len( sample.transferred_dataset_files )}
+ %if sample.transferred_dataset_files:
+ ## The cuurent user is not an admin, so this link will direct the
+ ## user to the target data library containing those datasets that
+ ## were successfully transferred.
+ <a href="${h.url_for( controller='library_common', action='browse_library', cntrller='library', id=trans.security.encode_id( sample.library.id ) )}">${len( sample.transferred_dataset_files )}</a>
+ %else:
+ ## Display a 0 with no link.
+ ${len( sample.transferred_dataset_files )}
+ %endif
%endif
</td>
%endif
- %if sample and ( is_admin or is_unsubmitted ) and not is_complete:
+ %if can_delete_samples:
## Delete button
<td valign="top"><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=current_sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
%endif
@@ -206,7 +223,7 @@
is_submitted = request.is_submitted
is_unsubmitted = request.is_unsubmitted
can_add_samples = request.is_unsubmitted
- can_delete_samples = request.samples and not is_complete
+ can_delete_samples = editing_samples and request.samples and not is_complete
can_edit_samples = request.samples and ( is_admin or not is_complete )
can_select_datasets = is_admin and current_samples and ( is_submitted or is_complete )
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
@@ -271,7 +288,7 @@
sample = None
%>
%if editing_samples:
- <tr>${render_editable_sample_row( is_admin, sample, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, sample, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
%elif sample:
<tr><td>${current_sample_name}</td>
@@ -302,11 +319,11 @@
<a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id= trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%else:
## If there are selected datasets, display them
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_selected_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
+ <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%endif
%elif sample.datasets:
## Only display a link if there is at least 1 selected dataset for the sample
- <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_selected_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
+ <a id="sampleDatasets-${sample.id}" href="${h.url_for( controller='requests_common', action='view_sample_datasets', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${len( sample.datasets )}</a>
%else:
${len( sample.datasets )}
%endif
@@ -322,7 +339,7 @@
</tr>
%else:
## The Add sample button was clicked for this sample_widget
- <tr>${render_editable_sample_row( is_admin, None, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, None, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
%endif
%endfor
</tbody>
@@ -390,7 +407,7 @@
</tr></%def>
-<%def name="render_request_type_sample_form_grids( grid_index, grid_name, fields_dict, editing_samples )">
+<%def name="render_request_type_sample_form_grids( grid_index, grid_name, fields_dict, current_samples, editing_samples )"><%
if not grid_name:
grid_name = "Sample form layout " + grid_index
@@ -432,6 +449,8 @@
</%def><%def name="render_sample_datasets( cntrller, sample, sample_datasets, title )">
+ ## The list of sample_datasets may not be the same as sample.datasets because it may be
+ ## filtered by a transfer_status value. The value of title changes based on this filter.
%if sample_datasets:
<%
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
--- a/templates/requests/common/events.mako
+++ b/templates/requests/common/events.mako
@@ -4,6 +4,7 @@
<%
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
can_edit_request = ( is_admin and not request.is_complete ) or request.is_unsubmitted
+ can_reject_request = is_admin and request.is_submitted
can_add_samples = request.is_unsubmitted
%>
@@ -13,14 +14,13 @@
<div popupmenu="request-${request.id}-popup"><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
%if can_edit_request:
- <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
%endif
%if can_add_samples:
- <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit</a>
+ <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit this request</a>
%endif
- %if is_admin and request.is_submitted:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
+ %if can_reject_request:
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
</div></ul>
--- a/templates/requests/common/edit_basic_request_info.mako
+++ b/templates/requests/common/edit_basic_request_info.mako
@@ -12,11 +12,11 @@
<div popupmenu="request-${request.id}-popup"><a class="action-button" href="${h.url_for( controller='requests_common', action='view_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Browse this request</a>
%if can_add_samples:
- <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit</a>
+ <a class="action-button" confirm="More samples cannot be added to this request once it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit this request</a>
%endif
<a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
%if is_admin and request.is_submitted:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ) )}">Select datasets to transfer</a>
%endif
</div>
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -27,6 +27,7 @@
can_edit_samples = request.samples and ( is_admin or not is_complete )
can_reject = is_admin and is_submitted
can_submit = request.samples and is_unsubmitted
+ can_undelete = request.deleted
%><br/><br/>
@@ -35,17 +36,17 @@
%if can_submit:
<li><a class="action-button" confirm="More samples cannot be added to this request after it is submitted. Click OK to submit." href="${h.url_for( controller='requests_common', action='submit_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Submit request</a></li>
%endif
- <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request actions</a></li>
+ <li><a class="action-button" id="request-${request.id}-popup" class="menubutton">Request Actions</a></li><div popupmenu="request-${request.id}-popup">
- %if request.deleted:
- <a class="action-button" href="${h.url_for( controller='requests_common', action='undelete_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Undelete</a>
+ %if can_undelete:
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='undelete_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Undelete this request</a>
%endif
%if can_edit_request:
- <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit</a>
+ <a class="action-button" href="${h.url_for( controller='requests_common', action='edit_basic_request_info', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Edit this request</a>
%endif
<a class="action-button" href="${h.url_for( controller='requests_common', action='request_events', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">View history</a>
%if can_reject:
- <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject</a>
+ <a class="action-button" href="${h.url_for( controller='requests_admin', action='reject_request', cntrller=cntrller, id=trans.security.encode_id( request.id ) )}">Reject this request</a>
%endif
</div></ul>
@@ -164,5 +165,5 @@
## Render the other grids
<% trans.sa_session.refresh( request.type.sample_form ) %>
%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), editing_samples=False )}
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), current_samples=current_samples, editing_samples=False )}
%endfor
1
0

galaxy-dist commit 865d7175847a: Corrected bug in reference to genome file in NGS simulation tool
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1289492971 18000
# Node ID 865d7175847ad322959f6b85532357d0f69afa46
# Parent 591c53b44ae4a6237a841adaa3abfe59829beebe
Corrected bug in reference to genome file in NGS simulation tool
--- a/tools/ngs_simulation/ngs_simulation.xml
+++ b/tools/ngs_simulation/ngs_simulation.xml
@@ -5,7 +5,7 @@
ngs_simulation.py
#if $in_type.input_type == "built-in"
--input="${ filter( lambda x: str( x[0] ) == str( $in_type.genome ), $__app__.tool_data_tables[ 'ngs_sim_fasta' ].get_fields() )[0][-1] }"
- --genome=$genome
+ --genome=$in_type.genome
#else
--input=$in_type.input1
#end if
1
0
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1289493322 18000
# Node ID ef3e52251722c1086160643a5f700c5db75a71d4
# Parent 865d7175847ad322959f6b85532357d0f69afa46
# Parent 7ea4c156ae32c4757378229bfc49584df91a024a
Merge
1
0

galaxy-dist commit 7ea4c156ae32: Add a pop-up menu for a sample if it is possible to either select datasets to transfer or transfer selected datasets for the sample. Also use better naming convention for a key variable name.
by commits-noreply@bitbucket.org 20 Nov '10
by commits-noreply@bitbucket.org 20 Nov '10
20 Nov '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1289492968 18000
# Node ID 7ea4c156ae32c4757378229bfc49584df91a024a
# Parent 591c53b44ae4a6237a841adaa3abfe59829beebe
Add a pop-up menu for a sample if it is possible to either select datasets to transfer or transfer selected datasets for the sample. Also use better naming convention for a key variable name.
--- a/lib/galaxy/web/controllers/requests_common.py
+++ b/lib/galaxy/web/controllers/requests_common.py
@@ -212,14 +212,14 @@ class RequestsCommon( BaseController, Us
except:
return invalid_id_redirect( trans, cntrller, request_id )
sample_state_id = params.get( 'sample_state_id', None )
- # Get the user entered sample information
- current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ # Build a list of sample widgets (based on the attributes of each sample) for display.
+ displayable_sample_widgets = self.__get_sample_widgets( trans, request, request.samples, **kwd )
request_widgets = self.__get_request_widgets( trans, request.id )
return trans.fill_template( '/requests/common/view_request.mako',
cntrller=cntrller,
request=request,
request_widgets=request_widgets,
- current_samples=current_samples,
+ displayable_sample_widgets=displayable_sample_widgets,
status=status,
message=message )
@web.expose
@@ -415,8 +415,8 @@ class RequestsCommon( BaseController, Us
editing_samples=editing_samples ) )
# Get all libraries for which the current user has permission to add items.
libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
- # Get the user entered sample information
- current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ # Build a list of sample widgets (based on the attributes of each sample) for display.
+ displayable_sample_widgets = self.__get_sample_widgets( trans, request, request.samples, **kwd )
encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd )
sample_operation = params.get( 'sample_operation', 'none' )
def handle_error( **kwd ):
@@ -433,14 +433,17 @@ class RequestsCommon( BaseController, Us
handle_error( **kwd )
if params.get( 'import_samples_button', False ):
# Import sample field values from a csv file
- return self.__import_samples( trans, cntrller, request, current_samples, libraries, **kwd )
+ return self.__import_samples( trans, cntrller, request, displayable_sample_widgets, libraries, **kwd )
elif params.get( 'add_sample_button', False ):
return self.add_sample( trans, cntrller, request_id, **kwd )
elif params.get( 'save_samples_button', False ):
if encoded_selected_sample_ids:
- # This gets tricky because we need the list of samples to include the same number
- # of objects that that current_samples ( i.e., request.samples ) has. We'll first
- # get the set of samples corresponding to the checked sample ids.
+ # We need the list of displayable_sample_widgets to include the same number
+ # of objects that that request.samples has so that we can enumerate over each
+ # list without problems. We have to be careful here since the user may have
+ # used the multi-select check boxes when editing sample widgets, but didn't
+ # select all of them. We'll first get the set of samples corresponding to the
+ # checked sample ids.
samples = []
selected_samples = []
for encoded_sample_id in encoded_selected_sample_ids:
@@ -453,12 +456,12 @@ class RequestsCommon( BaseController, Us
else:
samples.append( None )
# The __save_samples method requires sample_widgets, not sample objects
- samples = self.__get_sample_widgets( trans, request, samples, **kwd )
+ sample_widgets = self.__get_sample_widgets( trans, request, samples, **kwd )
else:
- samples = current_samples
- return self.__save_samples( trans, cntrller, request, samples, **kwd )
+ sample_widgets = displayable_sample_widgets
+ return self.__save_samples( trans, cntrller, request, sample_widgets, **kwd )
request_widgets = self.__get_request_widgets( trans, request.id )
- sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
+ sample_copy = self.__build_copy_sample_select_field( trans, displayable_sample_widgets )
libraries_select_field, folders_select_field = self.__build_library_and_folder_select_fields( trans,
request.user,
0,
@@ -473,7 +476,7 @@ class RequestsCommon( BaseController, Us
request=request,
encoded_selected_sample_ids=encoded_selected_sample_ids,
request_widgets=request_widgets,
- current_samples=current_samples,
+ displayable_sample_widgets=displayable_sample_widgets,
sample_copy=sample_copy,
libraries=libraries,
sample_operation_select_field=sample_operation_select_field,
@@ -805,12 +808,12 @@ class RequestsCommon( BaseController, Us
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
# Get the widgets for rendering the request form
request_widgets = self.__get_request_widgets( trans, request.id )
- current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
- if not current_samples:
+ displayable_sample_widgets = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ if not displayable_sample_widgets:
# Form field names are zero-based.
sample_index = 0
else:
- sample_index = len( current_samples )
+ sample_index = len( displayable_sample_widgets )
if params.get( 'add_sample_button', False ):
# Get all libraries for which the current user has permission to add items
libraries = request.user.accessible_libraries( trans, [ trans.app.security_agent.permitted_actions.LIBRARY_ADD ] )
@@ -818,18 +821,18 @@ class RequestsCommon( BaseController, Us
# See if the user has selected a sample to copy.
copy_sample_index = int( params.get( 'copy_sample_index', -1 ) )
for index in range( num_samples_to_add ):
- id_index = len( current_samples ) + 1
+ id_index = len( displayable_sample_widgets ) + 1
if copy_sample_index != -1:
# The user has selected a sample to copy.
- library_id = current_samples[ copy_sample_index][ 'library_select_field' ].get_selected( return_value=True )
- folder_id = current_samples[ copy_sample_index ][ 'folder_select_field' ].get_selected( return_value=True )
- name = current_samples[ copy_sample_index ][ 'name' ] + '_%i' % ( len( current_samples ) + 1 )
- field_values = [ val for val in current_samples[ copy_sample_index ][ 'field_values' ] ]
+ library_id = displayable_sample_widgets[ copy_sample_index][ 'library_select_field' ].get_selected( return_value=True )
+ folder_id = displayable_sample_widgets[ copy_sample_index ][ 'folder_select_field' ].get_selected( return_value=True )
+ name = displayable_sample_widgets[ copy_sample_index ][ 'name' ] + '_%i' % ( len( displayable_sample_widgets ) + 1 )
+ field_values = [ val for val in displayable_sample_widgets[ copy_sample_index ][ 'field_values' ] ]
else:
# The user has not selected a sample to copy, just adding a new generic sample.
library_id = None
folder_id = None
- name = 'Sample_%i' % ( len( current_samples ) + 1 )
+ name = 'Sample_%i' % ( len( displayable_sample_widgets ) + 1 )
field_values = [ '' for field in request.type.sample_form.fields ]
# Build the library_select_field and folder_select_field for the new sample being added.
library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans,
@@ -841,25 +844,26 @@ class RequestsCommon( BaseController, Us
folder_id=folder_id,
**kwd )
# Append the new sample to the current list of samples for the request
- current_samples.append( dict( name=name,
- barcode='',
- library=None,
- library_id=library_id,
- folder=None,
- folder_id=folder_id,
- field_values=field_values,
- library_select_field=library_select_field,
- folder_select_field=folder_select_field ) )
+ displayable_sample_widgets.append( dict( id=None,
+ name=name,
+ barcode='',
+ library=None,
+ library_id=library_id,
+ folder=None,
+ folder_id=folder_id,
+ field_values=field_values,
+ library_select_field=library_select_field,
+ folder_select_field=folder_select_field ) )
encoded_selected_sample_ids = self.__get_encoded_selected_sample_ids( trans, request, **kwd )
sample_operation = params.get( 'sample_operation', 'none' )
sample_operation_select_field = self.__build_sample_operation_select_field( trans, is_admin, request, sample_operation )
- sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
+ sample_copy = self.__build_copy_sample_select_field( trans, displayable_sample_widgets )
return trans.fill_template( '/requests/common/edit_samples.mako',
cntrller=cntrller,
request=request,
encoded_selected_sample_ids=encoded_selected_sample_ids,
request_widgets=request_widgets,
- current_samples=current_samples,
+ displayable_sample_widgets=displayable_sample_widgets,
sample_operation_select_field=sample_operation_select_field,
sample_copy=sample_copy,
editing_samples=False,
@@ -876,9 +880,9 @@ class RequestsCommon( BaseController, Us
request = trans.sa_session.query( trans.model.Request ).get( trans.security.decode_id( request_id ) )
except:
return invalid_id_redirect( trans, cntrller, request_id )
- current_samples = self.__get_sample_widgets( trans, request, request.samples, **kwd )
+ displayable_sample_widgets = self.__get_sample_widgets( trans, request, request.samples, **kwd )
sample_index = int( params.get( 'sample_id', 0 ) )
- sample_name = current_samples[sample_index]['name']
+ sample_name = displayable_sample_widgets[sample_index]['name']
sample = request.has_sample( sample_name )
if sample:
trans.sa_session.delete( sample.values )
@@ -960,7 +964,7 @@ class RequestsCommon( BaseController, Us
status=status,
files=[],
folder_path=folder_path )
- def __import_samples( self, trans, cntrller, request, current_samples, libraries, **kwd ):
+ def __import_samples( self, trans, cntrller, request, displayable_sample_widgets, libraries, **kwd ):
"""
Reads the samples csv file and imports all the samples. The format of the csv file is:
SampleName,DataLibrary,DataLibraryFolder,Field1,Field2....
@@ -987,19 +991,20 @@ class RequestsCommon( BaseController, Us
folder_id = folder.id
library_select_field, folder_select_field = self.__build_library_and_folder_select_fields( trans,
request.user,
- len( current_samples ),
+ len( displayable_sample_widgets ),
libraries,
None,
library_id,
folder_id,
**kwd )
- current_samples.append( dict( name=row[0],
- barcode='',
- library=None,
- folder=None,
- library_select_field=library_select_field,
- folder_select_field=folder_select_field,
- field_values=row[3:] ) )
+ displayable_sample_widgets.append( dict( id=None,
+ name=row[0],
+ barcode='',
+ library=None,
+ folder=None,
+ library_select_field=library_select_field,
+ folder_select_field=folder_select_field,
+ field_values=row[3:] ) )
except Exception, e:
if str( e ) == "'unicode' object has no attribute 'file'":
message = "Select a file"
@@ -1014,12 +1019,12 @@ class RequestsCommon( BaseController, Us
status='error',
message=message ) )
request_widgets = self.__get_request_widgets( trans, request.id )
- sample_copy = self.__build_copy_sample_select_field( trans, current_samples )
+ sample_copy = self.__build_copy_sample_select_field( trans, displayable_sample_widgets )
return trans.fill_template( '/requests/common/edit_samples.mako',
cntrller=cntrller,
request=request,
request_widgets=request_widgets,
- current_samples=current_samples,
+ displayable_sample_widgets=displayable_sample_widgets,
sample_copy=sample_copy,
editing_samples=False )
def __save_samples( self, trans, cntrller, request, samples, **kwd ):
@@ -1110,17 +1115,17 @@ class RequestsCommon( BaseController, Us
# by the admin ( i.e., the sample's SampleState would be set to request.type.states[0] ).
for index in range( len( samples ) - len( request.samples ) ):
sample_index = len( request.samples )
- current_sample = samples[ sample_index ]
- form_values = trans.model.FormValues( request.type.sample_form, current_sample[ 'field_values' ] )
+ sample_widget = samples[ sample_index ]
+ form_values = trans.model.FormValues( request.type.sample_form, sample_widget[ 'field_values' ] )
trans.sa_session.add( form_values )
trans.sa_session.flush()
- s = trans.model.Sample( name=current_sample[ 'name' ],
+ s = trans.model.Sample( name=sample_widget[ 'name' ],
desc='',
request=request,
form_values=form_values,
bar_code='',
- library=current_sample[ 'library' ],
- folder=current_sample[ 'folder' ] )
+ library=sample_widget[ 'library' ],
+ folder=sample_widget[ 'folder' ] )
trans.sa_session.add( s )
trans.sa_session.flush()
return trans.response.send_redirect( web.url_for( controller='requests_common',
@@ -1264,9 +1269,9 @@ class RequestsCommon( BaseController, Us
for index, sample in enumerate( samples ):
id_index = index + 1
if sample is None:
- # Id sample is None, then we'll use the sample from the request object since it will
- # not have updated =values from kwd.
+ # Use the sample from the request object since it will not have updated values from kwd.
sample = request.samples[ index ]
+ sample_id = sample.id
name = sample.name
bar_code = sample.bar_code
library = sample.library
@@ -1274,6 +1279,7 @@ class RequestsCommon( BaseController, Us
field_values = sample.values.content
else:
# Update the sample attributes from kwd
+ sample_id = None
name = util.restore_text( params.get( 'sample_%i_name' % index, sample.name ) )
bar_code = util.restore_text( params.get( 'sample_%i_barcode' % index, sample.bar_code ) )
library_id = util.restore_text( params.get( 'sample_%i_library_id' % id_index, '' ) )
@@ -1295,7 +1301,8 @@ class RequestsCommon( BaseController, Us
library_id=library_id,
folder_id=folder_id,
**kwd )
- sample_widgets.append( dict( name=name,
+ sample_widgets.append( dict( id=sample_id,
+ name=name,
barcode=bar_code,
library=library,
folder=folder,
@@ -1325,7 +1332,8 @@ class RequestsCommon( BaseController, Us
library_id=library_id,
folder_id=folder_id,
**kwd )
- sample_widgets.append( dict( name=name,
+ sample_widgets.append( dict( id=None,
+ name=name,
barcode=bar_code,
library=library,
folder=folder,
@@ -1335,10 +1343,10 @@ class RequestsCommon( BaseController, Us
index += 1
return sample_widgets
# ===== Methods for building SelectFields used on various request forms =====
- def __build_copy_sample_select_field( self, trans, current_samples ):
+ def __build_copy_sample_select_field( self, trans, displayable_sample_widgets ):
copy_sample_index_select_field = SelectField( 'copy_sample_index' )
copy_sample_index_select_field.add_option( 'None', -1, selected=True )
- for index, sample_dict in enumerate( current_samples ):
+ for index, sample_dict in enumerate( displayable_sample_widgets ):
copy_sample_index_select_field.add_option( sample_dict[ 'name' ], index )
return copy_sample_index_select_field
def __build_request_type_id_select_field( self, trans, selected_value='none' ):
@@ -1458,20 +1466,20 @@ class RequestsCommon( BaseController, Us
message += '<b>' + ef + '</b> '
return message
return None
- def __validate_sample_names( self, trans, cntrller, request, current_samples, **kwd ):
+ def __validate_sample_names( self, trans, cntrller, request, displayable_sample_widgets, **kwd ):
# Check for duplicate sample names for all samples of the request.
editing_samples = util.string_as_bool( kwd.get( 'editing_samples', False ) )
message = ''
- for index in range( len( current_samples ) - len( request.samples ) ):
+ for index in range( len( displayable_sample_widgets ) - len( request.samples ) ):
sample_index = index + len( request.samples )
- current_sample = current_samples[ sample_index ]
- sample_name = current_sample[ 'name' ]
+ sample_widget = displayable_sample_widgets[ sample_index ]
+ sample_name = sample_widget[ 'name' ]
if not sample_name.strip():
message = 'Enter the name of sample number %i' % sample_index
break
count = 0
- for i in range( len( current_samples ) ):
- if sample_name == current_samples[ i ][ 'name' ]:
+ for i in range( len( displayable_sample_widgets ) ):
+ if sample_name == displayable_sample_widgets[ i ][ 'name' ]:
count += 1
if count > 1:
message = "You tried to add %i samples with the name (%s). Samples belonging to a request must have unique names." % ( count, sample_name )
--- a/templates/requests/common/common.mako
+++ b/templates/requests/common/common.mako
@@ -113,7 +113,7 @@
</script></%def>
-<%def name="render_editable_sample_row( cntrller, sample, current_sample_index, current_sample, encoded_selected_sample_ids )">
+<%def name="render_editable_sample_row( cntrller, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )"><%
is_admin = cntrller == 'requests_admin' and trans.user_is_admin()
if sample:
@@ -145,7 +145,7 @@
<td><input type="checkbox" name=select_sample_${sample.id} id="sample_checkbox" value="true" ${checked_str}/><input type="hidden" name=select_sample_${sample.id} id="sample_checkbox" value="true"/></td>
%endif
<td valign="top">
- <input type="text" name="sample_${current_sample_index}_name" value="${current_sample['name']}" size="10"/>
+ <input type="text" name="sample_${sample_widget_index}_name" value="${sample_widget['name']}" size="10"/><div class="toolParamHelp" style="clear: both;"><i>${' (required)' }</i></div>
@@ -153,10 +153,10 @@
%if display_bar_code:
<td valign="top">
%if is_admin:
- <input type="text" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}" size="10"/>
+ <input type="text" name="sample_${sample_widget_index}_barcode" value="${sample_widget['barcode']}" size="10"/>
%else:
- ${current_sample['barcode']}
- <input type="hidden" name="sample_${current_sample_index}_barcode" value="${current_sample['barcode']}"/>
+ ${sample_widget['barcode']}
+ <input type="hidden" name="sample_${sample_widget_index}_barcode" value="${sample_widget['barcode']}"/>
%endif
</td>
%endif
@@ -169,8 +169,8 @@
%else:
<td></td>
%endif
- <td valign="top">${current_sample['library_select_field'].get_html()}</td>
- <td valign="top">${current_sample['folder_select_field'].get_html()}</td>
+ <td valign="top">${sample_widget['library_select_field'].get_html()}</td>
+ <td valign="top">${sample_widget['folder_select_field'].get_html()}</td>
%if display_datasets:
<td valign="top">
## An admin can select the datasets to transfer, while a non-admin can only view what has been selected
@@ -220,11 +220,11 @@
%endif
%if can_delete_samples:
## Delete button
- <td valign="top"><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=current_sample_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
+ <td valign="top"><a class="action-button" href="${h.url_for( controller='requests_common', action='delete_sample', cntrller=cntrller, request_id=trans.security.encode_id( request.id ), sample_id=sample_widget_index )}"><img src="${h.url_for('/static/images/delete_icon.png')}" style="cursor:pointer;"/></a></td>
%endif
</%def>
-<%def name="render_samples_grid( cntrller, request, current_samples, action, editing_samples=False, encoded_selected_sample_ids=[], render_buttons=False, grid_header='<h3>Samples</h3>' )">
+<%def name="render_samples_grid( cntrller, request, displayable_sample_widgets, action, editing_samples=False, encoded_selected_sample_ids=[], render_buttons=False, grid_header='<h3>Samples</h3>' )">
## Displays the "Samples" grid
<%
trans.sa_session.refresh( request )
@@ -236,7 +236,8 @@
can_add_samples = request.is_unsubmitted
can_delete_samples = editing_samples and request.samples and not is_complete
can_edit_samples = request.samples and ( is_admin or not is_complete )
- can_select_datasets = is_admin and current_samples and ( is_submitted or is_complete )
+ can_select_datasets = is_admin and displayable_sample_widgets and ( is_submitted or is_complete )
+ can_transfer_datasets = is_admin and request.samples and not request.is_rejected
display_checkboxes = editing_samples and ( is_complete or is_rejected or is_submitted )
display_bar_code = request.samples and ( is_complete or is_rejected or is_submitted )
display_datasets = request.samples and ( is_complete or is_submitted )
@@ -278,46 +279,67 @@
<thead><tbody><% trans.sa_session.refresh( request ) %>
- ## current_samples is a dictionary whose keys are:
- ## name, barcode, library, folder, field_values, library_select_field, folder_select_field
- %for current_sample_index, current_sample in enumerate( current_samples ):
+ ## displayable_sample_widgets is a dictionary whose keys are:
+ ## id, name, barcode, library, folder, field_values, library_select_field, folder_select_field
+ ## A displayable_sample_widget will have an id == None if the widget's associated sample has not
+ ## yet been saved (i.e., the use clicked the "Add sample" button but has not yet clicked the
+ ## "Save" button.
+ %for sample_widget_index, sample_widget in enumerate( displayable_sample_widgets ):
<%
- current_sample_name = current_sample[ 'name' ]
- current_sample_barcode = current_sample[ 'barcode' ]
- current_sample_library = current_sample[ 'library' ]
- if current_sample_library:
+ sample_widget_name = sample_widget[ 'name' ]
+ sample_widget_barcode = sample_widget[ 'barcode' ]
+ sample_widget_library = sample_widget[ 'library' ]
+ if sample_widget_library:
if cntrller == 'requests':
library_cntrller = 'library'
elif is_admin:
library_cntrller = 'library_admin'
else:
library_cntrller = None
- current_sample_folder = current_sample[ 'folder' ]
+ sample_widget_folder = sample_widget[ 'folder' ]
try:
- sample = request.samples[ current_sample_index ]
+ sample = request.samples[ sample_widget_index ]
except:
sample = None
%>
%if editing_samples:
- <tr>${render_editable_sample_row( cntrller, sample, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, sample, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
%elif sample:
<tr>
- <td>${current_sample_name}</td>
+ <td>
+ %if sample.state and ( can_select_datasets or can_transfer_datasets ):
+ ## A sample will have a state only after the request has been submitted.
+ <% encoded_id = trans.security.encode_id( sample.id ) %>
+ <div style="float: left; margin-left: 2px;" class="menubutton split popup" id="sample-${sample.id}-popup">
+ ${sample.name}
+ </div>
+ <div popupmenu="sample-${sample.id}-popup">
+ %if can_select_datasets:
+ <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='select_datasets_to_transfer', request_id=trans.security.encode_id( request.id ), sample_id=trans.security.encode_id( sample.id ) )}">Select datasets to transfer</a></li>
+ %endif
+ %if sample.untransferred_dataset_files:
+ <li><a class="action-button" href="${h.url_for( controller='requests_admin', action='manage_datasets', sample_id=trans.security.encode_id( sample.id ) )}">Transfer datasets</a></li>
+ %endif
+ </div>
+ %else:
+ ${sample_widget_name}
+ %endif
+ </td>
%if display_bar_code:
- <td>${current_sample_barcode}</td>
+ <td>${sample_widget_barcode}</td>
%endif
%if is_unsubmitted:
<td>Unsubmitted</td>
%else:
<td><a id="sampleState-${sample.id}" href="${h.url_for( controller='requests_common', action='sample_events', cntrller=cntrller, sample_id=trans.security.encode_id( sample.id ) )}">${render_sample_state( sample )}</a></td>
%endif
- %if current_sample_library and library_cntrller is not None:
- <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller=library_cntrller, id=trans.security.encode_id( current_sample_library.id ) )}">${current_sample_library.name}</a></td>
+ %if sample_widget_library and library_cntrller is not None:
+ <td><a href="${h.url_for( controller='library_common', action='browse_library', cntrller=library_cntrller, id=trans.security.encode_id( sample_widget_library.id ) )}">${sample_widget_library.name}</a></td>
%else:
<td></td>
%endif
- %if current_sample_folder:
- <td>${current_sample_folder.name}</td>
+ %if sample_widget_folder:
+ <td>${sample_widget_folder.name}</td>
%else:
<td></td>
%endif
@@ -371,7 +393,7 @@
</tr>
%else:
## The Add sample button was clicked for this sample_widget
- <tr>${render_editable_sample_row( cntrller, None, current_sample_index, current_sample, encoded_selected_sample_ids )}</tr>
+ <tr>${render_editable_sample_row( cntrller, None, sample_widget_index, sample_widget, encoded_selected_sample_ids )}</tr>
%endif
%endfor
</tbody>
@@ -439,7 +461,7 @@
</tr></%def>
-<%def name="render_request_type_sample_form_grids( grid_index, grid_name, fields_dict, current_samples, editing_samples )">
+<%def name="render_request_type_sample_form_grids( grid_index, grid_name, fields_dict, displayable_sample_widgets, editing_samples )"><%
if not grid_name:
grid_name = "Sample form layout " + grid_index
@@ -466,7 +488,7 @@
<thead><tbody><% trans.sa_session.refresh( request ) %>
- %for sample_index, sample in enumerate( current_samples ):
+ %for sample_index, sample in enumerate( displayable_sample_widgets ):
<%
if editing_samples or sample_index >= len( request.samples ):
display_only = False
@@ -505,7 +527,7 @@
<tr><td>
%if is_admin:
- <% encoded_id = trans.security.encode_id(dataset.id) %>
+ <% encoded_id = trans.security.encode_id( dataset.id ) %><span class="expandLink dataset-${dataset}-click"><span class="rowIcon"></span><div style="float: left; margin-left: 2px;" class="menubutton split popup" id="dataset-${dataset.id}-popup"><a class="dataset-${encoded_id}-click" href="${h.url_for( controller='requests_admin', action='manage_datasets', operation='view', id=trans.security.encode_id( dataset.id ) )}">${dataset.name}</a>
--- a/templates/requests/common/edit_samples.mako
+++ b/templates/requests/common/edit_samples.mako
@@ -72,14 +72,14 @@
<div class="toolFormBody"><form id="edit_samples" name="edit_samples" action="${h.url_for( controller='requests_common', action='edit_samples', cntrller=cntrller, id=trans.security.encode_id( request.id ), editing_samples=editing_samples )}" method="post">
- %if current_samples:
+ %if displayable_sample_widgets:
<%
if editing_samples:
grid_header = '<h3>Edit Current Samples of Request "%s"</h3>' % request.name
else:
grid_header = '<h3>Add Samples to Request "%s"</h3>' % request.name
%>
- ${render_samples_grid( cntrller, request, current_samples, action='edit_samples', editing_samples=editing_samples, encoded_selected_sample_ids=encoded_selected_sample_ids, render_buttons=False, grid_header=grid_header )}
+ ${render_samples_grid( cntrller, request, displayable_sample_widgets, action='edit_samples', editing_samples=editing_samples, encoded_selected_sample_ids=encoded_selected_sample_ids, render_buttons=False, grid_header=grid_header )}
%if editing_samples and len( sample_operation_select_field.options ) > 1 and not is_unsubmitted:
<div class="form-row" style="background-color:#FAFAFA;">
For selected samples:
@@ -118,14 +118,14 @@
## Render the other grids
<% trans.sa_session.refresh( request.type.sample_form ) %>
%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), current_samples=current_samples, editing_samples=editing_samples )}
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), displayable_sample_widgets=displayable_sample_widgets, editing_samples=editing_samples )}
%endfor
%else:
<label>There are no samples.</label>
%endif
%if not editing_samples and is_unsubmitted:
## The user is adding a new sample
- %if current_samples:
+ %if displayable_sample_widgets:
<p/><div class="form-row"><label> Copy <input type="text" name="num_sample_to_copy" value="1" size="3"/> samples from sample ${sample_copy.get_html()}</label>
@@ -138,7 +138,7 @@
<div class="form-row">
## hidden element to make twill work.
<input type="hidden" name="hidden_input" value=""/>
- %if ( request.samples or current_samples ) and ( editing_samples or len( current_samples ) > len( request.samples ) ):
+ %if ( request.samples or displayable_sample_widgets ) and ( editing_samples or len( displayable_sample_widgets ) > len( request.samples ) ):
<input type="submit" name="add_sample_button" value="Add sample" /><input type="submit" name="save_samples_button" value="Save"/><input type="submit" name="cancel_changes_button" value="Cancel"/>
--- a/templates/requests/common/view_request.mako
+++ b/templates/requests/common/view_request.mako
@@ -148,12 +148,12 @@
</div></div><p/>
-%if current_samples:
+%if displayable_sample_widgets:
<%
grid_header = '<h3>Samples</h3>'
render_buttons = can_edit_samples
%>
- ${render_samples_grid( cntrller, request, current_samples=current_samples, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=render_buttons, grid_header=grid_header )}
+ ${render_samples_grid( cntrller, request, displayable_sample_widgets=displayable_sample_widgets, action='view_request', editing_samples=False, encoded_selected_sample_ids=[], render_buttons=render_buttons, grid_header=grid_header )}
%else:
There are no samples.
%if can_add_samples:
@@ -165,5 +165,5 @@
## Render the other grids
<% trans.sa_session.refresh( request.type.sample_form ) %>
%for grid_index, grid_name in enumerate( request.type.sample_form.layout ):
- ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), current_samples=current_samples, editing_samples=False )}
+ ${render_request_type_sample_form_grids( grid_index, grid_name, request.type.sample_form.grid_fields( grid_index ), displayable_sample_widgets=displayable_sample_widgets, editing_samples=False )}
%endfor
1
0