[ARVADOS] created: eaa436ddd4aadf4fad387ea6115e35c885828ce0

git at public.curoverse.com git at public.curoverse.com
Tue Jan 28 21:16:22 EST 2014


        at  eaa436ddd4aadf4fad387ea6115e35c885828ce0 (commit)


commit eaa436ddd4aadf4fad387ea6115e35c885828ce0
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Jan 28 18:15:43 2014 -0800

    Show condensed data about pipeline instances side by side on "compare"
    page.
    
    refs #1978

diff --git a/apps/workbench/app/assets/stylesheets/application.css b/apps/workbench/app/assets/stylesheets/application.css
index 9c67653..d2993be 100644
--- a/apps/workbench/app/assets/stylesheets/application.css
+++ b/apps/workbench/app/assets/stylesheets/application.css
@@ -75,3 +75,6 @@ form input.search-mini {
 form.small-form-margin {
     margin-bottom: 2px;
 }
+.nowrap {
+    white-space: nowrap;
+}
diff --git a/apps/workbench/app/controllers/pipeline_instances_controller.rb b/apps/workbench/app/controllers/pipeline_instances_controller.rb
index f3932bf..99a4ddd 100644
--- a/apps/workbench/app/controllers/pipeline_instances_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_instances_controller.rb
@@ -1,12 +1,75 @@
 class PipelineInstancesController < ApplicationController
   skip_before_filter :find_object_by_uuid, only: :compare
   before_filter :find_objects_by_uuid, only: :compare
+  include PipelineInstancesHelper
 
   def compare
+    @rows = []          # each is {name: S, components: [...]}
+
+    # Build a table: x=pipeline y=component
+    @objects.each_with_index do |pi, pi_index|
+      pipeline_jobs(pi).each do |component|
+        # Find a cell with the same name as this component but no
+        # entry for this pipeline
+        target_row = nil
+        @rows.each_with_index do |row, row_index|
+          if row[:name] == component[:name] and !row[:components][pi_index]
+            target_row = row
+          end
+        end
+        if !target_row
+          target_row = {name: component[:name], components: []}
+          @rows << target_row
+        end
+        target_row[:components][pi_index] = component
+      end
+    end
+
+    @rows.each do |row|
+      # Build a "normal" pseudo-component for this row by picking the
+      # most common value for each attribute. If all values are
+      # equally common, there is no "normal".
+      normal = {}              # attr => most common value
+      highscore = {}           # attr => how common "normal" is
+      score = {}               # attr => { value => how common }
+      row[:components].each do |pj|
+        pj.each do |k,v|
+          vstr = for_comparison v
+          score[k] ||= {}
+          score[k][vstr] = (score[k][vstr.to_s] || 0) + 1
+          highscore[k] ||= 0
+          if score[k][vstr] == highscore[k]
+            # tie for first place = no "normal"
+            normal.delete k
+          elsif score[k][vstr] == highscore[k] + 1
+            # more pipelines have v than anything else
+            highscore[k] = score[k][vstr]
+            normal[k] = vstr
+          end
+        end
+      end
+
+      # Add a hash in component[:is_normal]: { attr => is_the_value_normal? }
+      row[:components].each do |pj|
+        pj[:is_normal] = {}
+        pj.each do |k,v|
+          pj[:is_normal][k] = (normal.has_key?(k) && normal[k] == for_comparison(v))
+        end
+      end
+    end
   end
 
   protected
+  def for_comparison v
+    if v.is_a? Hash or v.is_a? Array
+      v.to_json
+    else
+      v.to_s
+    end
+  end
+
   def find_objects_by_uuid
-    @objects = model_class.where(uuid: params[:uuid])
+    @objects = model_class.where(uuid: params[:uuid].split('/'))
   end
+
 end
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index 5500938..fe7012a 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -69,6 +69,7 @@ module ApplicationHelper
           link_name = "#{resource_class.to_s}: #{link_name}"
         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
     else
       attrvalue
diff --git a/apps/workbench/app/helpers/pipeline_instances_helper.rb b/apps/workbench/app/helpers/pipeline_instances_helper.rb
index c792db8..f314c65 100644
--- a/apps/workbench/app/helpers/pipeline_instances_helper.rb
+++ b/apps/workbench/app/helpers/pipeline_instances_helper.rb
@@ -1,18 +1,36 @@
 module PipelineInstancesHelper
-  def pipeline_jobs
-    if @object.components[:steps].is_a? Array
-      pipeline_jobs_oldschool
-    elsif @object.components.is_a? Hash
-      pipeline_jobs_newschool
+  def pipeline_jobs object=nil
+    object ||= @object
+    if object.components[:steps].is_a? Array
+      pipeline_jobs_oldschool object
+    elsif object.components.is_a? Hash
+      pipeline_jobs_newschool object
     end
   end
 
+  def render_pipeline_jobs
+    pipeline_jobs.collect do |pj|
+      render_pipeline_job pj
+    end
+  end
+
+  def render_pipeline_job pj
+    if pj[:percent_done]
+      pj[:progress_bar] = raw("<div class=\"progress\" style=\"width:100px\"><div class=\"bar bar-success\" style=\"width:#{pj[:percent_done]}%\"></div><div class=\"bar\" style=\"width:#{pj[:percent_running]}%\"></div></div>")
+    elsif pj[:progress]
+      raw("<div class=\"progress\" style=\"width:100px\"><div class=\"bar\" style=\"width:#{pj[:progress]*100}%\"></div></div>")
+    end
+    pj[:output_link] = link_to_if_arvados_object pj[:output]
+    pj[:job_link] = link_to_if_arvados_object pj[:job][:uuid]
+    pj
+  end
+
   protected
 
-  def pipeline_jobs_newschool
+  def pipeline_jobs_newschool object
     ret = []
     i = -1
-    @object.components.each do |cname, c|
+    object.components.each do |cname, c|
       i += 1
       pj = {index: i, name: cname}
       pj[:job] = c[:job].is_a?(Hash) ? c[:job] : {}
@@ -58,20 +76,18 @@ module PipelineInstancesHelper
         end
       end
       pj[:job_id] = pj[:job][:uuid]
-      pj[:job_link] = link_to_if_arvados_object pj[:job][:uuid]
+      pj[:script] = pj[:job][:script]
       pj[:script_version] = pj[:job][:script_version]
       pj[:output] = pj[:job][:output]
       pj[:finished_at] = (Time.parse(pj[:job][:finished_at]) rescue nil)
-      pj[:progress_bar] = raw("<div class=\"progress\" style=\"width:100px\"><div class=\"bar bar-success\" style=\"width:#{pj[:percent_done]}%\"></div><div class=\"bar\" style=\"width:#{pj[:percent_running]}%\"></div></div>")
-      pj[:output_link] = link_to_if_arvados_object pj[:output]
       ret << pj
     end
     ret
   end
 
-  def pipeline_jobs_oldschool
+  def pipeline_jobs_oldschool object
     ret = []
-    @object.components[:steps].each_with_index do |step, i|
+    object.components[:steps].each_with_index do |step, i|
       pj = {index: i, name: step[:name]}
       if step[:complete] and step[:complete] != 0
         if step[:output_data_locator]
@@ -112,8 +128,6 @@ module PipelineInstancesHelper
       pj[:script_version] = (step[:warehousejob][:revision] rescue nil)
       pj[:output] = step[:output_data_locator]
       pj[:finished_at] = (Time.parse(step[:warehousejob][:finishtime]) rescue nil)
-      pj[:progress_bar] = raw("<div class=\"progress\" style=\"width:100px\"><div class=\"bar\" style=\"width:#{pj[:progress]*100}%\"></div></div>")
-      pj[:output_link] = link_to_if_arvados_object pj[:output]
       ret << pj
     end
     ret
diff --git a/apps/workbench/app/views/application/_arvados_object_attr.html.erb b/apps/workbench/app/views/application/_arvados_object_attr.html.erb
index ec2ac36..d7e126e 100644
--- a/apps/workbench/app/views/application/_arvados_object_attr.html.erb
+++ b/apps/workbench/app/views/application/_arvados_object_attr.html.erb
@@ -1,8 +1,9 @@
+<% object ||= @object %>
 <% if attrvalue.is_a? Hash then attrvalue.each do |infokey, infocontent| %>
 <tr class="info">
   <td><%= attr %>[<%= infokey %>]</td>
   <td>
-    <%= render partial: 'application/arvados_attr_value', locals: { obj: @object, attr: nil, attrvalue: infocontent } %>
+    <%= render partial: 'application/arvados_attr_value', locals: { obj: object, attr: nil, attrvalue: infocontent } %>
   </td>
 </tr>
 <% end %>
@@ -10,7 +11,7 @@
 <tr class="<%= 'info' if %w(uuid owner_uuid created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).index(attr.to_s).nil? %>">
   <td><%= attr %></td>
   <td>
-    <%= render partial: 'application/arvados_attr_value', locals: { obj: @object, attr: attr, attrvalue: attrvalue } %>
+    <%= render partial: 'application/arvados_attr_value', locals: { obj: object, attr: attr, attrvalue: attrvalue } %>
   </td>
 </tr>
 <% end %>
diff --git a/apps/workbench/app/views/pipeline_instances/compare.html.erb b/apps/workbench/app/views/pipeline_instances/compare.html.erb
index f75f32a..7f90064 100644
--- a/apps/workbench/app/views/pipeline_instances/compare.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/compare.html.erb
@@ -1,44 +1,78 @@
-<table class="table table-condensed table-hover topalign">
-  <thead>
-  </thead>
-  <tbody>
-    <tr>
-      <% @objects.each do |object| %>
-      <td>
+<% content_for :css do %>
+.notnormal {
+  background: #ffffaa;
+}
+.headrow div {
+  padding-top: .5em;
+  padding-bottom: .5em;
+}
+.headrow:first-child {
+  border-bottom: 1px solid black;
+}
+<% end %>
 
-        <table class="table table-condensed table-hover topalign">
-          <thead>
-          </thead>
-          <tbody>
-            <% object.attributes_for_display.each do |attr, attrvalue| %>
-            <% if attr == 'components' and attrvalue.is_a? Hash %>
+<ul class="breadcrumb">
+  <li><%= link_to 'Pipeline instances', pipeline_instances_path %> <span class="divider">/</span></li>
+  <li class="active">Compare</li>
+</ul>
 
-            <tr class="info"><td><%= attr %></td><td>
-                <table class="table">
-                  <% pipeline_jobs.each do |pj| %>
-                  <tr><% %w(index name result job_link script script_version progress_detail progress_bar output_link).each do |key| %>
-                    <td>
-                      <% if key == 'script_version' %>
-                      <%= pj[key.to_sym][0..6] rescue '' %>
-                      <% else %>
-                      <%= pj[key.to_sym] %>
-                      <% end %>
-                    </td>
-                    <% end %>
-                  </tr>
-                  <% end %>
-                </table>
-            </td></tr>
+<% pi_span = [(10.0/(@objects.count)).floor,1].max %>
+<div>
+<% [['Instance', :uuid], ['Template', :pipeline_template_uuid]].each do |label, attr| %>
+<div class="row headrow">
+  <div class="span2">
+    <%# label %>
+  </div>
+  <% @objects.each do |object| %>
+  <div class="span<%= pi_span %>">
+    <%= render partial: 'application/arvados_attr_value', locals: { obj: object, attr: attr, attrvalue: object.send(attr.to_sym) } %>
+  </div>
+  <% end %>
+</div>
+<% end %>
+</div>
 
-            <% else %>
-            <%= render partial: 'application/arvados_object_attr', locals: { attr: attr, attrvalue: attrvalue } %>
-            <% end %>
-            <% end %>
-          </tbody>
-        </table>
+<% @rows.each do |row| %>
+<div class="row">
+  <div class="span2">
+    <%= row[:name] %>
+  </div>
+  <% @objects.each_with_index do |_, x| %>
+    <div class="span<%= pi_span %>">
+      <div class="row">
 
-      </td>
-      <% end %>
-    </tr>
-  </tbody>
-</table>
+        <% if row[:components][x] %>
+          <% pj = render_pipeline_job row[:components][x] %>
+
+          <div class="span3">
+            <%= link_to_if_arvados_object pj[:job_id], {friendly_name: true, with_class_name: true}, {class: 'deemphasize'} %>
+          </div>
+
+          <% %w(script script_version script_parameters output).each do |key| %>
+            <div class="span3">
+              <% unless key=='output' and pj[:result] != 'complete' %>
+              <% val = pj[key.to_sym] || pj[:job].andand[key.to_sym] %>
+              <% link_name = case
+                 when key == 'script_version' && val.match(/^[0-9a-f]{7,}$/)
+                   val = val[0..7] # TODO: leave val alone, make link_to handle git commits
+                 when key == 'output'
+                   val.sub! /\+K.*$/, ''
+                   val[0..12]
+                 when key == 'script_parameters'
+                   val = val.keys.sort.join(', ')
+                 end
+                 %>
+              <span class="deemphasize"><%= key %>:</span> <span class="<%= 'notnormal' if !pj[:is_normal][key.to_sym] %>"><%= link_to_if_arvados_object val, {friendly_name: true, link_text: link_name} %></span>
+              <% end %>
+            </div>
+          <% end %>
+          <% else %>
+          None
+        <% end %>
+      </div>
+    </div>
+  <% end %>
+</div>
+<div class="row" style="padding: .5em">
+</div>
+<% end %>
diff --git a/apps/workbench/app/views/pipeline_instances/show.html.erb b/apps/workbench/app/views/pipeline_instances/show.html.erb
index 74c090d..a36412e 100644
--- a/apps/workbench/app/views/pipeline_instances/show.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/show.html.erb
@@ -7,7 +7,7 @@
 
     <tr class="info"><td><%= attr %></td><td>
         <table class="table">
-          <% pipeline_jobs.each do |pj| %>
+          <% render_pipeline_jobs.each do |pj| %>
           <tr><% %w(index name result job_link script script_version progress_detail progress_bar output_link).each do |key| %>
             <td>
               <% if key == 'script_version' %>
diff --git a/apps/workbench/config/routes.rb b/apps/workbench/config/routes.rb
index a035535..c9bf19b 100644
--- a/apps/workbench/config/routes.rb
+++ b/apps/workbench/config/routes.rb
@@ -26,9 +26,8 @@ ArvadosWorkbench::Application.routes.draw do
   resources :groups
   resources :specimens
   resources :pipeline_templates
-  resources :pipeline_instances do
-    get 'compare/*uuid' => 'pipeline_instances#compare'
-  end
+  resources :pipeline_instances
+  get '/pipeline_instances/compare/*uuid' => 'pipeline_instances#compare'
   resources :links
   match '/collections/graph' => 'collections#graph'
   resources :collections

commit 043f54270bb129da9f5f07c2c975c6e89edd4a22
Author: Tom Clegg <tom at curoverse.com>
Date:   Tue Jan 28 07:57:47 2014 -0800

    Add pipeline_instances/compare page

diff --git a/apps/workbench/app/controllers/pipeline_instances_controller.rb b/apps/workbench/app/controllers/pipeline_instances_controller.rb
index afb9949..f3932bf 100644
--- a/apps/workbench/app/controllers/pipeline_instances_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_instances_controller.rb
@@ -1,2 +1,12 @@
 class PipelineInstancesController < ApplicationController
+  skip_before_filter :find_object_by_uuid, only: :compare
+  before_filter :find_objects_by_uuid, only: :compare
+
+  def compare
+  end
+
+  protected
+  def find_objects_by_uuid
+    @objects = model_class.where(uuid: params[:uuid])
+  end
 end
diff --git a/apps/workbench/app/views/pipeline_instances/compare.html.erb b/apps/workbench/app/views/pipeline_instances/compare.html.erb
new file mode 100644
index 0000000..f75f32a
--- /dev/null
+++ b/apps/workbench/app/views/pipeline_instances/compare.html.erb
@@ -0,0 +1,44 @@
+<table class="table table-condensed table-hover topalign">
+  <thead>
+  </thead>
+  <tbody>
+    <tr>
+      <% @objects.each do |object| %>
+      <td>
+
+        <table class="table table-condensed table-hover topalign">
+          <thead>
+          </thead>
+          <tbody>
+            <% object.attributes_for_display.each do |attr, attrvalue| %>
+            <% if attr == 'components' and attrvalue.is_a? Hash %>
+
+            <tr class="info"><td><%= attr %></td><td>
+                <table class="table">
+                  <% pipeline_jobs.each do |pj| %>
+                  <tr><% %w(index name result job_link script script_version progress_detail progress_bar output_link).each do |key| %>
+                    <td>
+                      <% if key == 'script_version' %>
+                      <%= pj[key.to_sym][0..6] rescue '' %>
+                      <% else %>
+                      <%= pj[key.to_sym] %>
+                      <% end %>
+                    </td>
+                    <% end %>
+                  </tr>
+                  <% end %>
+                </table>
+            </td></tr>
+
+            <% else %>
+            <%= render partial: 'application/arvados_object_attr', locals: { attr: attr, attrvalue: attrvalue } %>
+            <% end %>
+            <% end %>
+          </tbody>
+        </table>
+
+      </td>
+      <% end %>
+    </tr>
+  </tbody>
+</table>
diff --git a/apps/workbench/config/routes.rb b/apps/workbench/config/routes.rb
index f2480c6..a035535 100644
--- a/apps/workbench/config/routes.rb
+++ b/apps/workbench/config/routes.rb
@@ -26,7 +26,9 @@ ArvadosWorkbench::Application.routes.draw do
   resources :groups
   resources :specimens
   resources :pipeline_templates
-  resources :pipeline_instances
+  resources :pipeline_instances do
+    get 'compare/*uuid' => 'pipeline_instances#compare'
+  end
   resources :links
   match '/collections/graph' => 'collections#graph'
   resources :collections

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list