Improvements and bugfixes refs #2242.
authorPeter Amstutz <peter.amstutz@curoverse.com>
Thu, 6 Mar 2014 20:49:25 +0000 (15:49 -0500)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Thu, 6 Mar 2014 20:49:25 +0000 (15:49 -0500)
* Added tooltip to "play" button on pipeline templates page.
* Adjusted play button styling.
* Added a little bit of text to tell the user what to do on the parameter editing page.
* Moved "run pipeline" button to the tab bar row.
* Fixed the "-selection-" and "-recent-" dividers to be invalid selections.
* Tweaked editing popup label to say "set value for xxx" instead of "update xxx"
* Refactored status labels and progress bars for jobs and pipelines into partials that should be used everywhere consistently
* Fixed automatic refresh of pipeline instance page to emit ajax:complete event, and fixed shown.bs.tab event to catch all events and then apply the selector, instead of having to use the selector to attach events to specific DOM nodes (which breaks when the page is refreshed.)

16 files changed:
apps/workbench/app/assets/javascripts/editable.js
apps/workbench/app/assets/javascripts/selection.js
apps/workbench/app/controllers/pipeline_instances_controller.rb
apps/workbench/app/helpers/application_helper.rb
apps/workbench/app/helpers/pipeline_instances_helper.rb
apps/workbench/app/views/application/_content.html.erb
apps/workbench/app/views/application/_job_progress.html.erb [new file with mode: 0644]
apps/workbench/app/views/application/_job_status_label.html.erb [new file with mode: 0644]
apps/workbench/app/views/application/_pipeline_progress.html.erb [new file with mode: 0644]
apps/workbench/app/views/application/_pipeline_status_label.html.erb [new file with mode: 0644]
apps/workbench/app/views/jobs/_show_recent.html.erb
apps/workbench/app/views/pipeline_instances/_show_components.html.erb
apps/workbench/app/views/pipeline_instances/_show_recent.html.erb
apps/workbench/app/views/pipeline_instances/show.js.erb
apps/workbench/app/views/pipeline_templates/_show_recent.html.erb
apps/workbench/app/views/users/_tables.html.erb

index a74358694213fe36041d32852111741bf1581f1a..adb49d7c15b6628d56729821e618ef534f1b18ba 100644 (file)
@@ -9,3 +9,9 @@ $.fn.editable.defaults.params = function (params) {
     a[key][params.name] = params.value;
     return a;
 };
+
+$.fn.editable.defaults.validate = function (value) {
+    if (value == "***invalid***") {
+        return "Invalid selection";
+    }
+}
\ No newline at end of file
index c8ec8100ac90c7fdb2c559c9f73feac4603443a8..24dc9bd91f81f40f7beee9a263a398dd05e2c220 100644 (file)
@@ -136,7 +136,10 @@ select_form_sources  = null;
         if (get_selection_list) {
             var lst = get_selection_list();
             if (lst.length > 0) {
-                ret.push({text: "--- Selections ---", value: ""});
+                var text = "&horbar; Selections &horbar;";
+                var span = document.createElement('span');
+                span.innerHTML = text;
+                ret.push({text: span.innerHTML, value: "***invalid***"});
 
                 for (var i = 0; i < lst.length; i++) {
                     if (lst[i].type == type) {
@@ -145,7 +148,11 @@ select_form_sources  = null;
                 }
             }
         }
-        ret.push({text: "--- Recent ---", value: ""});
+
+        var text = "&horbar; Recent &horbar;";
+        var span = document.createElement('span');
+        span.innerHTML = text;
+        ret.push({text: span.innerHTML, value: "***invalid***"});
 
         var t = form_selection_sources[type];
         for (var key in t) {
index 83746289e437d96914437bde9c3510689f78ac41..e477102985121529455164116a92b0baccef9735 100644 (file)
@@ -182,6 +182,11 @@ class PipelineInstancesController < ApplicationController
     super
   end
 
+  def index
+    @objects ||= model_class.limit(20).all
+    super
+  end
+
   protected
   def for_comparison v
     if v.is_a? Hash or v.is_a? Array
index 01569ebd58325e6d02c86d5ba2844f7d1bbe8397..697f84355d1b4cdd7e6defc587f33c0130d6b7a1 100644 (file)
@@ -183,7 +183,9 @@ module ApplicationHelper
 
     if dataclass and dataclass.is_a? Class
       items = []
-      items.append({name: attrvalue, uuid: attrvalue, type: dataclass.to_s})
+      if attrvalue and !attrvalue.empty?
+        items.append({name: attrvalue, uuid: attrvalue, type: dataclass.to_s})
+      end
       #dataclass.where(uuid: attrvalue).each do |item|
       #  items.append({name: item.uuid, uuid: item.uuid, type: dataclass.to_s})
       #end
@@ -206,7 +208,7 @@ module ApplicationHelper
       :id => id
     }.merge(htmloptions)
 
-    lt += raw('<script>')
+    lt += raw("\n<script>")
     
     if items and items.length > 0
       lt += raw("add_form_selection_sources(#{items.to_json});\n")
index f3ac35dec38a88239a2a91f891ff62fc52df5f61..d0caf121199fa2a322dce0ce25eb7922f8970e2c 100644 (file)
@@ -1,30 +1,4 @@
 module PipelineInstancesHelper
-  def pipeline_summary object=nil
-    object ||= @object
-    ret = {todo:0, running:0, queued:0, done:0, failed:0, total:0}
-    object.components.values.each do |c|
-      ret[:total] += 1
-      case
-      when !c[:job]
-        ret[:todo] += 1
-      when c[:job][:success]
-        ret[:done] += 1
-      when c[:job][:failed]
-        ret[:failed] += 1
-      when c[:job][:finished_at]
-        ret[:running] += 1      # XXX finished but !success and !failed??
-      when c[:job][:started_at]
-        ret[:running] += 1
-      else
-        ret[:queued] += 1
-      end
-    end
-    ret.merge! Hash[ret.collect do |k,v|
-                      [('percent_' + k.to_s).to_sym,
-                       ret[:total]<1 ? 0 : (100.0*v/ret[:total]).floor]
-                    end]
-    ret
-  end
 
   def pipeline_jobs object=nil
     object ||= @object
@@ -42,26 +16,13 @@ module PipelineInstancesHelper
   end
 
   def render_pipeline_job pj
-    if pj[:percent_done]
-      pj[:progress_bar] = raw <<EOF
-<div class="progress" style="width:100%">
-  <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 <<EOF
-<div class="progress" style="width:100%">
-<span class="progress-bar" style="width:#{pj[:progress]*100}%">
-</span>
-</div>
-EOF
-    end
+    pj[:progress_bar] = render partial: 'job_progress', locals: {:j => pj[:job]}
     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 object
index 02efdf9999dfe5d004aad06df8a8709849c33a40..53444a5c9c72defe283deff498996f1c8ffb7782 100644 (file)
@@ -25,7 +25,6 @@
 <% end %>
 
 <% content_for :js do %>
-  $(window).on('load', function() {
-    $('ul.nav-tabs > li > a').on('shown.bs.tab', smart_scroll_fixup);
-   });
+    $(window).on('load', smart_scroll_fixup);
+    $(document).on('shown.bs.tab', 'ul.nav-tabs > li > a', smart_scroll_fixup);
 <% end %>
diff --git a/apps/workbench/app/views/application/_job_progress.html.erb b/apps/workbench/app/views/application/_job_progress.html.erb
new file mode 100644 (file)
index 0000000..a25acc3
--- /dev/null
@@ -0,0 +1,20 @@
+<% percent_total_tasks = 100 / (j[:tasks_summary][:done] + j[:tasks_summary][:running] + j[:tasks_summary][:failed] + j[:tasks_summary][:todo]) rescue 0 %>
+
+<% if defined? scaleby %>
+  <% percent_total_tasks *= scaleby %>
+<% end %>
+
+<% if not defined? scaleby %>
+  <div class="progress">
+<% end %>
+
+<span class="progress-bar progress-bar-success" style="width: <%= j[:tasks_summary][:done] * percent_total_tasks rescue 0 %>%;">
+</span>
+<span class="progress-bar progress-bar-danger" style="width: <%= j[:tasks_summary][:failed] * percent_total_tasks rescue 0 %>%;">
+</span>
+<span class="progress-bar" style="width: <%= j[:tasks_summary][:running] * percent_total_tasks rescue 0 %>%;">
+</span>
+
+<% if not defined? scaleby %>
+</div>
+<% end %>
diff --git a/apps/workbench/app/views/application/_job_status_label.html.erb b/apps/workbench/app/views/application/_job_status_label.html.erb
new file mode 100644 (file)
index 0000000..87b70fe
--- /dev/null
@@ -0,0 +1,11 @@
+<% if j[:success] %>
+  <span class="label label-success"><%= if defined? title then title else 'success' end %></span>
+<% elsif j[:success] == false %>
+  <span class="label label-danger"><%= if defined? title then title else 'failed' end %></span>
+<% elsif j[:finished_at] %>
+  <span class="label label-default"><%= if defined? title then title else 'finished' end %></span>
+<% elsif j[:started_at] %>
+  <span class="label label-info"><%= if defined? title then title else 'running' end %></span>
+<% else %>
+  <span class="label label-default"><%= if defined? title then title else 'not running' end %></span>
+<% end %>
diff --git a/apps/workbench/app/views/application/_pipeline_progress.html.erb b/apps/workbench/app/views/application/_pipeline_progress.html.erb
new file mode 100644 (file)
index 0000000..d478f65
--- /dev/null
@@ -0,0 +1,8 @@
+<% component_frac = 1.0 / p.components.length %>
+<div class="progress">
+  <% p.components.each do |k,c| %>
+    <% if c[:job] %>
+      <%= render partial: "job_progress", locals: {:j => c[:job], :scaleby => component_frac } %>
+    <% end %>
+  <% end %>
+</div>
diff --git a/apps/workbench/app/views/application/_pipeline_status_label.html.erb b/apps/workbench/app/views/application/_pipeline_status_label.html.erb
new file mode 100644 (file)
index 0000000..020ce81
--- /dev/null
@@ -0,0 +1,13 @@
+<% if p.success %>
+  <span class="label label-success">finished</span>
+<% elsif p.success == false %>
+  <span class="label label-danger">failed</span>
+<% elsif p.active %>
+  <span class="label label-info">running</span>
+<% else %>
+  <% if (p.components.select do |k,v| v[:job] end).length == 0 %>
+    <span class="label label-default">not started</span>
+  <% else %>
+    <span class="label label-default">not running</span>
+  <% end %>
+<% end %>
index 85331f3e44610c663510d1d5985151e5fcd327b3..304a3b5c1f0cc449cec74906e6273a510da016d2 100644 (file)
         <i class="icon-plus-sign expand-collapse-row" data-id="<%= j.uuid %>" style="cursor: pointer"></i>
       </td>
       <td>
-        <% if j.success == false %>
-        <span class="badge badge-warning" title="fail">&#x2716;</span>
-        <% elsif j.success %>
-        <span class="badge badge-success" title="success">&#x2714;</span>
-        <% elsif j.running %>
-        <span class="badge badge-info" title="running">&#x2708;</span>
-        <% else %>
-        <span class="badge" title="queued">&#x2709;</span>
-        <% end %>
+        <%= render partial: 'job_status_label', locals: {:j => j} %>
       </td>
       <td>
-        <% if j.started_at and not j.finished_at %>
-        <% percent_total_tasks = 100 / (j.tasks_summary[:running] + j.tasks_summary[:done] + j.tasks_summary[:todo]) rescue 0 %>
-        <div class="progress" style="margin-bottom: 0">
-          <div class="bar bar-success" style="width: <%= j.tasks_summary[:done] * percent_total_tasks rescue 0 %>%;"></div>
-          <div class="bar" style="width: <%= j.tasks_summary[:running] * percent_total_tasks rescue 0 %>%; opacity: 0.3"></div>
+        <div class="inline-progress-container">
+          <%= render partial: 'job_progress', locals: {:j => j} %>
         </div>
-        <% end %>
       </td>
       <td>
         <%= link_to_if_arvados_object j.uuid %>
index 24579c9b4b4c74bda726f13cec1455c78a9b4a1f..170e3f54221d851e7718a95d6b24c9a23ce8ad21 100644 (file)
@@ -28,8 +28,11 @@ td.required {
 <% end %>
 
 <% template = PipelineTemplate.find(@object.pipeline_template_uuid) %>
-<% if template %>
-  <h2><%= template.name %></h2>
+<%= content_for :content_top do %>
+  <% if template %>
+    <h2><%= template.name %></h2>
+  <% end %>
+  
 <% end %>
 
 <% if @object.active != nil %>
@@ -38,7 +41,7 @@ td.required {
     <col style="width: 15%" />
     <col style="width: 20%" />
     <col style="width: 12%" />
-    <col style="width: 8%" />
+    <col style="width: 12%" />
     <col style="width: 45%" />
   </colgroup>
   <thead>
@@ -60,38 +63,21 @@ td.required {
     <% 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 %>
+        <% job_status = render(partial: 'job_status_label', 
+                               locals: { :j => pj[:job], :title => pj[:name] }) %>
         <% if pj[:job].andand[:uuid] %>
-        <%= link_to pj[:name], job_url(id: pj[:job][:uuid]), class: "label #{label}" %>
+          <%= link_to(job_status, job_url(id: pj[:job][:uuid])) %>
         <% else %>
-          <span class="label <%= label %>"><%= pj[:name] %></span>
+          <%= job_status %>
         <% 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="label label-warning">cancelled</span>
-        <% elsif pj[:failed] %>
-        <span class="label label-danger">failed</span>
-        <% elsif pj[:result] == 'queued' %>
-        <span class="label">queued</span>
-        <% end %>
+        <%= render(partial: 'job_status_label', 
+                               locals: { :j => pj[:job] }) %>
       </td><td>
         <%= link_to_if_arvados_object pj[:output] %>
       </td>
@@ -99,7 +85,7 @@ td.required {
     <% end %>
   </tbody>
   <tfoot>
-    <tr><td colspan="4"></td></tr>
+    <tr><td colspan="5"></td></tr>
   </tfoot>
 </table>
 
@@ -111,10 +97,15 @@ setInterval(function(){$('a.refresh').click()}, 15000);
 
 <% else %>
 
-  <%= form_tag @object, :method => :put do |f| %>
+  <p>Please set the desired input parameters for the components of this pipeline.  Parameters highlighted in red are required.</p>
+
+  <% content_for :tab_line_buttons do %>
+    <%= form_tag @object, :method => :put do |f| %>
+      
+      <%= hidden_field @object.class.to_s.underscore.singularize.to_sym, :active, :value => true %>
 
-  <%= 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"} %>
+      <%= button_tag "Run pipeline", {class: 'btn btn-primary pull-right', id: "run-pipeline-button"} %>
+    <% end %>
   <% end %>
 
 <table class="table pipeline-components-table" style="margin-top: -.1em">
index ed5b2d086a83a843ac96fa38bd364ecc2ba7f958..09eae0f35122f760b2d72de3c618e4eaca92b407 100644 (file)
 <table class="table table-condensed table-fixedlayout">
   <colgroup>
     <col width="5%" />
-    <col width="10%" />
+    <col width="15%" />
+    <col width="25%" />
     <col width="20%" />
-    <col width="10%" />
-    <col width="30%" />
     <col width="15%" />
-    <col width="10%" />
+    <col width="20%" />
   </colgroup>
   <thead>
     <tr class="contain-align-left">
@@ -24,7 +23,7 @@
        Status
       </th><th>
        Instance
-      </th><th colspan="2">
+      </th><th>
        Template
       </th><th>
        Owner
       <td>
         <%= check_box_tag 'uuids[]', ob.uuid, false, :class => 'persistent-selection' %>
       </td><td>
-        <% if ob.success %>
-        <span class="label label-success">success</span>
-        <% elsif ob.active %>
-        <span class="label label-info">active</span>
-        <% end %>
-      </td><td colspan="2">
+        <%= render partial: 'pipeline_status_label', locals: {:p => ob} %>
+      </td><td colspan="1">
         <%= link_to_if_arvados_object ob, friendly_name: true %>
       </td><td>
         <%= link_to_if_arvados_object ob.pipeline_template_uuid, friendly_name: true %>
       </td>
       <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] == true
-                      'success'
-                    elsif c[:job][:success] == false
-                      'danger'
-                    elsif c[:job][:running] == true
-                      'info'
-                    else
-                      'warning'
-                    end %>
-        <span class="label label-<%= status || 'default' %>"><%= cname.to_s %></span>
+          <% if c[:job] %>
+            <%= render partial: "job_status_label", locals: {:j => c[:job], :title => cname.to_s } %>
+          <% else %>
+            <span class="label label-default"><%= cname.to_s %></span>            
+          <% end %>
         <% end %>
       </td>
     </tr>
index fc11e644249468e391a9762154882cb36aafe4a2..cfe288d0e322785294fce8bbcaaf8c4f144e268e 100644 (file)
@@ -2,3 +2,4 @@
 var new_content = "<%= escape_javascript(render template: 'pipeline_instances/show') %>";
 if ($('div.body-content').html() != new_content)
    $('div.body-content').html(new_content);
+$(document).trigger('ajax:complete');
index f878f5980664c4b775d7386bc7c437832864b1d9..342a74331e567f9bc7fd7a7e7f1380b5b87161de 100644 (file)
@@ -1,14 +1,13 @@
 <% content_for :css do %>
   .playbutton {
   color: white;
-  background: gray;
+  background: rgb(91, 192, 222);
   border: 0px;
   border-radius: 3px;
-  padding: 0px 3px;
+  padding: 0px 3px;  
   }
   .playbutton:hover {
-  color: white;
-  background: blackh;
+  background: rgb(57, 179, 215);
   }
 <% end %>
 
@@ -35,7 +34,7 @@
       <td>
         <%= form_tag '/pipeline_instances' do |f| %>
           <%= hidden_field :pipeline_instance, :pipeline_template_uuid, :value => ob.uuid %>
-          <%= button_tag nil, {class: 'playbutton'} do %>
+          <%= button_tag nil, {class: 'playbutton', title: "Run #{ob.name}"} do %>
             <span class="glyphicon glyphicon-play"></span>
           <% end %>
         <% end %>
index f9e3b6c8bec38c36482f99224af7f296cea3b463..08749307852a92992c7ba809628babd70763d769 100644 (file)
 </td>
 
 <td>
-  <% if j.success %>
-    <span class="label label-success">finished</span>
-  <% elsif j.success == false %>
-    <span class="label label-danger">failed</span>
-  <% elsif j.finished_at %>
-    <span class="label">finished?</span>
-  <% elsif j.started_at %>
-    <span class="label label-info">running</span>
-  <% else %>
-    <span class="label">queued</span>
-  <% end %>
+  <%= render partial: 'job_status_label', locals: {:j => j} %>
 </td>
 <td>
-  <% percent_total_tasks = 100 / (j.tasks_summary[:running] + j.tasks_summary[:done] + j.tasks_summary[:todo]) rescue 0 %>
   <div class="inline-progress-container">
-    <div class="progress">
-      <span class="progress-bar progress-bar-success" style="width: <%= j.tasks_summary[:done] * percent_total_tasks rescue 0 %>%;">
-      </span>
-      <span class="progress-bar" style="width: <%= j.tasks_summary[:running] * percent_total_tasks rescue 0 %>%;">
-      </span>
-      <% if j.success == false %>
-      <span class="progress-bar progress-bar-danger" style="width: <%= tasks_summary[:failed] * percent_total_tasks rescue 0 %>%;">
-      </span>
-      <% end %>
-    </div>
+  <%= render partial: 'job_progress', locals: {:j => j} %>
   </div>
 </td>
 
           </td>
 
           <td>
-            <% if p.success %>
-              <span class="label label-success">finished</span>
-            <% elsif p.success == false %>
-              <span class="label label-danger">failed</span>
-            <% elsif p.active and p.modified_at < 30.minutes.ago %>
-              <span class="label label-info">stopped</span>
-            <% elsif p.active %>
-              <span class="label label-info">running</span>
-            <% else %>
-              <span class="label">queued</span>
-            <% end %>
+            <%= render partial: 'pipeline_status_label', locals: {:p => p} %>
           </td>
+
           <td>
-            <% summary = pipeline_summary p %>
             <div class="inline-progress-container">
-              <div class="progress">
-                <span class="progress-bar progress-bar-success" style="width: <%= summary[:percent_done] %>%;">
-                </span>
-                <% if p.success == false %>
-                <span class="progress-bar progress-bar-danger" style="width: <%= 100.0 - summary[:percent_done] %>%;">
-                </span>
-                <% else %>
-                <span class="progress-bar" style="width: <%= summary[:percent_running] %>%;">
-                </span>
-                <span class="progress-bar progress-bar-info" style="width: <%= summary[:percent_queued] %>%;">
-                </span>
-                <span class="progress-bar progress-bar-danger" style="width: <%= summary[:percent_failed] %>%;">
-                </span>
-                <% end %>
-              </div>
+              <%= render partial: 'pipeline_progress', locals: {:p => p} %>
             </div>
           </td>
-
         </tr>
       <% end %>
     </table>