# gem 'capistrano'
# To use debugger
-# gem 'debugger'
+#gem 'byebug'
gem 'rvm-capistrano', :group => :test
gem 'piwik_analytics'
gem 'httpclient'
gem 'themes_for_rails'
+gem "deep_merge", :require => 'deep_merge/rails_compat'
\ No newline at end of file
coffee-script-source (1.6.3)
commonjs (0.2.7)
daemon_controller (1.1.7)
+ deep_merge (1.0.1)
erubis (2.7.0)
execjs (2.0.2)
highline (1.6.20)
bootstrap-sass (~> 3.1.0)
bootstrap-x-editable-rails
coffee-rails (~> 3.2.0)
+ deep_merge
httpclient
jquery-rails
less
}
targets.fadeToggle(200);
});
+
$(document).
on('ajax:send', function(e, xhr) {
$('.loading').fadeTo('fast', 1);
fixer.duplicateTheadTr();
fixer.fixThead();
});
-})(jQuery);
+});
$.fn.editable.defaults.ajaxOptions = {type: 'put', dataType: 'json'};
$.fn.editable.defaults.send = 'always';
+//$.fn.editable.defaults.mode = 'inline';
$.fn.editable.defaults.params = function (params) {
var a = {};
var key = params.pk.key;
a[key] = {};
a[key][params.name] = params.value;
return a;
-};
\ No newline at end of file
+};
--- /dev/null
+
+(function() {
+ var run_pipeline_button_state = function() {
+ var a = $('a.editable.required.editable-empty');
+ if (a.length > 0) {
+ $("#run-pipeline-button").addClass("disabled");
+ }
+ else {
+ $("#run-pipeline-button").removeClass("disabled");
+ }
+ }
+
+ $.fn.editable.defaults.success = function (response, newValue) {
+ var tag = $(this);
+ if (tag.hasClass("required")) {
+ if (newValue && newValue.trim() != "") {
+ tag.removeClass("editable-empty");
+ tag.parent().css("background-color", "");
+ tag.parent().prev().css("background-color", "");
+ }
+ else {
+ tag.addClass("editable-empty");
+ tag.parent().css("background-color", "#ffdddd");
+ tag.parent().prev().css("background-color", "#ffdddd");
+ }
+ }
+ run_pipeline_button_state();
+ }
+
+ $(window).on('load', function() {
+ var a = $('a.editable.required');
+ for (var i = 0; i < a.length; i++) {
+ var tag = $(a[i]);
+ if (tag.hasClass("editable-empty")) {
+ tag.parent().css("background-color", "#ffdddd");
+ tag.parent().prev().css("background-color", "#ffdddd");
+ }
+ else {
+ tag.parent().css("background-color", "");
+ tag.parent().prev().css("background-color", "");
+ }
+ }
+ run_pipeline_button_state();
+ } );
+
+})();
+++ /dev/null
-# Place all the behaviors and hooks related to the matching controller here.
-# All this logic will automatically be available in application.js.
-# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
--- /dev/null
+//= require jquery
+//= require jquery_ujs
+
+/** Javascript for local persistent selection. */
+
+get_selection_list = null;
+form_selection_sources = {};
+
+jQuery(function($){
+ var storage = localStorage; // sessionStorage
+
+ get_selection_list = function() {
+ if (!storage.persistentSelection) {
+ storage.persistentSelection = JSON.stringify([]);
+ }
+ return JSON.parse(storage.persistentSelection);
+ }
+
+ var put_storage = function(lst) {
+ storage.persistentSelection = JSON.stringify(lst);
+ }
+
+ var add_selection = function(uuid, name, href, type) {
+ var lst = get_selection_list();
+ lst.push({"uuid": uuid, "name": name, "href": href, "type": type});
+ put_storage(lst);
+ update_count();
+ };
+
+ var remove_selection = function(uuid) {
+ var lst = get_selection_list();
+ for (var i = 0; i < lst.length; i++) {
+ if (lst[i].uuid == uuid) {
+ lst.splice(i, 1);
+ i--;
+ }
+ }
+ put_storage(lst);
+ update_count();
+ };
+
+ var remove_selection_click = function(e) {
+ //remove_selection($(this).attr('name'));
+ remove_selection($(this).val());
+ };
+
+ var clear_selections = function() {
+ put_storage([]);
+ update_count();
+ }
+
+ var update_count = function(e) {
+ var lst = get_selection_list();
+ $("#persistent-selection-count").text(lst.length);
+
+ if (lst.length > 0) {
+ $('#persistent-selection-list').html('<li><a href="#" class="btn pull-right" id="clear_selections_button">Clear selections</a></li>'
+ +'<li class="notification"><table style="width: 100%"></table></li>');
+ for (var i = 0; i < lst.length; i++) {
+ $('#persistent-selection-list > li > table').append("<tr>"
+ + "<td>"
+ + "<form>"
+ + "<input class='remove-selection' type='checkbox' value='" + lst[i].uuid + "' checked='true'></input>"
+ + "</form>"
+ + "</td>"
+
+ + "<td>"
+ + "<span style='padding-left: 1em'><a href=\"" + lst[i].href + "\">" + lst[i].name + "</a></span>"
+ + "</td>"
+
+ + "<td style=\"vertical-align: top\">"
+ + "<span style=\"padding-right: 1em\">" + lst[i].type + "</span>"
+ + "</td>"
+
+ + "</tr>");
+ }
+ } else {
+ $('#persistent-selection-list').html("<li class='notification empty'>No selections.</li>");
+ }
+
+ var checkboxes = $('.persistent-selection:checkbox');
+ for (i = 0; i < checkboxes.length; i++) {
+ for (var j = 0; j < lst.length; j++) {
+ if (lst[j].uuid == $(checkboxes[i]).val()) {
+ checkboxes[i].checked = true;
+ break;
+ }
+ }
+ if (j == lst.length) {
+ checkboxes[i].checked = false;
+ }
+ }
+
+ $('.remove-selection').on('click', remove_selection_click);
+ $('#clear_selections_button').on('click', clear_selections);
+ };
+
+ $(document).
+ on('change', '.persistent-selection:checkbox', function(e) {
+ //console.log($(this));
+ //console.log($(this).val());
+
+ var inc = 0;
+ if ($(this).is(":checked")) {
+ add_selection($(this).val(), $(this).attr('friendly_name'), $(this).attr('href'), $(this).attr('friendly_type'));
+ }
+ else {
+ remove_selection($(this).val());
+ }
+ });
+
+
+ $(window).on('load storage', update_count);
+});
+
+add_form_selection_sources = null;
+select_form_sources = null;
+
+(function() {
+ var form_selection_sources = {};
+ add_form_selection_sources = function (src) {
+ for (var i = 0; i < src.length; i++) {
+ var t = form_selection_sources[src[i].type];
+ if (!t) {
+ t = form_selection_sources[src[i].type] = {};
+ }
+ if (!t[src[i].uuid]) {
+ t[src[i].uuid] = src[i];
+ }
+ }
+ };
+
+ select_form_sources = function(type) {
+ var ret = [];
+
+ if (get_selection_list) {
+ var lst = get_selection_list();
+ if (lst.length > 0) {
+ ret.push({text: "--- Selections ---", value: ""});
+
+ for (var i = 0; i < lst.length; i++) {
+ if (lst[i].type == type) {
+ ret.push({text: lst[i].name, value: lst[i].uuid})
+ }
+ }
+ }
+ }
+ ret.push({text: "--- Recent ---", value: ""});
+
+ var t = form_selection_sources[type];
+ for (var key in t) {
+ if (t.hasOwnProperty(key)) {
+ var obj = t[key];
+ ret.push({text: obj.name, value: obj.uuid})
+ }
+ }
+ return ret;
+ };
+})();
+
}
function smart_scroll_fixup(s) {
- console.log(s);
+ //console.log(s);
if (s != null && s.type == 'shown.bs.tab') {
s = [s.target];
}
else {
s = $(".smart-scroll");
}
- console.log(s);
+ //console.log(s);
for (var i = 0; i < s.length; i++) {
a = s[i];
var h = window.innerHeight - a.getBoundingClientRect().top - 20;
position:relative;
top:1.5em;
}
+
+/* Setting the height needs to be fixed with javascript. */
+.dropdown-menu {
+ padding-right: 20px;
+ max-height: 440px;
+ width: 400px;
+ overflow-y: auto;
+}
+
+#persistent-selection-list {
+ width: 500px;
+}
+
+#persistent-selection-list li table tr {
+ border-top: 1px solid rgb(221, 221, 221);
+}
def unprocessable(message=nil)
@errors ||= []
+
@errors << message if message
render_error status: 422
end
def create
@object ||= model_class.new params[model_class.to_s.underscore.singularize]
@object.save!
+
respond_to do |f|
f.json { render json: @object }
f.html {
end
def show
+ if @object.components.empty? and @object.pipeline_template_uuid
+ template = PipelineTemplate.find(@object.pipeline_template_uuid)
+ pipeline = {}
+ template.components.each do |component_name, component_props|
+ pipeline[component_name] = {}
+ component_props.each do |k, v|
+ if k == :script_parameters
+ pipeline[component_name][:script_parameters] = {}
+ v.each do |param_name, param_value|
+ if param_value.is_a? Hash
+ if param_value[:value]
+ pipeline[component_name][:script_parameters][param_name] = param_value[:value]
+ elsif param_value[:default]
+ pipeline[component_name][:script_parameters][param_name] = param_value[:default]
+ elsif param_value[:optional] != nil or param_value[:required] != nil
+ pipeline[component_name][:script_parameters][param_name] = ""
+ else
+ pipeline[component_name][:script_parameters][param_name] = param_value
+ end
+ else
+ pipeline[component_name][:script_parameters][param_name] = param_value
+ end
+ end
+ else
+ pipeline[component_name][k] = v
+ end
+ end
+ end
+ @object.components= pipeline
+ @object.save
+ end
+
@pipelines = [@object]
if params[:compare]
%w(Compare Graph)
end
+ def update
+ updates = params[@object.class.to_s.underscore.singularize.to_sym]
+ if updates["components"]
+ require 'deep_merge/rails_compat'
+ updates["components"] = updates["components"].deeper_merge(@object.components)
+ end
+ super
+ end
+
protected
def for_comparison v
if v.is_a? Hash or v.is_a? Array
controller.current_user
end
+ def self.match_uuid(uuid)
+ /^([0-9a-z]{5})-([0-9a-z]{5})-([0-9a-z]{15})$/.match(uuid.to_s)
+ end
+
def current_api_host
Rails.configuration.arvados_v1_base.gsub /https?:\/\/|\/arvados\/v1/,''
end
end
end
style_opts[:class] = (style_opts[:class] || '') + ' nowrap'
- link_to link_name, { controller: resource_class.to_s.underscore.pluralize, action: 'show', id: link_uuid }, style_opts
+ link_to link_name, { controller: resource_class.to_s.tableize, action: 'show', id: link_uuid }, style_opts
else
attrvalue
end
:class => "editable"
}.merge(htmloptions)
end
+
+ def render_editable_subattribute(object, attr, subattr, template, htmloptions={})
+ attrvalue = object.send(attr)
+ subattr.each do |k|
+ if attrvalue and attrvalue.is_a? Hash
+ attrvalue = attrvalue[k]
+ else
+ break
+ end
+ end
+
+ datatype = nil
+ required = true
+ if template
+ #puts "Template is #{template.class} #{template.is_a? Hash} #{template}"
+ if template.is_a? Hash
+ if template[:output_of]
+ return raw("<span class='label label-default'>#{template[:output_of]}</span>")
+ end
+ if template[:dataclass]
+ dataclass = template[:dataclass]
+ end
+ if template[:optional] != nil
+ required = (template[:optional] != "true")
+ end
+ if template[:required] != nil
+ required = template[:required]
+ end
+ end
+ end
+
+ return attrvalue if !object.attribute_editable? attr
+
+ if not dataclass
+ rsc = template
+ if template.is_a? Hash
+ if template[:value]
+ rsc = template[:value]
+ elsif template[:default]
+ rsc = template[:default]
+ end
+ end
+
+ dataclass = ArvadosBase.resource_class_for_uuid(rsc)
+ end
+
+ if dataclass && dataclass.is_a?(Class)
+ datatype = 'select'
+ elsif dataclass == 'number'
+ datatype = 'number'
+ else
+ if template.is_a? Array
+ # ?!?
+ elsif template.is_a? String
+ if /^\d+$/.match(template)
+ datatype = 'number'
+ else
+ datatype = 'text'
+ end
+ end
+ end
+
+ id = "#{object.uuid}-#{subattr.join('-')}"
+ dn = "[#{attr}]"
+ subattr.each do |a|
+ dn += "[#{a}]"
+ end
+
+ if attrvalue.is_a? String
+ attrvalue = attrvalue.strip
+ end
+
+ if dataclass and dataclass.is_a? Class
+ items = []
+ items.append({name: attrvalue, uuid: attrvalue, type: dataclass.to_s})
+ #dataclass.where(uuid: attrvalue).each do |item|
+ # items.append({name: item.uuid, uuid: item.uuid, type: dataclass.to_s})
+ #end
+ dataclass.limit(10).each do |item|
+ items.append({name: item.uuid, uuid: item.uuid, type: dataclass.to_s})
+ end
+ end
+
+ lt = link_to attrvalue, '#', {
+ "data-emptytext" => "none",
+ "data-placement" => "bottom",
+ "data-type" => datatype,
+ "data-url" => url_for(action: "update", id: object.uuid, controller: object.class.to_s.pluralize.underscore),
+ "data-title" => "Update #{subattr[-1].to_s.titleize}",
+ "data-name" => dn,
+ "data-pk" => "{id: \"#{object.uuid}\", key: \"#{object.class.to_s.underscore}\"}",
+ "data-showbuttons" => "false",
+ "data-value" => attrvalue,
+ :class => "editable #{'required' if required}",
+ :id => id
+ }.merge(htmloptions)
+
+ lt += raw('<script>')
+
+ if items and items.length > 0
+ lt += raw("add_form_selection_sources(#{items.to_json});\n")
+ end
+
+ lt += raw("$('##{id}').editable({source: function() { return select_form_sources('#{dataclass}'); } });\n")
+
+ lt += raw("</script>")
+
+ lt
+ end
end
{source: x.tail_uuid, target: x.head_uuid, type: x.name}
end
end
+
+ def self.match(uuid)
+ /^([a-f0-9]{32}(\+[0-9]+)?)(\+.*)?$/.match(uuid.to_s)
+ end
end
def render_pipeline_job pj
if pj[:percent_done]
- pj[:progress_bar] = raw("<div class=\"progress\" style=\"width:100px\"><span class=\"progress-bar progress-bar-success\" style=\"width:#{pj[:percent_done]}%\"></span><span class=\"progress-bar\" style=\"width:#{pj[:percent_running]}%\"></span></div>")
+ pj[:progress_bar] = raw <<EOF
+<div class="progress" style="width:100px">
+ <span class="progress-bar progress-bar-success" style="width:#{pj[:percent_done]}%"></span>
+ <span class="progress-bar" style="width:#{pj[:percent_running]}%"></span>
+</div>
+EOF
elsif pj[:progress]
- raw("<div class=\"progress\" style=\"width:100px\"><span class=\"progress-bar\" style=\"width:#{pj[:progress]*100}%\"></span></div>")
+ raw <<EOF
+<div class="progress" style="width:100px">
+<span class="progress-bar" style="width:#{pj[:progress]*100}%">
+</span>
+</div>
+EOF
end
pj[:output_link] = link_to_if_arvados_object pj[:output]
pj[:job_link] = link_to_if_arvados_object pj[:job][:uuid]
end
def self.collection_uuid(uuid)
- m = /^([a-f0-9]{32}(\+[0-9]+)?)(\+.*)?$/.match(uuid.to_s)
+ m = CollectionsHelper.match(uuid)
if m
#if m[2]
return m[1]
attr_reader :kind
@columns
end
+
def self.column(name, sql_type = nil, default = nil, null = true)
ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
end
+
def self.attribute_info
self.columns
@attribute_info
end
+
def self.find(uuid, opts={})
if uuid.class != String or uuid.length < 27 then
raise 'argument to find() must be a uuid string. Acceptable formats: warehouse locator or string with format xxxxx-xxxxx-xxxxxxxxxxxxxxx'
end
new.private_reload(hash)
end
+
def self.order(*args)
ArvadosResourceList.new(self).order(*args)
end
+
def self.where(*args)
ArvadosResourceList.new(self).where(*args)
end
+
def self.limit(*args)
ArvadosResourceList.new(self).limit(*args)
end
+
def self.eager(*args)
ArvadosResourceList.new(self).eager(*args)
end
+
def self.all(*args)
ArvadosResourceList.new(self).all(*args)
end
+
def save
obdata = {}
self.class.columns.each do |col|
end
end
+ @new_record = false
+
self
end
+
def save!
self.save or raise Exception.new("Save failed")
end
@links = $arvados_api_client.api Link, '', { _method: 'GET', where: o, eager: true }
@links = $arvados_api_client.unpack_api_response(@links)
end
+
def all_links
return @all_links if @all_links
res = $arvados_api_client.api Link, '', {
}
@all_links = $arvados_api_client.unpack_api_response(res)
end
+
def reload
private_reload(self.uuid)
end
+
def private_reload(uuid_or_hash)
raise "No such object" if !uuid_or_hash
if uuid_or_hash.is_a? Hash
end
end
@all_links = nil
+ @new_record = false
self
end
+
+ def to_param
+ uuid
+ end
+
def dup
super.forget_uuid!
end
(name if self.respond_to? :name) || uuid
end
+ def selection_label
+ friendly_link_name
+ end
+
protected
def forget_uuid!
def used_by
$arvados_api_client.api "collections/#{self.uuid}/", "used_by"
end
+
+ # def selection_label
+ # name = ''
+ # i = 0
+ # if self.files.length > 3
+ # m = 3
+ # else
+ # m = self.files.length
+ # end
+ # while i < m
+ # name += "#{self.files[i][1]}"
+ # i += 1
+ # name += ", " if i < m
+ # end
+ # if i < self.files.length
+ # name += "&ellip;"
+ # end
+ # name
+ # end
end
end
end
end
-
+
def attribute_editable?(attr)
- attr == 'name'
+ attr.to_sym == :name || (attr.to_sym == :components and self.active == nil)
end
def attributes_for_display
--- /dev/null
+<%if object %>
+<%= check_box_tag 'uuids[]', object.uuid, false, {
+ :class => 'persistent-selection',
+ :friendly_type => object.class.name,
+ :friendly_name => object.selection_label,
+ :href => "#{url_for controller: object.class.name.tableize, action: 'show', id: object.uuid }"
+} %>
+<% end %>
<% attr_blacklist = ' created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at' %>
+<%= form_tag do |f| %>
+
<table class="table table-condensed arv-index">
<thead>
<tr>
+ <th></th>
<% @objects.first.attributes_for_display.each do |attr, attrvalue| %>
<% next if attr_blacklist.index(" "+attr) %>
<th class="arv-attr-<%= attr %>">
<tbody>
<% @objects.each do |object| %>
<tr data-object-uuid="<%= object.uuid %>">
+ <td>
+ <%= render :partial => "selection_checkbox", :locals => {:object => object} %>
+ </td>
+
<% object.attributes_for_display.each do |attr, attrvalue| %>
<% next if attr_blacklist.index(" "+attr) %>
<td class="arv-object-<%= object.class.to_s %> arv-attr-<%= attr %>">
</table>
<% end %>
+
+<% end %>
<% @collections.each do |c| %>
<tr class="collection" data-object-uuid="<%= c.uuid %>">
+ <td>
+ <%= render :partial => "selection_checkbox", :locals => {:object => c} %>
+ </td>
<td>
<%= link_to_if_arvados_object c.uuid %>
</td>
+<% content_for :css do %>
+.file-list-inline-image {
+ width: 50%;
+ height: auto;
+}
+<% end %>
+
<table class="table table-condensed table-fixedlayout">
<colgroup>
+ <col width="4%" />
<col width="35%" />
<col width="40%" />
<col width="15%" />
</colgroup>
<thead>
<tr>
+ <th></th>
<th>path</th>
<th>file</th>
<th style="text-align:right">size</th>
<% if @object then @object.files.sort_by{|f|[f[0],f[1]]}.each do |file| %>
<% file_path = "#{file[0]}/#{file[1]}" %>
<tr>
+ <td>
+ <% fp2 = file_path[2..-1] if file_path[0..1] == './' %>
+ <% fp2 ||= file_path %>
+<%= check_box_tag 'uuids[]', @object.uuid+file_path, false, {
+ :class => 'persistent-selection',
+ :friendly_type => "File",
+ :friendly_name => "#{@object.uuid}/#{fp2}",
+ :href => "#{url_for controller: 'collections', action: 'show', id: @object.uuid }/#{file_path}"
+ } %>
+ </td>
<td>
<%= file[0] %>
</td>
<td>
- <%= link_to file[1], {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'inline'}, {title: 'View in browser'} %>
+ <%= link_to((if /\.(jpg|jpeg|gif|png|svg)$/i.match(file[1]) then
+ image_tag "#{url_for @object}/#{file_path}", class: "file-list-inline-image"
+ else
+ file[1]
+ end),
+ {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'inline'},
+ {title: file_path}) %>
</td>
<td style="text-align:right">
<div style="padding-right: 1em">
+<%= form_tag do |f| %>
+
<table id="collections-index" class="topalign table table-condensed table-fixedlayout table-fixed-header-row">
<colgroup>
+ <col width="4%" />
<col width="10%" />
<col width="36%" />
<col width="15%" />
</colgroup>
<thead>
<tr class="contain-align-left">
+ <th></th>
<th>uuid</th>
<th>contents</th>
<th>owner</th>
<%= render partial: 'index_tbody' %>
</tbody>
</table>
+
+<% end %>
+
</div>
<% content_for :footer_js do %>
padding-top: 1.25em;
}
- /* Setting the height needs to be fixed with javascript. */
- .dropdown-menu {
- padding-right: 20px;
- max-height: 440px;
- width: 400px;
- overflow-y: auto;
- }
-
@media (min-width: 768px) {
.left-nav {
position: fixed;
<span class="glyphicon glyphicon-arrow-right"></span>
</li>
<li>
-<%= link_to controller.breadcrumb_page_name, request.fullpath %>
+ <%= link_to controller.breadcrumb_page_name, request.fullpath %>
+ </li>
+ <li style="padding: 14px 0 14px">
+ <%= form_tag do |f| %>
+ <%= render :partial => "selection_checkbox", :locals => {:object => @object} %>
+ <% end %>
</li>
<% end %>
<% end %>
</li>
-->
- <!-- XXX placeholder for this when persistent selection is implemented
- <li class="dropdown">
+ <li class="dropdown notification-menu">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
<span class="glyphicon glyphicon-paperclip"></span>
- <span class="badge badge-alert"><%= @selection_count %></span>
+ <span class="badge" id="persistent-selection-count"></span>
<span class="caret"></span>
</a>
- <ul class="dropdown-menu" role="menu">
- <li style="padding: 10px">No selections.</li>
+ <ul class="dropdown-menu" role="menu" id="persistent-selection-list">
</ul>
</li>
- -->
<% if current_user.is_active %>
<li class="dropdown notification-menu">
padding-left: 1em;
padding-right: 1em;
}
+table.pipeline-components-table {
+ width: 100%;
+ table-layout: fixed;
+ overflow: hidden;
+}
+
table.pipeline-components-table thead th {
text-align: bottom;
}
table.pipeline-components-table div.progress {
margin-bottom: 0;
}
+
+table.pipeline-components-table td {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+td.required {
+ background: #ffdddd;
+}
+
<% end %>
-<br />
+<% template = PipelineTemplate.find(@object.pipeline_template_uuid) %>
+<% if template %>
+ <h2><%= template.name %></h2>
+<% end %>
+
+<% if @object.active != nil %>
<table class="table pipeline-components-table">
<colgroup>
- <col width="15%" />
- <col width="15%" />
- <col width="35%" />
- <col width="35%" />
+ <col style="width: 15%" />
+ <col style="width: 20%" />
+ <col style="width: 12%" />
+ <col style="width: 8%" />
+ <col style="width: 45%" />
</colgroup>
<thead>
<tr>
<th>
component
+ </th><th>
+ script, version
</th><th>
progress
<%= link_to '(refresh)', request.fullpath, class: 'refresh', remote: true, method: 'get' %>
</th><th>
- script, version
</th><th>
output
</th>
<% render_pipeline_jobs.each do |pj| %>
<tr>
<td>
+ <% label = if pj[:job].andand[:uuid]
+ if pj[:job][:success] == true
+ 'label-success'
+ elsif pj[:job][:success] == false
+ 'label-danger'
+ elsif pj[:job][:running] == true
+ 'label-info'
+ else
+ 'label-default'
+ end
+ else
+ 'label-default'
+ end %>
<% if pj[:job].andand[:uuid] %>
- <%= link_to pj[:name], job_url(id: pj[:job][:uuid]) %>
+ <%= link_to pj[:name], job_url(id: pj[:job][:uuid]), class: "label #{label}" %>
<% else %>
- <%= pj[:name] %>
+ <span class="label <%= label %>"><%= pj[:name] %></span>
<% end %>
+
+ </td><td>
+ <%= pj[:script] %>
+ <br /><span class="deemphasize"><%= pj[:script_version] %></span>
</td><td>
<%= pj[:progress_bar] %>
+ </td><td>
<% if pj[:job].andand[:cancelled_at] %>
- <span class="pull-right label label-warning">cancelled</span>
+ <span class="label label-warning">cancelled</span>
<% elsif pj[:failed] %>
- <span class="pull-right label label-warning">failed</span>
+ <span class="label label-danger">failed</span>
<% elsif pj[:result] == 'queued' %>
- <span class="pull-right label">queued</span>
+ <span class="label">queued</span>
<% end %>
- </td><td>
- <%= pj[:script] %>
- <br /><span class="deemphasize"><%= pj[:script_version] %></span>
</td><td>
<%= link_to_if_arvados_object pj[:output] %>
</td>
<% if @object.active %>
<% content_for :js do %>
-setInterval(function(){$('a.refresh').click()}, 30000);
+setInterval(function(){$('a.refresh').click()}, 15000);
<% end %>
<% end %>
-<pre><%= JSON.pretty_generate @object.attributes %></pre>
+<% else %>
+
+ <%= form_tag @object, :method => :put do |f| %>
+
+ <%= hidden_field @object.class.to_s.underscore.singularize.to_sym, :active, :value => true %>
+ <%= button_tag "Run pipeline", {class: 'btn btn-primary pull-right', id: "run-pipeline-button"} %>
+ <% end %>
+
+<table class="table pipeline-components-table" style="margin-top: -.1em">
+ <colgroup>
+ <col style="width: 15%" />
+ <col style="width: 20%" />
+ <col style="width: 20%" />
+ <col style="width: 45%" />
+ </colgroup>
+
+ <thead>
+ <tr>
+ <th>
+ component
+ </th><th>
+ script
+ </th><th>
+ parameter
+ </th><th>
+ value
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <% template.components.each do |k, template_value| %>
+
+ <tr>
+ <td><span class="label label-default"><%= k %></span></td>
+
+ <td><%= render_editable_subattribute @object, :components, [k, :script], template_value[:script] %></td>
+
+ <td>script version</td>
+
+ <td>
+ <%= render_editable_subattribute @object, :components, [k, :script_version], template_value[:script_version] %>
+ </td>
+ </tr>
+
+ <% if template_value[:script_parameters].length > 0 %>
+ <% template_value[:script_parameters].each do |p, tv| %>
+ <tr>
+ <td style="border-top: none"></td>
+ <td style="border-top: none"></td>
+
+ <td class="property-edit-row"><%= p %></td>
+ <td class="property-edit-row"><%= render_editable_subattribute @object, :components, [k, :script_parameters, p.to_sym], tv %></td>
+ <% end %>
+ </tr>
+ <% end %>
+ <% end %>
+ </tbody>
+ </table>
+
+<% end %>
<tr data-object-uuid="<%= ob.uuid %>">
<td>
- <%= check_box_tag 'uuids[]', ob.uuid, false %>
+ <%= check_box_tag 'uuids[]', ob.uuid, false, :class => 'persistent-selection' %>
</td><td>
<% if ob.success %>
<span class="label label-success">success</span>
</td>
</tr>
<tr>
- <td style="border-top: 0;" colspan="3">
+ <td style="border-top: 0;" colspan="2">
</td>
- <td style="border-top: 0; opacity: 0.5;" colspan="4">
+ <td style="border-top: 0; opacity: 0.5;" colspan="5">
<% ob.components.each do |cname, c| %>
<% status = if !(c.is_a?(Hash) && c[:job].is_a?(Hash))
nil
- elsif c[:job][:success]
+ elsif c[:job][:success] == true
'success'
- elsif c[:job][:running]
+ elsif c[:job][:success] == false
+ 'danger'
+ elsif c[:job][:running] == true
'info'
else
'warning'
+<% content_for :css do %>
+ .playbutton {
+ color: white;
+ background: gray;
+ border: 0px;
+ border-radius: 3px;
+ padding: 0px 3px;
+ }
+ .playbutton:hover {
+ color: white;
+ background: blackh;
+ }
+<% end %>
+
<table class="table table-hover">
<thead>
<tr class="contain-align-left">
<th>
+ </th><th>
id
</th><th>
name
<% @objects.sort_by { |ob| ob[:created_at] }.reverse.each do |ob| %>
<tr>
+ <td>
+ <%= form_tag '/pipeline_instances' do |f| %>
+ <%= hidden_field :pipeline_instance, :pipeline_template_uuid, :value => ob.uuid %>
+ <%= button_tag nil, {class: 'playbutton'} do %>
+ <span class="glyphicon glyphicon-play"></span>
+ <% end %>
+ <% end %>
+ </td>
<td>
<%= link_to_if_arvados_object ob %>
</td><td>