[ARVADOS] created: 06f5f794cd1fc8cb4dbf72e3a2fbc440b44101b9

git at public.curoverse.com git at public.curoverse.com
Mon Jun 2 01:25:58 EDT 2014


        at  06f5f794cd1fc8cb4dbf72e3a2fbc440b44101b9 (commit)


commit 06f5f794cd1fc8cb4dbf72e3a2fbc440b44101b9
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jun 2 01:24:55 2014 -0400

    2872: Show collection details in chooser.

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 0941921..c1e82eb 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -495,4 +495,15 @@ class ApplicationController < ActionController::Base
       root_of[g.uuid] == current_user.uuid
     end
   end
+
+  helper_method :get_object
+  def get_object uuid
+    if @get_object.nil? and @objects
+      @get_object = @objects.each_with_object({}) do |object, h|
+        h[object.uuid] = object
+      end
+    end
+    @get_object ||= {}
+    @get_object[uuid]
+  end
 end
diff --git a/apps/workbench/app/views/collections/_choose_rows.html.erb b/apps/workbench/app/views/collections/_choose_rows.html.erb
index 8622830..55e6451 100644
--- a/apps/workbench/app/views/collections/_choose_rows.html.erb
+++ b/apps/workbench/app/views/collections/_choose_rows.html.erb
@@ -1,11 +1,15 @@
 <% @name_links.each do |name_link| %>
   <div class="row selectable <%= 'multiple' if multiple %>" data-object-uuid="<%= name_link.uuid %>">
-    <div class="col-sm-8" style="overflow-x:hidden">
+    <div class="col-lg-12" style="overflow-x:hidden">
       <i class="fa fa-fw fa-archive"></i>
       <%= name_link.name %>
     </div>
-    <div class="col-sm-4" style="overflow-x:hidden">
-      <%= link_to_if_arvados_object name_link.tail_uuid, friendly_name: true %>
+    <div class="col-lg-12 arv-description-in-table">
+      <%= render_controller_partial(
+          'show_object_description_cell.html',
+          controller_name: 'collections',
+          locals: {object: get_object(name_link.head_uuid)})
+          %>
     </div>
   </div>
 <% end %>
diff --git a/apps/workbench/app/views/collections/_show_object_description_cell.html.erb b/apps/workbench/app/views/collections/_show_object_description_cell.html.erb
index 0b3352b..1f1325d 100644
--- a/apps/workbench/app/views/collections/_show_object_description_cell.html.erb
+++ b/apps/workbench/app/views/collections/_show_object_description_cell.html.erb
@@ -1,9 +1,4 @@
 <div class="nowrap">
-  <div>
-    <% Link.filter([['link_class','=','tag'],['head_uuid','=',object.uuid]]).collect(&:name).each do |tagname| %>
-      <span class="label label-info"><%= tagname %></span>
-    <% end %>
-  </div>
   <span class="deemphasize">
     Files (<%= human_readable_bytes_html(object.total_bytes) %>):
   </span><span class="arvados-filename">
@@ -11,4 +6,9 @@
       <%= file %>
     <% end %>
   </span>
+  <div>
+    <% Link.filter([['link_class','=','tag'],['head_uuid','=',object.uuid]]).collect(&:name).each do |tagname| %>
+      <span class="label label-info"><%= tagname %></span>
+    <% end %>
+  </div>
 </div>

commit 830678c2715bac06d581dcdce8ea518c1bcc2939
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jun 2 01:10:17 2014 -0400

    2872: Fix css on collection tab line buttons.

diff --git a/apps/workbench/app/views/collections/_show_files.html.erb b/apps/workbench/app/views/collections/_show_files.html.erb
index 74e02f7..c461163 100644
--- a/apps/workbench/app/views/collections/_show_files.html.erb
+++ b/apps/workbench/app/views/collections/_show_files.html.erb
@@ -1,14 +1,6 @@
 <% content_for :tab_line_buttons do %>
-<div class="row">
-  <div class="col-md-6"></div>
-  <div class="col-md-6">
-    <div class="pull-right">
-      <span style="padding-left: 1em">Collection storage status:</span>
-      <%= render partial: 'toggle_persist', locals: { uuid: @object.uuid, current_state: (@is_persistent ? 'persistent' : 'cache') } %>
-
-    </div>
-  </div>
-</div>
+<span style="padding-left: 1em">Collection storage status:</span>
+<%= render partial: 'toggle_persist', locals: { uuid: @object.uuid, current_state: (@is_persistent ? 'persistent' : 'cache') } %>
 <% end %>
 
 <% file_tree = @object.andand.files_tree %>

commit bff608d3f7430cb0f97d2ac185d1d7674c6b9ff8
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jun 2 01:09:06 2014 -0400

    2872: Add useful pipeline instance content summary.

diff --git a/apps/workbench/app/helpers/pipeline_instances_helper.rb b/apps/workbench/app/helpers/pipeline_instances_helper.rb
index 7b6fb72..35d28d5 100644
--- a/apps/workbench/app/helpers/pipeline_instances_helper.rb
+++ b/apps/workbench/app/helpers/pipeline_instances_helper.rb
@@ -82,17 +82,22 @@ module PipelineInstancesHelper
       end
       if pj[:job][:success]
         pj[:result] = 'complete'
+        pj[:labeltype] = 'success'
         pj[:complete] = true
         pj[:progress] = 1.0
       elsif pj[:job][:finished_at]
         pj[:result] = 'failed'
+        pj[:labeltype] = 'danger'
         pj[:failed] = true
       elsif pj[:job][:started_at]
         pj[:result] = 'running'
+        pj[:labeltype] = 'primary'
       elsif pj[:job][:uuid]
         pj[:result] = 'queued'
+        pj[:labeltype] = 'default'
       else
         pj[:result] = 'none'
+        pj[:labeltype] = 'default'
       end
       pj[:job_id] = pj[:job][:uuid]
       pj[:script] = pj[:job][:script] || c[:script]
diff --git a/apps/workbench/app/views/pipeline_instances/_component_labels.html.erb b/apps/workbench/app/views/pipeline_instances/_component_labels.html.erb
new file mode 100644
index 0000000..d2d824b
--- /dev/null
+++ b/apps/workbench/app/views/pipeline_instances/_component_labels.html.erb
@@ -0,0 +1,5 @@
+<% pipeline_jobs(object).each do |pj| %>
+  <span class="label label-<%= pj[:labeltype] %>">
+    <%= pj[:name] %>
+  </span> 
+<% end %>
diff --git a/apps/workbench/app/views/pipeline_instances/_show_object_description_cell.html.erb b/apps/workbench/app/views/pipeline_instances/_show_object_description_cell.html.erb
new file mode 100644
index 0000000..38f51a3
--- /dev/null
+++ b/apps/workbench/app/views/pipeline_instances/_show_object_description_cell.html.erb
@@ -0,0 +1,4 @@
+<div class="nowrap">
+  <%= object.content_summary %><br />
+  <%= render partial: 'pipeline_instances/component_labels', locals: {object: object} %>
+</div>

commit a9f77ff084be7ad9caeb9e9601c022cb05e3c548
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jun 2 00:52:50 2014 -0400

    2872: Disable chooser OK button until selection is made, update run-pipeline wording.

diff --git a/apps/workbench/app/assets/javascripts/select_modal.js b/apps/workbench/app/assets/javascripts/select_modal.js
index 278dbb5..6e22d80 100644
--- a/apps/workbench/app/assets/javascripts/select_modal.js
+++ b/apps/workbench/app/assets/javascripts/select_modal.js
@@ -1,4 +1,5 @@
 $(document).on('click', '.selectable', function() {
+    var any;
     var $this = $(this);
     if (!$this.hasClass('multiple')) {
         $this.closest('.selectable-container').
@@ -6,6 +7,13 @@ $(document).on('click', '.selectable', function() {
             removeClass('active');
     }
     $this.toggleClass('active');
+    any = ($this.
+           closest('.selectable-container').
+           find('.selectable.active').length > 0)
+    $this.
+        closest('.modal').
+        find('[data-enable-if-selection]').
+        prop('disabled', !any);
 }).on('click', '.modal button[data-action-href]', function() {
     var selection = [];
     var data = [];
diff --git a/apps/workbench/app/views/application/_choose.html.erb b/apps/workbench/app/views/application/_choose.html.erb
index 2b4f61e..94ed8e6 100644
--- a/apps/workbench/app/views/application/_choose.html.erb
+++ b/apps/workbench/app/views/application/_choose.html.erb
@@ -15,7 +15,7 @@
 
       <div class="modal-footer">
         <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Cancel</button>
-        <button class="btn btn-primary" aria-hidden="true"><%= params[:action_name] || 'Select' %></button>
+        <button class="btn btn-primary" aria-hidden="true" data-enable-if-selection disabled><%= raw(params[:action_name]) || 'Select' %></button>
         <div class="modal-error hide" style="text-align: left; margin-top: 1em;">
         </div>
       </div>
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index 3a11930..450ba29 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -36,7 +36,7 @@
         <%= link_to(
               choose_pipeline_templates_path(
                 title: 'Choose a pipeline to run:',
-                action_name: 'Configure...',
+                action_name: 'Next: choose inputs <i class="fa fa-fw fa-arrow-circle-right"></i>',
                 action_href: pipeline_instances_path,
                 action_method: 'post',
                 action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
diff --git a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
index b8f94d5..6d6a8b1 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
@@ -10,7 +10,8 @@
   </h2>
   <% if template %>
   <blockquote><span class="deemphasize">From template:</span><br />
-    <%= link_to_if_arvados_object template, friendly_name: true %>
+    <%= link_to_if_arvados_object template, friendly_name: true %><br />
+    <%= template.description %>
   </blockquote>
   <% end %>
 <% end %>
@@ -120,7 +121,7 @@ setInterval(function(){$('a.refresh').click()}, 15000);
 
 <% else %>    <%# State new or ready or paused %>
   <% if @object.state == 'New' %>
-    <p>Please set the desired input parameters for the components of this pipeline.  Parameters highlighted in red are required.</p>
+    <p><i>Here are all of the pipeline's components (jobs that will need to run in order to complete the pipeline). If you know what you're doing (or you're experimenting) you can modify these parameters before starting the pipeline. Usually, you only need to edit the settings presented on the "Inputs" tab above.</i></p>
   <% end %>
 
   <% content_for :tab_line_buttons do %>

commit 0a6ca2aada7bc0706fd1e41c1002cd6aa375c3a1
Author: Tom Clegg <tom at curoverse.com>
Date:   Mon Jun 2 00:18:42 2014 -0400

    2872: Add infinite scroll to chooser modal.

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 3ed440f..0941921 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -129,8 +129,25 @@ class ApplicationController < ActionController::Base
   end
 
   def choose
+    params[:limit] ||= 20
     find_objects_for_index if !@objects
-    render partial: 'choose', locals: {multiple: params[:multiple]}
+    respond_to do |f|
+      if params[:partial]
+        f.json {
+          render json: {
+            content: render_to_string(partial: "choose_rows.html",
+                                      formats: [:html],
+                                      locals: {
+                                        multiple: params[:multiple]
+                                      }),
+            next_page_href: @next_page_href
+          }
+        }
+      end
+      f.js {
+        render partial: 'choose', locals: {multiple: params[:multiple]}
+      }
+    end
   end
 
   def render_content
diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index 4ba23c5..24b9b1f 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -41,10 +41,13 @@ class CollectionsController < ApplicationController
   end
 
   def choose
+    params[:limit] ||= 20
     @objects = Link.
       filter([['link_class','=','name'],
               ['head_uuid','is_a','arvados#collection']])
     find_objects_for_index
+    @next_page_href = (next_page_offset and
+                       url_for(offset: next_page_offset, partial: true))
     @name_links = @objects
     @objects = Collection.
       filter([['uuid','in', at name_links.collect(&:head_uuid)]])
diff --git a/apps/workbench/app/controllers/folders_controller.rb b/apps/workbench/app/controllers/folders_controller.rb
index b7b4854..637ae36 100644
--- a/apps/workbench/app/controllers/folders_controller.rb
+++ b/apps/workbench/app/controllers/folders_controller.rb
@@ -82,7 +82,8 @@ class FoldersController < ApplicationController
   end
 
   def show
-    @objects = @object.contents(include_linked: true,
+    @objects = @object.contents(limit: 50,
+                                include_linked: true,
                                 offset: params[:offset] || 0)
     @share_links = Link.filter([['head_uuid', '=', @object.uuid],
                                 ['link_class', '=', 'permission']])
diff --git a/apps/workbench/app/views/application/_choose.html.erb b/apps/workbench/app/views/application/_choose.html.erb
index cf18cdc..2b4f61e 100644
--- a/apps/workbench/app/views/application/_choose.html.erb
+++ b/apps/workbench/app/views/application/_choose.html.erb
@@ -8,7 +8,7 @@
       </div>
 
       <div class="modal-body">
-        <div class="container-fluid arv-folder-list selectable-container" style="height: 15em; overflow-y: scroll">
+        <div class="container-fluid arv-folder-list selectable-container" style="height: 15em; overflow-y: scroll" data-infinite-scroller="#choose-scroll" id="choose-scroll" data-infinite-content-href="<%= @next_page_href %>">
           <%= render partial: 'choose_rows', locals: {multiple: multiple} %>
         </div>
       </div>

commit 70ac6969e76770bcc6becfe94aa5811a0f320fcb
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 17:27:15 2014 -0400

    2872: Rearrange folder index. Show collection tags and files in folder view.

diff --git a/apps/workbench/app/assets/javascripts/editable.js b/apps/workbench/app/assets/javascripts/editable.js
index a32eb7e..093a671 100644
--- a/apps/workbench/app/assets/javascripts/editable.js
+++ b/apps/workbench/app/assets/javascripts/editable.js
@@ -41,10 +41,9 @@ $.fn.editable.defaults.validate = function (value) {
 
 $(document).
     on('ready ajax:complete', function() {
-        $('#editable-submit').click(function() {
-            console.log($(this));
-        });
         $('.editable').
+            not('.editable-done-setup').
+            addClass('editable-done-setup').
             editable({
                 success: function(response, newValue) {
                     // If we just created a new object, stash its UUID
@@ -77,10 +76,13 @@ $(document).
             });
     }).
     on('ready ajax:complete', function() {
-        $("[data-toggle~='x-editable']").click(function(e) {
-            e.stopPropagation();
-            $($(this).attr('data-toggle-selector')).editable('toggle');
-        });
+        $("[data-toggle~='x-editable']").
+            not('.editable-done-setup').
+            addClass('editable-done-setup').
+            click(function(e) {
+                e.stopPropagation();
+                $($(this).attr('data-toggle-selector')).editable('toggle');
+            });
     });
 
 $.fn.editabletypes.text.defaults.tpl = '<input type="text" name="editable-text">'
diff --git a/apps/workbench/app/assets/stylesheets/application.css.scss b/apps/workbench/app/assets/stylesheets/application.css.scss
index 7d76f5a..75080a0 100644
--- a/apps/workbench/app/assets/stylesheets/application.css.scss
+++ b/apps/workbench/app/assets/stylesheets/application.css.scss
@@ -47,6 +47,7 @@ table.table-justforlayout {
     font-size: .8em;
     color: #888;
 }
+.arvados-filename,
 .arvados-uuid {
     font-size: .8em;
     font-family: monospace;
@@ -184,6 +185,7 @@ div#wrapper {
 }
 .arv-description-in-table {
   max-height: 3.5em;
+  overflow-x: hidden;
   overflow-y: hidden;
 }
 .arv-description-in-table:hover {
diff --git a/apps/workbench/app/assets/stylesheets/folders.css.scss b/apps/workbench/app/assets/stylesheets/folders.css.scss
index 163c188..aa5f14c 100644
--- a/apps/workbench/app/assets/stylesheets/folders.css.scss
+++ b/apps/workbench/app/assets/stylesheets/folders.css.scss
@@ -6,3 +6,7 @@
 .arv-folder-list > .row.folder:hover {
     background: #d9edf7;
 }
+div.scroll-20em {
+    height: 20em;
+    overflow-y: scroll;
+}
diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 97ef55a..3ed440f 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -144,7 +144,7 @@ class ApplicationController < ActionController::Base
   end
 
   def update
-    @updates ||= params[@object.class.to_s.underscore.singularize.to_sym]
+    @updates ||= params[@object.resource_param_name.to_sym]
     @updates.keys.each do |attr|
       if @object.send(attr).is_a? Hash
         if @updates[attr].is_a? String
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index 117f808..dc97251 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -212,7 +212,8 @@ module ApplicationHelper
       end
     end
 
-    if !object.attribute_editable?(attr, :ever) or
+    if !object or
+        !object.attribute_editable?(attr, :ever) or
         (!object.editable? and
          !object.owner_uuid.in?(my_folders.collect(&:uuid)))
       return link_to_if_arvados_object attrvalue
@@ -349,6 +350,15 @@ module ApplicationHelper
     end
   end
 
+  def render_controller_partial partial, opts
+    cname = opts.delete :controller_name
+    begin
+      render opts.merge(partial: "#{cname}/#{partial}")
+    rescue ActionView::MissingTemplate
+      render opts.merge(partial: "application/#{partial}")
+    end
+  end
+    
   def fa_icon_class_for_object object
     case object.class.to_s.to_sym
     when :User
@@ -365,6 +375,22 @@ module ApplicationHelper
       'fa-clipboard'
     when :Human
       'fa-male'
+    when :VirtualMachine
+      'fa-terminal'
+    when :Repository
+      'fa-code-fork'
+    when :Link
+      'fa-arrows-h'
+    when :User
+      'fa-user'
+    when :Node
+      'fa-cloud'
+    when :KeepService
+      'fa-exchange'
+    when :KeepDisk
+      'fa-hdd-o'
+    else
+      'fa-cube'
     end
   end
 end
diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index cb45701..e8b4caf 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -348,6 +348,10 @@ class ArvadosBase < ActiveRecord::Base
     resource_class
   end
 
+  def resource_param_name
+    self.class.to_s.underscore
+  end
+
   def friendly_link_name
     (name if self.respond_to? :name) || default_name
   end
@@ -364,6 +368,14 @@ class ArvadosBase < ActiveRecord::Base
     self.to_s.underscore.humanize
   end
 
+  def controller
+    (self.class.to_s.pluralize + 'Controller').constantize
+  end
+
+  def controller_name
+    self.class.to_s.tableize
+  end
+
   # Placeholder for name when name is missing or empty
   def default_name
     if self.respond_to? :name
diff --git a/apps/workbench/app/views/application/_content.html.erb b/apps/workbench/app/views/application/_content.html.erb
index 32c053f..b41da15 100644
--- a/apps/workbench/app/views/application/_content.html.erb
+++ b/apps/workbench/app/views/application/_content.html.erb
@@ -1,3 +1,24 @@
+<% content_for :content_top do %>
+  <% if @object and not @object.is_a?(Group) and @object.class.goes_in_folders? and @object.owner_uuid == current_user.uuid %>
+    <div class="pull-right" style="width: 40%">
+      <div class="alert alert-warning alert-dismissable">
+        <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
+        <strong>Hey.</strong> This <%= @object.class_for_display.downcase %> belongs to your account, but it's not in any of your folders. If you want it to be easy to find in the future, you should move it to a folder.<br />
+        <%= button_to(choose_folders_path(
+                   title: 'Move to...',
+                   editable: true,
+                   action_name: 'Move',
+                   action_href: url_for(action: :update),
+                   action_method: 'patch',
+                   action_data: {selection_param: @object.resource_param_name+'[owner_uuid]', success: 'page-refresh'}.to_json),
+                  { class: "btn btn-primary btn-sm", remote: true, method: 'get' }) do %>
+          <i class="fa fa-fw fa-folder"></i> Choose a folder...
+        <% end %>
+      </div>
+    </div>
+  <% end %>
+<% end %>
+
 <% content_for :tab_panes do %>
 
 <% comparable = controller.respond_to? :compare %>
diff --git a/apps/workbench/app/views/application/_content_layout.html.erb b/apps/workbench/app/views/application/_content_layout.html.erb
index 1bc0b85..426a497 100644
--- a/apps/workbench/app/views/application/_content_layout.html.erb
+++ b/apps/workbench/app/views/application/_content_layout.html.erb
@@ -1,4 +1,5 @@
 <%= content_for :content_top %>
+<br clear="all" />
 <div class="pull-right">
   <%= content_for :tab_line_buttons %>
 </div>
diff --git a/apps/workbench/app/views/application/_show_object_button.html.erb b/apps/workbench/app/views/application/_show_object_button.html.erb
index 157ae49..17e9737 100644
--- a/apps/workbench/app/views/application/_show_object_button.html.erb
+++ b/apps/workbench/app/views/application/_show_object_button.html.erb
@@ -1,3 +1,12 @@
 <% htmloptions = {class: ''}.merge(htmloptions || {})
    htmloptions[:class] += " btn-#{size}" rescue nil %>
-<%= link_to_if_arvados_object object, { link_text: raw('<i class="glyphicon glyphicon-zoom-in"></i>') }, { data: {toggle: 'tooltip', placement: 'top'}, title: 'show', class: 'btn btn-default btn-nodecorate ' + htmloptions[:class] } %>
+<%= link_to_if_arvados_object object, {
+      link_text: raw('<i class="fa fa-fw ' + fa_icon_class_for_object(object) + '"></i>')
+    }, {
+      data: {
+        toggle: 'tooltip',
+        placement: 'top'
+      },
+      title: 'show',
+      class: 'btn btn-default btn-nodecorate ' + htmloptions[:class]
+    } %>
diff --git a/apps/workbench/app/views/application/_show_object_description_cell.html.erb b/apps/workbench/app/views/application/_show_object_description_cell.html.erb
new file mode 100644
index 0000000..7ad3f0e
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_object_description_cell.html.erb
@@ -0,0 +1,2 @@
+<%= object.content_summary %>
+
diff --git a/apps/workbench/app/views/collections/_show_object_description_cell.html.erb b/apps/workbench/app/views/collections/_show_object_description_cell.html.erb
new file mode 100644
index 0000000..0b3352b
--- /dev/null
+++ b/apps/workbench/app/views/collections/_show_object_description_cell.html.erb
@@ -0,0 +1,14 @@
+<div class="nowrap">
+  <div>
+    <% Link.filter([['link_class','=','tag'],['head_uuid','=',object.uuid]]).collect(&:name).each do |tagname| %>
+      <span class="label label-info"><%= tagname %></span>
+    <% end %>
+  </div>
+  <span class="deemphasize">
+    Files (<%= human_readable_bytes_html(object.total_bytes) %>):
+  </span><span class="arvados-filename">
+    <% object.files.each do |path, file, size| %>
+      <%= file %>
+    <% end %>
+  </span>
+</div>
diff --git a/apps/workbench/app/views/folders/_index_folders.html.erb b/apps/workbench/app/views/folders/_index_folders.html.erb
new file mode 100644
index 0000000..734e0f4
--- /dev/null
+++ b/apps/workbench/app/views/folders/_index_folders.html.erb
@@ -0,0 +1,31 @@
+<div class="container-fluid arv-folder-list">
+  <% tree.each do |foldernode| %>
+    <% rowtype = foldernode[:object].class %>
+    <% next if rowtype != Group and !show_root_node %>
+    <div class="<%= 'folder' if rowtype == Group %> row">
+      <div class="col-md-12" style="padding-left: <%= foldernode[:depth] - (show_root_node ? 0 : 1) %>em;">
+        <% if show_root_node and rowtype == String %>
+          <i class="fa fa-fw fa-folder-open-o"></i>
+          <%= foldernode[:object] %>
+        <% elsif show_root_node and rowtype == User %>
+          <% if foldernode[:object].uuid == current_user.andand.uuid %>
+            <i class="fa fa-fw fa-folder-open-o"></i>
+            My Folders
+          <% else %>
+            <i class="fa fa-fw fa-folder-o"></i>
+            <%= foldernode[:object].friendly_link_name %>
+          <% end %>
+        <% elsif rowtype == Group %>
+          <i class="fa fa-fw fa-folder-o"></i>
+          <% opts = {} %>
+          <% opts[:title] = foldernode[:object].description %>
+          <% opts[:'data-toggle'] = 'tooltip' %>
+          <% opts[:'data-placement'] = 'bottom' %>
+          <%= link_to foldernode[:object], opts do %>
+            <%= foldernode[:object].friendly_link_name %>
+          <% end %>
+        <% end %>
+      </div>
+    </div>
+  <% end %>
+</div>
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index ce9f1b1..3a11930 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -67,7 +67,7 @@
   </div>
 </div>
 
-<table class="table table-condensed arv-index arv-folder-contents">
+<table class="table table-condensed table-fixedlayout arv-index arv-folder-contents" style="overflow-x: hidden">
   <colgroup>
     <col width="40%" />
     <col width="60%" />
diff --git a/apps/workbench/app/views/folders/_show_contents_rows.html.erb b/apps/workbench/app/views/folders/_show_contents_rows.html.erb
index c20bf27..54e7ff6 100644
--- a/apps/workbench/app/views/folders/_show_contents_rows.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents_rows.html.erb
@@ -6,21 +6,23 @@
       >
     <td>
       <% if folder.editable? %>
-        <%= link_to({action: 'remove_item', id: folder.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display.downcase} #{name_object.name rescue object.uuid} from this folder?", toggle: 'tooltip', placement: 'top'}, class: 'btn btn-xs btn-default btn-nodecorate', title: 'remove') do %>
+        <%= link_to({action: 'remove_item', id: folder.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display.downcase} #{name_object.name rescue object.uuid} from this folder?", toggle: 'tooltip', placement: 'top'}, class: 'btn btn-sm btn-default btn-nodecorate', title: 'remove') do %>
           <i class="fa fa-fw fa-ban"></i>
         <% end %>
       <% else %>
         <i class="fa fa-fw"></i><%# placeholder %>
       <% end %>
 
-      <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
-
-      <i class="fa fa-fw <%= fa_icon_class_for_object(object) %>"></i>
+      <%= render :partial => "show_object_button", :locals => {object: object, size: 'sm'} %>
 
       <%= render_editable_attribute name_object, 'name', nil %>
     </td>
-    <td>
-      <%= object.content_summary %>
+    <td class="arv-description-in-table">
+      <%= render_controller_partial(
+          'show_object_description_cell.html',
+          controller_name: object.controller_name,
+          locals: {object: object})
+          %>
     </td>
   </tr>
 <% end %>
diff --git a/apps/workbench/app/views/folders/_show_folders.html.erb b/apps/workbench/app/views/folders/_show_folders.html.erb
deleted file mode 100644
index 8c4f0d8..0000000
--- a/apps/workbench/app/views/folders/_show_folders.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-<div class="container-fluid arv-folder-list">
-  <% [@my_folder_tree, @shared_folder_tree].each do |tree| %>
-    <% tree.each do |foldernode| %>
-      <% rowtype = foldernode[:object].class %>
-      <div class="<%= 'folder' if rowtype == Group %> row">
-        <div class="col-lg-4" style="padding-left: <%= 1 + foldernode[:depth] %>em;">
-          <% if rowtype == String %>
-            <i class="fa fa-fw fa-folder-open-o"></i>
-            <%= foldernode[:object] %>
-          <% elsif rowtype == User %>
-            <% if foldernode[:object].uuid == current_user.andand.uuid %>
-              <i class="fa fa-fw fa-folder-open-o"></i>
-              My Folders
-            <% else %>
-              <i class="fa fa-fw fa-folder-o"></i>
-              <%= foldernode[:object].friendly_link_name %>
-            <% end %>
-          <% else %>
-            <i class="fa fa-fw fa-folder-o"></i>
-            <%= link_to foldernode[:object] do %>
-              <%= foldernode[:object].friendly_link_name %>
-            <% end %>
-          <% end %>
-        </div>
-        <div class="col-lg-8 arv-description-in-table">
-          <% if rowtype == Group %>
-            <%= foldernode[:object].description %>
-          <% end %>
-        </div>
-      </div>
-    <% end %>
-  <% end %>
-</div>
diff --git a/apps/workbench/app/views/folders/index.html.erb b/apps/workbench/app/views/folders/index.html.erb
new file mode 100644
index 0000000..7666e54
--- /dev/null
+++ b/apps/workbench/app/views/folders/index.html.erb
@@ -0,0 +1,57 @@
+<% content_for :breadcrumbs do %>
+<li class="nav-separator"><span class="glyphicon glyphicon-arrow-right"></span></li>
+<li><a href="#">Home</a></li>
+<% end %>
+
+<div class="container-fluid">
+  <div class="row">
+    <div class="col-sm-6">
+      <% if my_folders.empty? %>
+        <div class="panel panel-info">
+          <div class="panel-heading">
+            <h3 class="panel-title">
+              Welcome to <b><%= Rails.configuration.site_name %></b>.
+            </h3>
+          </div>
+          <div class="panel-body">
+            <img src="/favicon.ico" class="pull-right" alt="" style="opacity: 0.3"/>
+            <p>
+              This site runs Arvados, the open source biomedical analysis platform. <a href="https://arvados.org" target="_blank">Learn more…</a>
+            </p>
+            <p>
+              <b>To get started,</b> create a folder using the "Add new folder" button below.
+            </p>
+          </div>
+        </div>
+      <% end %>
+      <div class="panel panel-default">
+        <div class="panel-heading">
+          <div class="pull-right">
+            <%= button_to folders_path(method: 'post'), class: 'btn btn-xs btn-primary' do %>
+              <i class="fa fa-fw fa-plus"></i>
+              Add new folder
+            <% end %>
+          </div>
+          <h3 class="panel-title">
+            My folders
+          </h3>
+        </div>
+        <div class="panel-body scroll-20em">
+          <%= render partial: 'index_folders', locals: {tree: @my_folder_tree, show_root_node: false} %>
+        </div>
+      </div>
+    </div>
+    <div class="col-sm-6">
+      <div class="panel panel-default">
+        <div class="panel-heading">
+          <h3 class="panel-title">
+            Shared folders
+          </h3>
+        </div>
+        <div class="panel-body scroll-20em">
+          <%= render partial: 'index_folders', locals: {tree: @shared_folder_tree, show_root_node: false} %>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/apps/workbench/app/views/layouts/application.html.erb b/apps/workbench/app/views/layouts/application.html.erb
index 0ec08cc..631595f 100644
--- a/apps/workbench/app/views/layouts/application.html.erb
+++ b/apps/workbench/app/views/layouts/application.html.erb
@@ -167,7 +167,10 @@
                 <span class="glyphicon glyphicon-cog"></span><span class="caret"></span>
               </a>
               <ul class="dropdown-menu" role="menu">
-                <li role="presentation" class="dropdown-header">System objects</li>
+                <li role="presentation" class="dropdown-header">
+                  <i class="fa fa-lg fa-fw"></i>
+                  System tools
+                </li>
                 <li role="presentation" class="divider"></li>
                 <li role="presentation"><a href="/repositories">
                     <i class="fa fa-lg fa-code-fork fa-fw"></i> Repositories
diff --git a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
index b08e0b8..b8f94d5 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
@@ -9,10 +9,9 @@
     <%= render_editable_attribute @object, 'name', nil %>
   </h2>
   <% if template %>
-  <h4>
-    From template:
+  <blockquote><span class="deemphasize">From template:</span><br />
     <%= link_to_if_arvados_object template, friendly_name: true %>
-  </h4>
+  </blockquote>
   <% end %>
 <% end %>
 

commit 1b981c1ca2e3d4d5aa6841fe2b334a19cc11f4f5
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 14:31:48 2014 -0400

    2872: Add "delete folder" button.

diff --git a/apps/workbench/app/views/application/_content_layout.html.erb b/apps/workbench/app/views/application/_content_layout.html.erb
index c7ff33b..1bc0b85 100644
--- a/apps/workbench/app/views/application/_content_layout.html.erb
+++ b/apps/workbench/app/views/application/_content_layout.html.erb
@@ -1,3 +1,5 @@
 <%= content_for :content_top %>
-<%= content_for :tab_line_buttons %>
+<div class="pull-right">
+  <%= content_for :tab_line_buttons %>
+</div>
 <%= content_for :tab_panes %>
diff --git a/apps/workbench/app/views/application/_delete_object_button.html.erb b/apps/workbench/app/views/application/_delete_object_button.html.erb
index 69ed9dc..6d6383e 100644
--- a/apps/workbench/app/views/application/_delete_object_button.html.erb
+++ b/apps/workbench/app/views/application/_delete_object_button.html.erb
@@ -1,5 +1,5 @@
 <% if object.editable? %>
-  <%= link_to({action: 'destroy', id: object.uuid}, method: :delete, remote: true, data: {confirm: "You are about to delete #{object.class_for_display.downcase} '#{object.friendly_link_name}' (#{object.uuid}).\n\nAre you sure?"}) do %>
+  <%= link_to({action: 'destroy', id: object.uuid}, method: :delete, remote: true, data: {confirm: "Really delete #{object.class_for_display.downcase} '#{object.friendly_link_name}'?"}) do %>
     <i class="glyphicon glyphicon-trash"></i>
   <% end %>
 <% end %>
diff --git a/apps/workbench/app/views/application/index.html.erb b/apps/workbench/app/views/application/index.html.erb
index 20af648..0e72f7a 100644
--- a/apps/workbench/app/views/application/index.html.erb
+++ b/apps/workbench/app/views/application/index.html.erb
@@ -7,14 +7,18 @@
   <% if controller.model_class.creatable? %>
 
     <% if controller.model_class.name == 'User' %>
-      <%= link_to "Add a new #{controller.model_class.to_s.underscore.gsub '_', ' '}", setup_user_popup_path,
-        {class: 'btn btn-primary pull-right', :remote => true, 'data-toggle' =>  "modal",
-          'data-target' => '#user-setup-modal-window', return_to: request.url}  %>
+      <%= link_to setup_user_popup_path,
+        {class: 'btn btn-sm btn-primary', :remote => true, 'data-toggle' =>  "modal",
+          'data-target' => '#user-setup-modal-window', return_to: request.url} do %>
+        <i class="fa fa-fw fa-plus"></i> Add a new user
+      <% end %>
       <div id="user-setup-modal-window" class="modal fade" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"></div>
     <% else %>
-      <%= button_to "Add a new #{controller.controller_name.singularize.humanize.downcase}",
-        { action: 'create' },
-        { class: 'btn btn-primary pull-right' } %>
+      <%= button_to({action: 'create'}, {class: 'btn btn-sm btn-primary'}) do %>
+        <i class="fa fa-fw fa-plus"></i>
+        Add a new
+        <%= controller.controller_name.singularize.humanize.downcase %>
+      <% end %>
     <% end %>
 
   <% end %>
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index 63b6abc..ce9f1b1 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -10,6 +10,14 @@
 
 <% end %>
 
+<% content_for :tab_line_buttons do %>
+  <% if @objects_and_names.empty? %>
+    <%= button_to(folder_path(id: @object.uuid, return_to: folders_path), method: 'delete', class: 'btn btn-sm btn-primary', data: {confirm: "Really delete folder '#{@object.name}'?"}) do %>
+      <i class="fa fa-fw fa-trash-o"></i> Delete folder
+    <% end %>
+  <% end %>
+<% end %>
+
 <div class="container-fluid">
   <div class="row">
     <div class="col-md-4">

commit 5758bd5c9ee5a253c695431f98d9e95b843e798e
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 14:11:41 2014 -0400

    2872: Fix "remove from folder"

diff --git a/apps/workbench/app/controllers/folders_controller.rb b/apps/workbench/app/controllers/folders_controller.rb
index eae92ba..b7b4854 100644
--- a/apps/workbench/app/controllers/folders_controller.rb
+++ b/apps/workbench/app/controllers/folders_controller.rb
@@ -36,7 +36,7 @@ class FoldersController < ApplicationController
     if item.owner_uuid == @object.uuid
       # Object is owned by this folder. Remove it from the folder by
       # changing owner to the current user.
-      item.update_attributes owner_uuid: current_user
+      item.update_attributes owner_uuid: current_user.uuid
       @removed_uuids << item.uuid
     end
   end

commit 605522fc29649de26b7038e73339ffb35d12768e
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 14:04:18 2014 -0400

    2872: Make editable work for names in folder, choose data from current folder, tweak css.

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index e839dd1..97ef55a 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -452,4 +452,30 @@ class ApplicationController < ActionController::Base
       @notification_count = ''
     end
   end
+
+  helper_method :my_folders
+  def my_folders
+    return @my_folders if @my_folders
+    @my_folders = []
+    root_of = {}
+    Group.filter([['group_class','=','folder']]).each do |g|
+      root_of[g.uuid] = g.owner_uuid
+      @my_folders << g
+    end
+    done = false
+    while not done
+      done = true
+      root_of = root_of.each_with_object({}) do |(child, parent), h|
+        if root_of[parent]
+          h[child] = root_of[parent]
+          done = false
+        else
+          h[child] = parent
+        end
+      end
+    end
+    @my_folders = @my_folders.select do |g|
+      root_of[g.uuid] == current_user.uuid
+    end
+  end
 end
diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index ece8ccc..4ba23c5 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -41,11 +41,11 @@ class CollectionsController < ApplicationController
   end
 
   def choose
-    @name_links = Link.
+    @objects = Link.
       filter([['link_class','=','name'],
               ['head_uuid','is_a','arvados#collection']])
-    @name_links.collect { |x| x }
-    $stderr.puts @name_links.inspect
+    find_objects_for_index
+    @name_links = @objects
     @objects = Collection.
       filter([['uuid','in', at name_links.collect(&:head_uuid)]])
     super
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index 4749e0e..117f808 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -134,7 +134,11 @@ module ApplicationHelper
 
   def render_editable_attribute(object, attr, attrvalue=nil, htmloptions={})
     attrvalue = object.send(attr) if attrvalue.nil?
-    return attrvalue if !object.attribute_editable? attr
+    if !object.attribute_editable?(attr, :ever) or
+        (!object.editable? and
+         !object.owner_uuid.in?(my_folders.collect(&:uuid)))
+      return attrvalue 
+    end
 
     input_type = 'text'
     case object.class.attribute_info[attr.to_sym].andand[:type]
@@ -208,7 +212,9 @@ module ApplicationHelper
       end
     end
 
-    unless object.andand.attribute_editable? attr
+    if !object.attribute_editable?(attr, :ever) or
+        (!object.editable? and
+         !object.owner_uuid.in?(my_folders.collect(&:uuid)))
       return link_to_if_arvados_object attrvalue
     end
 
@@ -242,6 +248,7 @@ module ApplicationHelper
       end
       modal_path = choose_collections_path \
       ({ title: 'Choose a dataset:',
+         filters: [['owner_uuid', '=', object.owner_uuid]].to_json,
          action_name: 'OK',
          action_href: pipeline_instance_path(id: object.uuid),
          action_method: 'patch',
diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index a4f12d3..cb45701 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -305,13 +305,15 @@ class ArvadosBase < ActiveRecord::Base
       (writable_by.include? current_user.uuid rescue false)))
   end
 
-  def attribute_editable?(attr)
+  def attribute_editable?(attr, ever=nil)
     if "created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at".index(attr.to_s)
       false
     elsif not (current_user.andand.is_active)
       false
     elsif attr == 'uuid'
       current_user.is_admin
+    elsif ever
+      true
     else
       editable?
     end
diff --git a/apps/workbench/app/models/pipeline_instance.rb b/apps/workbench/app/models/pipeline_instance.rb
index beeba62..3e9eda2 100644
--- a/apps/workbench/app/models/pipeline_instance.rb
+++ b/apps/workbench/app/models/pipeline_instance.rb
@@ -29,9 +29,10 @@ class PipelineInstance < ArvadosBase
     end
   end
   
-  def attribute_editable?(attr)
-    attr && (attr.to_sym == :name ||
-            (attr.to_sym == :components and (self.state == 'New' || self.state == 'Ready')))
+  def attribute_editable? attr, *args
+    super(attr, *args) && (attr.to_sym == :name ||
+                           (attr.to_sym == :components and
+                            (self.state == 'New' || self.state == 'Ready')))
   end
 
   def attributes_for_display
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index ecfd405..63b6abc 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -12,7 +12,7 @@
 
 <div class="container-fluid">
   <div class="row">
-    <div class="col-lg-4">
+    <div class="col-md-4">
       <% if @object.editable? %>
         <%= link_to(
               choose_collections_path(
@@ -37,14 +37,14 @@
         <% end %>
       <% end %>
     </div>
-    <div class="col-lg-4">
+    <div class="col-md-4">
       <form class="form-inline" role="form">
         Show:
         <select class="form-control" data-filter-rows-by="data-kind" data-filter-target="table.arv-index.arv-folder-contents tbody">
           <option value="">Everything</option>
           <option value="arvados#collection">Data</option>
-          <option value="arvados#pipeline_instance arvados#job">Compute jobs</option>
-          <option value="arvados#pipeline_template">Pipelines</option>
+          <option value="arvados#pipelineInstance arvados#job">Compute jobs</option>
+          <option value="arvados#pipelineTemplate">Pipelines</option>
           <!--
           <option value="arvados#specimen">Specimens</option>
           <option value="arvados#human">Humans</option>
@@ -53,7 +53,7 @@
         </select>
       </form>
     </div>
-    <div class="col-lg-4">
+    <div class="col-md-4">
       <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents" data-search-target=".arv-index.arv-folder-contents"/>
     </div>
   </div>
diff --git a/apps/workbench/app/views/folders/_show_permissions.html.erb b/apps/workbench/app/views/folders/_show_permissions.html.erb
index 41a7cd7..262cb3b 100644
--- a/apps/workbench/app/views/folders/_show_permissions.html.erb
+++ b/apps/workbench/app/views/folders/_show_permissions.html.erb
@@ -1,6 +1,6 @@
 <div class="container-fluid">
   <div class="row">
-    <div class="col-lg-6">
+    <div class="col-md-6">
       <div class="panel panel-default">
         <div class="panel-heading">
           Additional permissions
@@ -19,7 +19,7 @@
         </div>
       </div>
     </div>
-    <div class="col-lg-6">
+    <div class="col-md-6">
       <% if @object.owner %>
         <div class="panel panel-default">
           <div class="panel-heading">

commit 1b79dc4a25091e035a1c02693ecfcb8453649c27
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 05:45:40 2014 -0400

    2872: Rearrange standard views to deemphasize "advanced" usage, add infinite scroll

diff --git a/apps/workbench/app/assets/javascripts/folders.js b/apps/workbench/app/assets/javascripts/folders.js
index ff1c7b8..73dcfbb 100644
--- a/apps/workbench/app/assets/javascripts/folders.js
+++ b/apps/workbench/app/assets/javascripts/folders.js
@@ -1,20 +1,42 @@
 $(document).
     on('paste keyup change', 'input.search-folder-contents', function() {
         var q = new RegExp($(this).val(), 'i');
-        $(this).closest('div.panel').find('tbody tr').each(function() {
-            $(this).toggle(!!$(this).text().match(q));
-        });
+        $($(this).attr('data-search-target')).find('tbody').
+            data('q', q).
+            trigger('refresh');
+    }).on('refresh', 'tbody', function() {
+        var q = $(this).data('q');
+        var filters = $(this).data('filters');
+        $('tr', this).hide();
+        $('tr', this).filter(function() {
+            var $row = $(this);
+            var pass = true;
+            if (q && !$row.text().match(q))
+                return false;
+            if (filters) {
+                $.each(filters, function(filterby, val) {
+                    if (!val) return;
+                    if (!pass) return;
+                    pass = false;
+                    $.each(val.split(" "), function(i, e) {
+                        if ($row.attr(filterby) == e)
+                            pass = true;
+                    });
+                });
+            }
+            return pass;
+        }).show();
+        $('.infinite-scroller').trigger('scroll');
     }).on('change', 'select[data-filter-rows-by]', function() {
         var val = $(this).val();
         var filterby = $(this).attr('data-filter-rows-by');
-        var $target = $($(this).attr('data-filter-in'));
-        if (val == '') {
-            $target.find('.filterable').show();
-        } else {
-            $target.find('.filterable').hide();
-            console.log('.filterable[' + filterby + '="' + val + '"]');
-            $.each(val.split(" "), function(i, e) {
-                $target.find('.filterable['+filterby+'="'+e+'"]').show();
-            });
-        }
+        var $target = $($(this).attr('data-filter-target'));
+        var filters = $target.data('filters') || {};
+        filters[filterby] = val;
+        $target.
+            data('filters', filters).
+            trigger('refresh');
+    }).on('ajax:complete', function() {
+        $('input.search-folder-contents').trigger('change');
+        $('select[data-filter-rows-by]').trigger('change');
     });
diff --git a/apps/workbench/app/assets/javascripts/infinite_scroll.js b/apps/workbench/app/assets/javascripts/infinite_scroll.js
new file mode 100644
index 0000000..48b8136
--- /dev/null
+++ b/apps/workbench/app/assets/javascripts/infinite_scroll.js
@@ -0,0 +1,47 @@
+function maybe_load_more_content() {
+    var scroller = this;        // element with scroll bars
+    var container;              // element that receives new content
+    var src;                    // url for retrieving content
+    if ($(scroller).scrollTop() + $(scroller).height()
+        >
+        scroller.scrollHeight - 50) {
+        container = $(this).data('infinite-container');
+        src = $(container).attr('data-infinite-content-href');
+        if (!src)
+            // Finished
+            return;
+        // Don't start another request until this one finishes
+        $(container).attr('data-infinite-content-href', null);
+        $.ajax(src,
+               {dataType: 'json',
+                type: 'GET',
+                data: {},
+                context: {container: container, src: src}}).
+            fail(function(jqxhr, status, error) {
+                if (jqxhr.readyState == 0 || jqxhr.status == 0) {
+                    message = "Cancelled."
+                } else if (jqxhr.responseJSON && jqxhr.responseJSON.errors) {
+                    message = jqxhr.responseJSON.errors.join("; ");
+                } else {
+                    message = "Request failed.";
+                }
+                // TODO: report this to the user.
+                console.log(message);
+                $(this.container).attr('data-infinite-content-href', this.src);
+            }).
+            done(function(data, status, jqxhr) {
+                $(this.container).append(data.content);
+                $(this.container).attr('data-infinite-content-href', data.next_page_href);
+                $(document).trigger('ajax:complete');
+            });
+    }
+}
+$(document).
+    on('ready ajax:complete', function() {
+        $('[data-infinite-scroller]').each(function() {
+            $($(this).attr('data-infinite-scroller')).
+                addClass('infinite-scroller').
+                data('infinite-container', this).
+                on('scroll', maybe_load_more_content);
+        });
+    });
diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 4aa79fb..e839dd1 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -88,6 +88,20 @@ class ApplicationController < ActionController::Base
     @objects = @objects.filter(@filters).limit(@limit).offset(@offset)
   end
 
+  helper_method :next_page_offset
+  def next_page_offset
+    if @objects.respond_to?(:result_offset) and
+        @objects.respond_to?(:result_limit) and
+        @objects.respond_to?(:items_available)
+      next_offset = @objects.result_offset + @objects.result_limit
+      if next_offset < @objects.items_available
+        next_offset
+      else
+        nil
+      end
+    end
+  end
+
   def index
     find_objects_for_index if !@objects
     respond_to do |f|
@@ -115,7 +129,7 @@ class ApplicationController < ActionController::Base
   end
 
   def choose
-    find_objects_for_index
+    find_objects_for_index if !@objects
     render partial: 'choose', locals: {multiple: params[:multiple]}
   end
 
@@ -198,7 +212,7 @@ class ApplicationController < ActionController::Base
   end
 
   def show_pane_list
-    %w(Attributes Metadata Advanced)
+    %w(Attributes Advanced)
   end
 
   protected
diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index 9371bd1..ece8ccc 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -7,7 +7,7 @@ class CollectionsController < ApplicationController
   RELATION_LIMIT = 5
 
   def show_pane_list
-    %w(Files Attributes Metadata Provenance_graph Used_by JSON API)
+    %w(Files Provenance_graph Used_by Advanced)
   end
 
   def set_persistent
@@ -44,6 +44,8 @@ class CollectionsController < ApplicationController
     @name_links = Link.
       filter([['link_class','=','name'],
               ['head_uuid','is_a','arvados#collection']])
+    @name_links.collect { |x| x }
+    $stderr.puts @name_links.inspect
     @objects = Collection.
       filter([['uuid','in', at name_links.collect(&:head_uuid)]])
     super
diff --git a/apps/workbench/app/controllers/folders_controller.rb b/apps/workbench/app/controllers/folders_controller.rb
index 73e24bc..eae92ba 100644
--- a/apps/workbench/app/controllers/folders_controller.rb
+++ b/apps/workbench/app/controllers/folders_controller.rb
@@ -8,7 +8,7 @@ class FoldersController < ApplicationController
   end
 
   def show_pane_list
-    %w(Contents Permissions)
+    %w(Contents Permissions Advanced)
   end
 
   def remove_item
@@ -82,7 +82,8 @@ class FoldersController < ApplicationController
   end
 
   def show
-    @objects = @object.contents include_linked: true
+    @objects = @object.contents(include_linked: true,
+                                offset: params[:offset] || 0)
     @share_links = Link.filter([['head_uuid', '=', @object.uuid],
                                 ['link_class', '=', 'permission']])
     @logs = Log.limit(10).filter([['object_uuid', '=', @object.uuid]])
@@ -95,13 +96,31 @@ class FoldersController < ApplicationController
         end
       else
         @objects_and_names << [object,
-                               Link.new(tail_uuid: @object.uuid,
+                               Link.new(owner_uuid: @object.uuid,
+                                        tail_uuid: @object.uuid,
                                         head_uuid: object.uuid,
                                         link_class: "name",
                                         name: "")]
       end
     end
-    super
+    if params[:partial]
+      respond_to do |f|
+        f.json {
+          render json: {
+            content: render_to_string(partial: 'show_contents_rows.html',
+                                      formats: [:html],
+                                      locals: {
+                                        objects_and_names: @objects_and_names,
+                                        folder: @object
+                                      }),
+            next_page_href: (next_page_offset and
+                             url_for(offset: next_page_offset, partial: true))
+          }
+        }
+      end
+    else
+      super
+    end
   end
 
   def create
diff --git a/apps/workbench/app/controllers/pipeline_templates_controller.rb b/apps/workbench/app/controllers/pipeline_templates_controller.rb
index afe41c4..2be51c6 100644
--- a/apps/workbench/app/controllers/pipeline_templates_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_templates_controller.rb
@@ -6,6 +6,6 @@ class PipelineTemplatesController < ApplicationController
   end
 
   def show_pane_list
-    %w(Components Pipelines Attributes Metadata JSON API)
+    %w(Components Pipelines Advanced)
   end
 end
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index a463a50..4749e0e 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -161,7 +161,7 @@ module ApplicationHelper
       ajax_options['data-pk'][:defaults] = object.attributes
     end
     ajax_options['data-pk'] = ajax_options['data-pk'].to_json
-    @unique_id ||= 0
+    @unique_id ||= (Time.now.to_f*1000000).to_i
     span_id = object.uuid.to_s + '-' + attr.to_s + '-' + (@unique_id += 1).to_s
 
     span_tag = content_tag 'span', attrvalue.to_s, {
diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index a6aded9..a4f12d3 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -364,7 +364,11 @@ class ArvadosBase < ActiveRecord::Base
 
   # Placeholder for name when name is missing or empty
   def default_name
-    "New #{class_for_display.downcase}"
+    if self.respond_to? :name
+      "New #{class_for_display.downcase}"
+    else
+      uuid
+    end
   end
 
   def owner
diff --git a/apps/workbench/app/models/collection.rb b/apps/workbench/app/models/collection.rb
index 90e53e8..ae86108 100644
--- a/apps/workbench/app/models/collection.rb
+++ b/apps/workbench/app/models/collection.rb
@@ -25,6 +25,7 @@ class Collection < ArvadosBase
   end
 
   def files_tree
+    return [] if files.empty?
     tree = files.group_by { |file_spec| File.split(file_spec.first) }
     # Fill in entries for empty directories.
     tree.keys.map { |basedir, _| File.split(basedir) }.each do |splitdir|
diff --git a/apps/workbench/app/models/job.rb b/apps/workbench/app/models/job.rb
index 56428ab..6fe3743 100644
--- a/apps/workbench/app/models/job.rb
+++ b/apps/workbench/app/models/job.rb
@@ -10,4 +10,19 @@ class Job < ArvadosBase
   def self.creatable?
     false
   end
+
+  def default_name
+    if script
+      x = "\"#{script}\" job"
+    else
+      x = super
+    end
+    if finished_at
+      x += " finished #{finished_at.strftime('%b %-d')}"
+    elsif started_at
+      x += " started #{started_at.strftime('%b %-d')}"
+    elsif created_at
+      x += " submitted #{created_at.strftime('%b %-d')}"
+    end
+  end
 end
diff --git a/apps/workbench/app/models/link.rb b/apps/workbench/app/models/link.rb
index 5e7b42a..868082b 100644
--- a/apps/workbench/app/models/link.rb
+++ b/apps/workbench/app/models/link.rb
@@ -4,4 +4,8 @@ class Link < ArvadosBase
   def self.by_tail(t, opts={})
     where(opts.merge :tail_uuid => t.uuid)
   end
+
+  def default_name
+    self.class.resource_class_for_uuid(head_uuid).default_name rescue super
+  end
 end
diff --git a/apps/workbench/app/views/application/_arvados_attr_value.html.erb b/apps/workbench/app/views/application/_arvados_attr_value.html.erb
index 3efca72..8f82b04 100644
--- a/apps/workbench/app/views/application/_arvados_attr_value.html.erb
+++ b/apps/workbench/app/views/application/_arvados_attr_value.html.erb
@@ -3,7 +3,7 @@
     <%= message %><br />
   <% end %>
 <% else %>
-      <% if obj.attribute_editable?(attr) %>
+      <% if obj.attribute_editable?(attr) and (!defined?(editable) || editable) %>
         <%= render_editable_attribute obj, attr %>
         <% if resource_class_for_uuid(attrvalue, {referring_object: obj, referring_attr: attr}) %>
 	<br />
diff --git a/apps/workbench/app/views/application/_content.html.erb b/apps/workbench/app/views/application/_content.html.erb
index 8a0624b..32c053f 100644
--- a/apps/workbench/app/views/application/_content.html.erb
+++ b/apps/workbench/app/views/application/_content.html.erb
@@ -15,7 +15,7 @@
 <div class="tab-content">
 <% panes.each_with_index do |(pane, content), i| %>
   <div id="<%= pane %>" class="tab-pane fade <%= 'in active' if i==0 %>">
-    <div class="smart-scroll" style="margin-top:0.5em;">
+    <div id="<%= pane %>-scroll" class="smart-scroll" style="margin-top:0.5em;">
       <%= content %>
     </div>
   </div>
diff --git a/apps/workbench/app/views/application/_show_advanced.html.erb b/apps/workbench/app/views/application/_show_advanced.html.erb
index d31b5f5..e8474f6 100644
--- a/apps/workbench/app/views/application/_show_advanced.html.erb
+++ b/apps/workbench/app/views/application/_show_advanced.html.erb
@@ -1,5 +1,6 @@
 <div class="panel-group" id="arv-adv-accordion">
-  <% ['API response',
+  <% ['Metadata',
+     'API response',
      'Python example',
      'CLI example',
      'curl example'].each do |section| %>
diff --git a/apps/workbench/app/views/application/_show_advanced_metadata.html.erb b/apps/workbench/app/views/application/_show_advanced_metadata.html.erb
new file mode 100644
index 0000000..68e4298
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced_metadata.html.erb
@@ -0,0 +1,44 @@
+<% outgoing = Link.where(tail_uuid: @object.uuid) %>
+<% incoming = Link.where(head_uuid: @object.uuid) %>
+
+<% if (outgoing | incoming).any? %>
+<table class="table topalign">
+  <colgroup>
+    <col width="20%" />
+    <col width="10%" />
+    <col width="10%" />
+    <col width="20%" />
+    <col width="20%" />
+    <col width="20%" />
+  </colgroup>
+  <thead>
+    <tr>
+      <th></th>
+      <th>link_class</th>
+      <th>name</th>
+      <th>tail</th>
+      <th>head</th>
+      <th>properties</th>
+    </tr>
+  </thead>
+  <tbody>
+    <% (outgoing | incoming).each do |link| %>
+      <tr>
+        <td>
+          <%= render partial: 'show_object_button', locals: { object: link, size: 'xs' } %>
+          <span class="arvados-uuid"><%= link.uuid %></span>
+        </td>
+        <td><%= link.link_class %></td>
+        <td><%= link.name %></td>
+        <td><%= link.tail_uuid == object.uuid ? 'this' : (render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "tail_uuid", attrvalue: link.tail_uuid, editable: false }) %></td>
+        <td><%= link.head_uuid == object.uuid ? 'this' : (render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "head_uuid", attrvalue: link.head_uuid, editable: false }) %></td>
+        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "properties", attrvalue: link.properties, editable: false } %></td>
+      </tr>
+    <% end %>
+  </tbody>
+</table>
+<% else %>
+<span class="deemphasize">
+  (No metadata links found)
+</span>
+<% end %>
diff --git a/apps/workbench/app/views/application/_show_metadata.html.erb b/apps/workbench/app/views/application/_show_metadata.html.erb
deleted file mode 100644
index 551806f..0000000
--- a/apps/workbench/app/views/application/_show_metadata.html.erb
+++ /dev/null
@@ -1,58 +0,0 @@
-<% outgoing = Link.where(tail_uuid: @object.uuid) %>
-<% incoming = Link.where(head_uuid: @object.uuid) %>
-
-<h3>Metadata about this object</h3>
-<% if outgoing.items_available > 0 %>
-<table class="table topalign">
-  <thead>
-    <tr>
-      <th>metadata uuid</th>
-      <th>class</th>
-      <th>name</th>
-      <th>properties</th>
-      <th>object</th>
-    </tr>
-  </thead>
-  <tbody>
-    <% outgoing.each do |link| %>
-      <tr>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "uuid", attrvalue: link.uuid } %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "link_class", attrvalue: link.link_class } %></td>
-        <td><%= render_editable_attribute link, 'name' %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "properties", attrvalue: link.properties } %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "head_uuid", attrvalue: link.head_uuid } %></td>
-      </tr>
-    <% end %>
-  </tbody>
-</table>
-<% else %>
-No metadata.
-<% end %>
-
-<h3>Metadata that refers to this object</h3>
-<% if incoming.items_available > 0 %>
-<table class="table topalign">
-  <thead>
-    <tr>
-      <th>metadata uuid</th>
-      <th>subject</th>
-      <th>class</th>
-      <th>name</th>
-      <th>properties</th>
-    </tr>
-  </thead>
-  <tbody>
-    <% incoming.each do |link| %>
-      <tr>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "uuid", attrvalue: link.uuid } %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "tail_uuid", attrvalue: link.tail_uuid } %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "link_class", attrvalue: link.link_class } %></td>
-        <td><%= render_editable_attribute link, 'name' %></td>
-        <td><%= render partial: 'application/arvados_attr_value', locals: { obj: link, attr: "properties", attrvalue: link.properties } %></td>
-      </tr>
-    <% end %>
-  </tbody>
-</table>
-<% else %>
-No metadata.
-<% end %>
diff --git a/apps/workbench/app/views/collections/show.html.erb b/apps/workbench/app/views/collections/show.html.erb
index 440d2ff..16497c7 100644
--- a/apps/workbench/app/views/collections/show.html.erb
+++ b/apps/workbench/app/views/collections/show.html.erb
@@ -13,19 +13,19 @@
         <% end %>
 
         <% if @output_of.andand.any? %>
-          <p>Output of jobs:<br />
+          <p>This collection was the output of:<br />
           <%= render_arvados_object_list_start(@output_of, 'Show all jobs',
                 jobs_path(filter: [['output', '=', @object.uuid]].to_json)) do |job| %>
-          <%= link_to_if_arvados_object(job, friendly_name: true) %><br />
+            <%= link_to_if_arvados_object(job, friendly_name: true) %><br />
           <% end %>
           </p>
         <% end %>
 
         <% if @log_of.andand.any? %>
-          <p>Log of jobs:<br />
+          <p>This collection contains log messages from:<br />
           <%= render_arvados_object_list_start(@log_of, 'Show all jobs',
                 jobs_path(filter: [['log', '=', @object.uuid]].to_json)) do |job| %>
-          <%= link_to_if_arvados_object(job, friendly_name: true) %><br />
+            <%= link_to_if_arvados_object(job, friendly_name: true) %><br />
           <% end %>
           </p>
         <% end %>
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index d880e01..ecfd405 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -13,32 +13,34 @@
 <div class="container-fluid">
   <div class="row">
     <div class="col-lg-4">
-      <%= link_to(
-            choose_collections_path(
-              title: 'Add data to folder:',
-              multiple: true,
-              action_name: 'Add',
-              action_href: actions_path(id: @object.uuid),
-              action_method: 'post',
-              action_data: {selection_param: 'selection[]', copy_selections_into_folder: @object.uuid, success: 'page-refresh'}.to_json),
-            { class: "btn btn-primary btn-sm", remote: true, method: 'get', data: {'event-after-select' => 'page-refresh'} }) do %>
-        <i class="fa fa-fw fa-plus"></i> Add data
-      <% end %>
-      <%= link_to(
-            choose_pipeline_templates_path(
-              title: 'Choose a pipeline to run:',
-              action_name: 'Configure...',
-              action_href: pipeline_instances_path,
-              action_method: 'post',
-              action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
-            { class: "btn btn-primary btn-sm", remote: true, method: 'get' }) do %>
-        <i class="fa fa-fw fa-gear"></i> Run a pipeline
+      <% if @object.editable? %>
+        <%= link_to(
+              choose_collections_path(
+                title: 'Add data to folder:',
+                multiple: true,
+                action_name: 'Add',
+                action_href: actions_path(id: @object.uuid),
+                action_method: 'post',
+                action_data: {selection_param: 'selection[]', copy_selections_into_folder: @object.uuid, success: 'page-refresh'}.to_json),
+              { class: "btn btn-primary btn-sm", remote: true, method: 'get', data: {'event-after-select' => 'page-refresh'} }) do %>
+          <i class="fa fa-fw fa-plus"></i> Add data
+        <% end %>
+        <%= link_to(
+              choose_pipeline_templates_path(
+                title: 'Choose a pipeline to run:',
+                action_name: 'Configure...',
+                action_href: pipeline_instances_path,
+                action_method: 'post',
+                action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
+              { class: "btn btn-primary btn-sm", remote: true, method: 'get' }) do %>
+          <i class="fa fa-fw fa-gear"></i> Run a pipeline
+        <% end %>
       <% end %>
     </div>
     <div class="col-lg-4">
       <form class="form-inline" role="form">
         Show:
-        <select class="form-control" data-filter-rows-by="data-kind" data-filter-in="table.arv-index.arv-folder-contents">
+        <select class="form-control" data-filter-rows-by="data-kind" data-filter-target="table.arv-index.arv-folder-contents tbody">
           <option value="">Everything</option>
           <option value="arvados#collection">Data</option>
           <option value="arvados#pipeline_instance arvados#job">Compute jobs</option>
@@ -52,43 +54,18 @@
       </form>
     </div>
     <div class="col-lg-4">
-      <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents"/>
+      <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents" data-search-target=".arv-index.arv-folder-contents"/>
     </div>
   </div>
 </div>
 
 <table class="table table-condensed arv-index arv-folder-contents">
-  <tbody>
-    <colgroup>
-      <col width="40%" />
-      <col width="60%" />
-    </colgroup>
-    <% @objects_and_names.each do |object, name_link| %>
-      <% name_object = (object.respond_to?(:name) || !name_link) ? object : name_link %>
-      <tr class="filterable"
-          data-object-uuid="<%= name_object.uuid %>"
-          data-kind="<%= object.kind %>"
-          >
-        <td>
-          <% if @object.editable? %>
-            <%= link_to({action: 'remove_item', id: @object.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display.downcase} #{name_object.name rescue object.uuid} from this folder?", toggle: 'tooltip', placement: 'top'}, class: 'btn btn-xs btn-default btn-nodecorate', title: 'remove') do %>
-              <i class="fa fa-fw fa-ban"></i>
-            <% end %>
-          <% else %>
-            <i class="fa fa-fw"></i><%# placeholder %>
-          <% end %>
-
-          <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
-
-          <i class="fa fa-fw <%= fa_icon_class_for_object(object) %>"></i>
-
-          <%= render_editable_attribute name_object, 'name', nil, {data: {emptytext: "Unnamed #{object.class_for_display}"}} %>
-        </td>
-        <td>
-          <%= object.content_summary %>
-        </td>
-      </tr>
-    <% end %>
+  <colgroup>
+    <col width="40%" />
+    <col width="60%" />
+  </colgroup>
+  <tbody data-infinite-scroller="#Contents-scroll" data-infinite-content-href="<%= url_for(format: :json, partial: :contents_rows, offset: next_page_offset) if next_page_offset %>">
+    <%= render partial: 'show_contents_rows', locals: {folder: @object, objects_and_names: @objects_and_names} %>
   </tbody>
   <thead>
     <tr>
diff --git a/apps/workbench/app/views/folders/_show_contents_rows.html.erb b/apps/workbench/app/views/folders/_show_contents_rows.html.erb
new file mode 100644
index 0000000..c20bf27
--- /dev/null
+++ b/apps/workbench/app/views/folders/_show_contents_rows.html.erb
@@ -0,0 +1,26 @@
+<% objects_and_names.each do |object, name_link| %>
+  <% name_object = (object.respond_to?(:name) || !name_link) ? object : name_link %>
+  <tr class="filterable"
+      data-object-uuid="<%= name_object.uuid %>"
+      data-kind="<%= object.kind %>"
+      >
+    <td>
+      <% if folder.editable? %>
+        <%= link_to({action: 'remove_item', id: folder.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display.downcase} #{name_object.name rescue object.uuid} from this folder?", toggle: 'tooltip', placement: 'top'}, class: 'btn btn-xs btn-default btn-nodecorate', title: 'remove') do %>
+          <i class="fa fa-fw fa-ban"></i>
+        <% end %>
+      <% else %>
+        <i class="fa fa-fw"></i><%# placeholder %>
+      <% end %>
+
+      <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
+
+      <i class="fa fa-fw <%= fa_icon_class_for_object(object) %>"></i>
+
+      <%= render_editable_attribute name_object, 'name', nil %>
+    </td>
+    <td>
+      <%= object.content_summary %>
+    </td>
+  </tr>
+<% end %>
diff --git a/services/api/app/controllers/arvados/v1/groups_controller.rb b/services/api/app/controllers/arvados/v1/groups_controller.rb
index 4bccbcc..da82e81 100644
--- a/services/api/app/controllers/arvados/v1/groups_controller.rb
+++ b/services/api/app/controllers/arvados/v1/groups_controller.rb
@@ -20,9 +20,10 @@ class Arvados::V1::GroupsController < ApplicationController
     offset_all = @offset
     @orders = []
 
-    [Group, Job, PipelineInstance, PipelineTemplate,
-     Human, Specimen, Trait,
-     Collection].each do |klass|
+    [Group,
+     Job, PipelineInstance, PipelineTemplate,
+     Collection,
+     Human, Specimen, Trait].each do |klass|
       @objects = klass.readable_by(*@read_users)
       cond_sql = "#{klass.table_name}.owner_uuid = ?"
       cond_params = [@object.uuid]
diff --git a/services/api/app/models/link.rb b/services/api/app/models/link.rb
index af39185..1b3fc34 100644
--- a/services/api/app/models/link.rb
+++ b/services/api/app/models/link.rb
@@ -10,6 +10,7 @@ class Link < ArvadosModel
   after_destroy :maybe_invalidate_permissions_cache
   attr_accessor :head_kind, :tail_kind
   validate :name_link_has_valid_name
+  validate :name_link_owner_is_tail
 
   api_accessible :user, extend: :common do |t|
     t.add :tail_uuid
@@ -92,4 +93,11 @@ class Link < ArvadosModel
       true
     end
   end
+
+  def name_link_owner_is_tail
+    if link_class == 'name'
+      self.owner_uuid = tail_uuid
+      ensure_owner_uuid_is_permitted
+    end
+  end
 end

commit b3cc51580f7d4bfa0c390e29950b2d605bfcda79
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Jun 1 00:05:51 2014 -0400

    2872: Use data chooser for running pipelines. Many presentation fixes.

diff --git a/apps/workbench/app/assets/javascripts/application.js b/apps/workbench/app/assets/javascripts/application.js
index d66cb92..7274b3b 100644
--- a/apps/workbench/app/assets/javascripts/application.js
+++ b/apps/workbench/app/assets/javascripts/application.js
@@ -111,6 +111,11 @@ jQuery(function($){
             $('.btn').button();
         });
 
+    $(document).
+        on('ready ajax:complete', function() {
+            $('[data-toggle~=tooltip]').tooltip({container:'body'});
+        });
+
     HeaderRowFixer = function(selector) {
         this.duplicateTheadTr = function() {
             $(selector).each(function() {
diff --git a/apps/workbench/app/assets/javascripts/editable.js b/apps/workbench/app/assets/javascripts/editable.js
index 0514c1e..a32eb7e 100644
--- a/apps/workbench/app/assets/javascripts/editable.js
+++ b/apps/workbench/app/assets/javascripts/editable.js
@@ -75,6 +75,12 @@ $(document).
                       });
                 }
             });
+    }).
+    on('ready ajax:complete', function() {
+        $("[data-toggle~='x-editable']").click(function(e) {
+            e.stopPropagation();
+            $($(this).attr('data-toggle-selector')).editable('toggle');
+        });
     });
 
 $.fn.editabletypes.text.defaults.tpl = '<input type="text" name="editable-text">'
diff --git a/apps/workbench/app/assets/javascripts/folders.js b/apps/workbench/app/assets/javascripts/folders.js
index 10695cf..ff1c7b8 100644
--- a/apps/workbench/app/assets/javascripts/folders.js
+++ b/apps/workbench/app/assets/javascripts/folders.js
@@ -1,12 +1,20 @@
 $(document).
-    on('ready ajax:complete', function() {
-        $("[data-toggle='x-editable']").click(function(e) {
-            e.stopPropagation();
-            $($(this).attr('data-toggle-selector')).editable('toggle');
-        });
-    }).on('paste keyup change', 'input.search-folder-contents', function() {
+    on('paste keyup change', 'input.search-folder-contents', function() {
         var q = new RegExp($(this).val(), 'i');
         $(this).closest('div.panel').find('tbody tr').each(function() {
             $(this).toggle(!!$(this).text().match(q));
         });
+    }).on('change', 'select[data-filter-rows-by]', function() {
+        var val = $(this).val();
+        var filterby = $(this).attr('data-filter-rows-by');
+        var $target = $($(this).attr('data-filter-in'));
+        if (val == '') {
+            $target.find('.filterable').show();
+        } else {
+            $target.find('.filterable').hide();
+            console.log('.filterable[' + filterby + '="' + val + '"]');
+            $.each(val.split(" "), function(i, e) {
+                $target.find('.filterable['+filterby+'="'+e+'"]').show();
+            });
+        }
     });
diff --git a/apps/workbench/app/assets/stylesheets/application.css.scss b/apps/workbench/app/assets/stylesheets/application.css.scss
index d67d8dc..7d76f5a 100644
--- a/apps/workbench/app/assets/stylesheets/application.css.scss
+++ b/apps/workbench/app/assets/stylesheets/application.css.scss
@@ -189,3 +189,7 @@ div#wrapper {
 .arv-description-in-table:hover {
   overflow-y: scroll;
 }
+
+.btn.btn-nodecorate {
+  border: none;
+}
diff --git a/apps/workbench/app/assets/stylesheets/select_modal.css.scss b/apps/workbench/app/assets/stylesheets/select_modal.css.scss
index 47ae374..f97110a 100644
--- a/apps/workbench/app/assets/stylesheets/select_modal.css.scss
+++ b/apps/workbench/app/assets/stylesheets/select_modal.css.scss
@@ -1,3 +1,8 @@
+.selectable-container > .row {
+    padding-top: 5px;
+    padding-bottom: 5px;
+    padding-right: 1em;
+}
 .selectable.active, .selectable:hover {
     background: #d9edf7;
 }
diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 1c92191..4aa79fb 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -1,5 +1,6 @@
 class ApplicationController < ActionController::Base
   include ArvadosApiClientHelper
+  include ApplicationHelper
 
   respond_to :html, :json, :js
   protect_from_forgery
@@ -84,11 +85,11 @@ class ApplicationController < ActionController::Base
     end
 
     @objects ||= model_class
-    @objects = @objects.filter(@filters).limit(@limit).offset(@offset).all
+    @objects = @objects.filter(@filters).limit(@limit).offset(@offset)
   end
 
   def index
-    find_objects_for_index
+    find_objects_for_index if !@objects
     respond_to do |f|
       f.json { render json: @objects }
       f.html { render }
@@ -197,7 +198,7 @@ class ApplicationController < ActionController::Base
   end
 
   def show_pane_list
-    %w(Attributes Metadata JSON API)
+    %w(Attributes Metadata Advanced)
   end
 
   protected
@@ -244,7 +245,13 @@ class ApplicationController < ActionController::Base
       if params[:uuid].empty?
         @object = nil
       else
-        @object = model_class.find(params[:uuid])
+        if (model_class != Link and
+            resource_class_for_uuid(params[:uuid]) == Link)
+          @name_link = Link.find(params[:uuid])
+          @object = model_class.find(@name_link.head_uuid)
+        else
+          @object = model_class.find(params[:uuid])
+        end
       end
     else
       @object = model_class.where(uuid: params[:uuid]).first
diff --git a/apps/workbench/app/controllers/folders_controller.rb b/apps/workbench/app/controllers/folders_controller.rb
index bfae5fd..73e24bc 100644
--- a/apps/workbench/app/controllers/folders_controller.rb
+++ b/apps/workbench/app/controllers/folders_controller.rb
@@ -41,8 +41,9 @@ class FoldersController < ApplicationController
     end
   end
 
-  def index
+  def find_objects_for_index
     @objects = Group.where(group_class: 'folder').order('name')
+    super
     parent_of = {current_user.uuid => 'me'}
     @objects.each do |ob|
       parent_of[ob.uuid] = ob.owner_uuid
@@ -100,7 +101,6 @@ class FoldersController < ApplicationController
                                         name: "")]
       end
     end
-
     super
   end
 
diff --git a/apps/workbench/app/controllers/jobs_controller.rb b/apps/workbench/app/controllers/jobs_controller.rb
index 4746635..8743a6f 100644
--- a/apps/workbench/app/controllers/jobs_controller.rb
+++ b/apps/workbench/app/controllers/jobs_controller.rb
@@ -44,6 +44,6 @@ class JobsController < ApplicationController
   end
 
   def show_pane_list
-    %w(Attributes Provenance Metadata JSON API)
+    %w(Details Provenance Advanced)
   end
 end
diff --git a/apps/workbench/app/controllers/pipeline_instances_controller.rb b/apps/workbench/app/controllers/pipeline_instances_controller.rb
index 761dc91..3bb18aa 100644
--- a/apps/workbench/app/controllers/pipeline_instances_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_instances_controller.rb
@@ -3,6 +3,33 @@ class PipelineInstancesController < ApplicationController
   before_filter :find_objects_by_uuid, only: :compare
   include PipelineInstancesHelper
 
+  def update
+    @updates ||= params[@object.class.to_s.underscore.singularize.to_sym]
+    if (components = @updates[:components])
+      components.each do |cname, component|
+        if component[:script_parameters]
+          component[:script_parameters].each do |param, value_info|
+            if value_info.is_a? Hash
+              if resource_class_for_uuid(value_info[:value]) == Link
+                # Use the link target, not the link itself, as script
+                # parameter; but keep the link info around as well.
+                link = Link.find value_info[:value]
+                value_info[:value] = link.head_uuid
+                value_info[:link_uuid] = link.uuid
+                value_info[:link_name] = link.name
+              else
+                # Delete stale link_uuid and link_name data.
+                value_info[:link_uuid] = nil
+                value_info[:link_name] = nil
+              end
+            end
+          end
+        end
+      end
+    end
+    super
+  end
+
   def graph(pipelines)
     count = {}    
     provenance = {}
@@ -142,10 +169,13 @@ class PipelineInstancesController < ApplicationController
   end
 
   def show_pane_list
-    panes = %w(Components Graph Attributes Metadata JSON API)
+    panes = %w(Components Graph Advanced)
     if @object and @object.state.in? ['New', 'Ready']
       panes = %w(Inputs) + panes
     end
+    if not @object.components.values.collect { |x| x['job'] }.compact.any?
+      panes -= ['Graph']
+    end
     panes
   end
 
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index 81fc689..a463a50 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -79,10 +79,16 @@ module ApplicationHelper
   #
   def link_to_if_arvados_object(attrvalue, opts={}, style_opts={})
     if (resource_class = resource_class_for_uuid(attrvalue, opts))
-      link_uuid = attrvalue.is_a?(ArvadosBase) ? attrvalue.uuid : attrvalue
+      if attrvalue.is_a? ArvadosBase
+        object = attrvalue
+        link_uuid = attrvalue.uuid
+      else
+        object = nil
+        link_uuid = attrvalue
+      end
       link_name = opts[:link_text]
       if !link_name
-        link_name = link_uuid
+        link_name = object.andand.default_name || resource_class.default_name
 
         if opts[:friendly_name]
           if attrvalue.respond_to? :friendly_link_name
@@ -159,17 +165,17 @@ module ApplicationHelper
     span_id = object.uuid.to_s + '-' + attr.to_s + '-' + (@unique_id += 1).to_s
 
     span_tag = content_tag 'span', attrvalue.to_s, {
-      "data-emptytext" => "none",
+      "data-emptytext" => (object.andand.default_name || 'none'),
       "data-placement" => "bottom",
       "data-type" => input_type,
-      "data-title" => "Update #{attr.gsub '_', ' '}",
+      "data-title" => "Edit #{attr.gsub '_', ' '}",
       "data-name" => attr,
       "data-object-uuid" => object.uuid,
       "data-toggle" => "manual",
       "id" => span_id,
       :class => "editable"
     }.merge(htmloptions).merge(ajax_options)
-    span_tag + raw(' <a href="#" class="btn btn-xs btn-default" data-toggle="x-editable" data-toggle-selector="#' + span_id + '"><i class="fa fa-fw fa-pencil"></i> Edit</a>')
+    span_tag + raw(' <a href="#" class="btn btn-xs btn-default btn-nodecorate" data-toggle="x-editable tooltip" data-toggle-selector="#' + span_id + '" data-placement="top" title="edit"><i class="fa fa-fw fa-pencil"></i></a>')
   end
 
   def render_pipeline_component_attribute(object, attr, subattr, value_info, htmloptions={})
@@ -215,6 +221,49 @@ module ApplicationHelper
       dataclass = ArvadosBase.resource_class_for_uuid(attrvalue)
     end
 
+    id = "#{object.uuid}-#{subattr.join('-')}"
+    dn = "[#{attr}]"
+    subattr.each do |a|
+      dn += "[#{a}]"
+    end
+    if value_info.is_a? Hash
+      dn += '[value]'
+    end
+
+    if dataclass == Collection
+      selection_param = object.class.to_s.underscore + dn
+      display_value = attrvalue
+      if value_info.is_a?(Hash)
+        if (link = Link.find? value_info[:link_uuid])
+          display_value = link.name
+        elsif value_info[:link_name]
+          display_value = value_info[:link_name]
+        end
+      end
+      modal_path = choose_collections_path \
+      ({ title: 'Choose a dataset:',
+         action_name: 'OK',
+         action_href: pipeline_instance_path(id: object.uuid),
+         action_method: 'patch',
+         action_data: {
+           merge: true,
+           selection_param: selection_param,
+           success: 'page-refresh'
+         }.to_json,
+        })
+      return content_tag('div', :class => 'input-group') do
+        html = text_field_tag(dn, display_value, :class => 'form-control')
+        html + content_tag('span', :class => 'input-group-btn') do
+          link_to('Choose',
+                  modal_path,
+                  { :class => "btn btn-primary",
+                    :remote => true,
+                    :method => 'get',
+                  })
+        end
+      end
+    end
+
     if dataclass.andand.is_a?(Class)
       datatype = 'select'
     elsif dataclass == 'number'
@@ -228,15 +277,6 @@ module ApplicationHelper
       datatype = 'text'
     end
 
-    id = "#{object.uuid}-#{subattr.join('-')}"
-    dn = "[#{attr}]"
-    subattr.each do |a|
-      dn += "[#{a}]"
-    end
-    if value_info.is_a? Hash
-      dn += '[value]'
-    end
-
     selectables = []
     attrtext = attrvalue
     if dataclass and dataclass.is_a? Class
@@ -303,15 +343,21 @@ module ApplicationHelper
   end
 
   def fa_icon_class_for_object object
-    case object.class.to_s
-    when 'User'
+    case object.class.to_s.to_sym
+    when :User
       'fa-user'
-    when 'Group'
+    when :Group
       object.group_class ? 'fa-folder' : 'fa-users'
-    when 'Job', 'PipelineInstance', 'PipelineTemplate'
+    when :Job, :PipelineInstance, :PipelineTemplate
       'fa-gears'
-    when 'Collection'
+    when :Collection
       'fa-archive'
+    when :Specimen
+      'fa-flask'
+    when :Trait
+      'fa-clipboard'
+    when :Human
+      'fa-male'
     end
   end
 end
diff --git a/apps/workbench/app/models/arvados_base.rb b/apps/workbench/app/models/arvados_base.rb
index 2c2963c..a6aded9 100644
--- a/apps/workbench/app/models/arvados_base.rb
+++ b/apps/workbench/app/models/arvados_base.rb
@@ -109,6 +109,10 @@ class ArvadosBase < ActiveRecord::Base
     new.private_reload(hash)
   end
 
+  def self.find?(*args)
+    find(*args) rescue nil
+  end
+
   def self.order(*args)
     ArvadosResourceList.new(self).order(*args)
   end
@@ -282,7 +286,7 @@ class ArvadosBase < ActiveRecord::Base
   end
 
   def class_for_display
-    self.class.to_s
+    self.class.to_s.underscore.humanize
   end
 
   def self.creatable?
@@ -343,7 +347,7 @@ class ArvadosBase < ActiveRecord::Base
   end
 
   def friendly_link_name
-    (name if self.respond_to? :name) || uuid
+    (name if self.respond_to? :name) || default_name
   end
 
   def content_summary
@@ -354,6 +358,15 @@ class ArvadosBase < ActiveRecord::Base
     friendly_link_name
   end
 
+  def self.default_name
+    self.to_s.underscore.humanize
+  end
+
+  # Placeholder for name when name is missing or empty
+  def default_name
+    "New #{class_for_display.downcase}"
+  end
+
   def owner
     ArvadosBase.find(owner_uuid) rescue nil
   end
diff --git a/apps/workbench/app/models/collection.rb b/apps/workbench/app/models/collection.rb
index 2fe4e2b..90e53e8 100644
--- a/apps/workbench/app/models/collection.rb
+++ b/apps/workbench/app/models/collection.rb
@@ -1,6 +1,4 @@
 class Collection < ArvadosBase
-  include ApplicationHelper
-
   MD5_EMPTY = 'd41d8cd98f00b204e9800998ecf8427e'
 
   # Return true if the given string is the locator of a zero-length blob
@@ -13,7 +11,7 @@ class Collection < ArvadosBase
   end
 
   def content_summary
-    human_readable_bytes_html(total_bytes) + " " + super
+    ApplicationController.helpers.human_readable_bytes_html(total_bytes) + " " + super
   end
 
   def total_bytes
diff --git a/apps/workbench/app/views/application/_show_advanced.html.erb b/apps/workbench/app/views/application/_show_advanced.html.erb
new file mode 100644
index 0000000..d31b5f5
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced.html.erb
@@ -0,0 +1,22 @@
+<div class="panel-group" id="arv-adv-accordion">
+  <% ['API response',
+     'Python example',
+     'CLI example',
+     'curl example'].each do |section| %>
+    <% section_id = section.gsub(" ","_").downcase %>
+    <div class="panel panel-default">
+      <div class="panel-heading">
+        <h4 class="panel-title">
+          <a data-toggle="collapse" data-parent="#arv-adv-accordion" href="#advanced_<%=section_id%>">
+            <%= section %>
+          </a>
+        </h4>
+      </div>
+      <div id="advanced_<%=section_id%>" class="panel-collapse collapse">
+        <div class="panel-body">
+          <%= render partial: "show_advanced_#{section_id}", locals: {object: @object} %>
+        </div>
+      </div>
+    </div>
+  <% end %>
+</div>
diff --git a/apps/workbench/app/views/application/_show_advanced_api_response.html.erb b/apps/workbench/app/views/application/_show_advanced_api_response.html.erb
new file mode 100644
index 0000000..9ef124a
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced_api_response.html.erb
@@ -0,0 +1,3 @@
+<pre>
+<%= JSON.pretty_generate(object.attributes.reject { |k,v| k == 'id' }) rescue nil %>
+</pre>
diff --git a/apps/workbench/app/views/application/_show_advanced_cli_example.html.erb b/apps/workbench/app/views/application/_show_advanced_cli_example.html.erb
new file mode 100644
index 0000000..4516876
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced_cli_example.html.erb
@@ -0,0 +1,8 @@
+<pre>
+arv --pretty <%= object.class.to_s.underscore %> get \
+ --uuid <%= object.uuid %>
+
+arv <%= object.class.to_s.underscore %> update \
+ --uuid <%= object.uuid %> \
+ --<%= object.class.to_s.underscore.gsub '_', '-' %> '<%= JSON.generate({object.attributes.keys[-3] => object.attributes.values[-3]}).gsub("'","'\''") %>'
+</pre>
diff --git a/apps/workbench/app/views/application/_show_advanced_curl_example.html.erb b/apps/workbench/app/views/application/_show_advanced_curl_example.html.erb
new file mode 100644
index 0000000..0454c13
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced_curl_example.html.erb
@@ -0,0 +1,9 @@
+<pre>
+curl -X PUT \
+ -H "Authorization: OAuth2 $ARVADOS_API_TOKEN" \
+ --data-urlencode <%= object.class.to_s.underscore %>@/dev/stdin \
+ https://$ARVADOS_API_HOST/arvados/v1/<%= object.class.to_s.pluralize.underscore %>/<%= object.uuid %> \
+ <<EOF
+<%= JSON.pretty_generate({object.attributes.keys[-3] => object.attributes.values[-3]}) %>
+EOF
+</pre>
diff --git a/apps/workbench/app/views/application/_show_advanced_python_example.html.erb b/apps/workbench/app/views/application/_show_advanced_python_example.html.erb
new file mode 100644
index 0000000..3ceae4f
--- /dev/null
+++ b/apps/workbench/app/views/application/_show_advanced_python_example.html.erb
@@ -0,0 +1,5 @@
+<pre>
+import arvados
+
+x = arvados.api().<%= object.class.to_s.pluralize.underscore %>().get(uuid='<%= object.uuid %>').execute()
+</pre>
diff --git a/apps/workbench/app/views/application/_show_json.html.erb b/apps/workbench/app/views/application/_show_json.html.erb
deleted file mode 100644
index 2f0cd21..0000000
--- a/apps/workbench/app/views/application/_show_json.html.erb
+++ /dev/null
@@ -1,3 +0,0 @@
-<pre>
-<%= JSON.pretty_generate(@object.attributes.reject { |k,v| k == 'id' }) rescue nil %>
-</pre>
diff --git a/apps/workbench/app/views/application/_show_object_button.html.erb b/apps/workbench/app/views/application/_show_object_button.html.erb
index 81ca745..157ae49 100644
--- a/apps/workbench/app/views/application/_show_object_button.html.erb
+++ b/apps/workbench/app/views/application/_show_object_button.html.erb
@@ -1,3 +1,3 @@
 <% htmloptions = {class: ''}.merge(htmloptions || {})
    htmloptions[:class] += " btn-#{size}" rescue nil %>
-<%= link_to_if_arvados_object object, { link_text: raw('Show <i class="fa fa-fw fa-arrow-circle-right"></i>') }, { class: 'btn btn-default ' + htmloptions[:class] } %>
+<%= link_to_if_arvados_object object, { link_text: raw('<i class="glyphicon glyphicon-zoom-in"></i>') }, { data: {toggle: 'tooltip', placement: 'top'}, title: 'show', class: 'btn btn-default btn-nodecorate ' + htmloptions[:class] } %>
diff --git a/apps/workbench/app/views/folders/_choose.html.erb b/apps/workbench/app/views/folders/_choose.html.erb
index c27d669..7d57ca5 100644
--- a/apps/workbench/app/views/folders/_choose.html.erb
+++ b/apps/workbench/app/views/folders/_choose.html.erb
@@ -8,7 +8,7 @@
       </div>
 
       <div class="modal-body">
-        <div class="container-fluid arv-folder-list selectable-container" style="height: 15em; overflow-y: scroll">
+        <div class="container-fluid selectable-container" style="height: 15em; overflow-y: scroll">
           <% [@my_folder_tree, @shared_folder_tree].each do |tree| %>
             <% tree.each do |foldernode| %>
               <% if foldernode[:object].is_a? String %>
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
index 6a609cf..d880e01 100644
--- a/apps/workbench/app/views/folders/_show_contents.html.erb
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -26,7 +26,7 @@
       <% end %>
       <%= link_to(
             choose_pipeline_templates_path(
-              title: 'Run pipeline:',
+              title: 'Choose a pipeline to run:',
               action_name: 'Configure...',
               action_href: pipeline_instances_path,
               action_method: 'post',
@@ -36,12 +36,20 @@
       <% end %>
     </div>
     <div class="col-lg-4">
-      <select class="form-control" data-filter-rows-by="kind">
-        <option value="">Show everything</option>
-        <option value="arvados#collection">Data</option>
-        <option value="arvados#pipeline_instance arvados#job">Compute jobs</option>
-        <option value="arvados#pipeline_template">Pipelines</option>
-      </select>
+      <form class="form-inline" role="form">
+        Show:
+        <select class="form-control" data-filter-rows-by="data-kind" data-filter-in="table.arv-index.arv-folder-contents">
+          <option value="">Everything</option>
+          <option value="arvados#collection">Data</option>
+          <option value="arvados#pipeline_instance arvados#job">Compute jobs</option>
+          <option value="arvados#pipeline_template">Pipelines</option>
+          <!--
+          <option value="arvados#specimen">Specimens</option>
+          <option value="arvados#human">Humans</option>
+          <option value="arvados#trait">Traits</option>
+          -->
+        </select>
+      </form>
     </div>
     <div class="col-lg-4">
       <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents"/>
@@ -49,48 +57,46 @@
   </div>
 </div>
 
-<table class="table table-condensed arv-index">
+<table class="table table-condensed arv-index arv-folder-contents">
   <tbody>
     <colgroup>
       <col width="40%" />
-      <col width="40%" />
-      <col width="10%" />
-      <col width="10%" />
+      <col width="60%" />
     </colgroup>
     <% @objects_and_names.each do |object, name_link| %>
-      <tr data-object-uuid="<%= (name_link && name_link.uuid) || object.uuid %>">
+      <% name_object = (object.respond_to?(:name) || !name_link) ? object : name_link %>
+      <tr class="filterable"
+          data-object-uuid="<%= name_object.uuid %>"
+          data-kind="<%= object.kind %>"
+          >
         <td>
+          <% if @object.editable? %>
+            <%= link_to({action: 'remove_item', id: @object.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display.downcase} #{name_object.name rescue object.uuid} from this folder?", toggle: 'tooltip', placement: 'top'}, class: 'btn btn-xs btn-default btn-nodecorate', title: 'remove') do %>
+              <i class="fa fa-fw fa-ban"></i>
+            <% end %>
+          <% else %>
+            <i class="fa fa-fw"></i><%# placeholder %>
+          <% end %>
+
+          <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
+
           <i class="fa fa-fw <%= fa_icon_class_for_object(object) %>"></i>
-          <%= render_editable_attribute name_link, 'name', nil, {data: {emptytext: "Unnamed #{object.class_for_display}"}} %>
+
+          <%= render_editable_attribute name_object, 'name', nil, {data: {emptytext: "Unnamed #{object.class_for_display}"}} %>
         </td>
         <td>
           <%= object.content_summary %>
         </td>
-        <td>
-          <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
-        </td>
-        <td>
-          <% if @object.editable? %>
-            <%= link_to({action: 'remove_item', id: @object.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display} #{name_link.andand.uuid ? name_link.name : object.uuid} from this folder?"}, class: 'btn btn-xs btn-default') do %>
-              Remove <i class="fa fa-fw fa-ban"></i>
-            <% end %>
-          <% end %>
-        </td>
       </tr>
     <% end %>
   </tbody>
   <thead>
     <tr>
       <th>
-        name
       </th>
       <th>
         description
       </th>
-      <th>
-      </th>
-      <th>
-      </th>
     </tr>
   </thead>
 </table>
diff --git a/apps/workbench/app/views/jobs/_show_details.html.erb b/apps/workbench/app/views/jobs/_show_details.html.erb
new file mode 100644
index 0000000..7b6b176
--- /dev/null
+++ b/apps/workbench/app/views/jobs/_show_details.html.erb
@@ -0,0 +1 @@
+<%= render partial: 'application/show_attributes' %>
diff --git a/apps/workbench/app/views/layouts/application.html.erb b/apps/workbench/app/views/layouts/application.html.erb
index 6e3618e..0ec08cc 100644
--- a/apps/workbench/app/views/layouts/application.html.erb
+++ b/apps/workbench/app/views/layouts/application.html.erb
@@ -71,9 +71,15 @@
             <% else %>
               <li class="nav-separator"><span class="glyphicon glyphicon-arrow-right"></span></li>
               <li>
-                <%= link_to(
-                            controller.controller_name.humanize.downcase,
-                            url_for({controller: params[:controller]})) %>
+                <% if @object and \
+                      ((@name_link and (o = Group.find?(@name_link.tail_uuid)))\
+                       or (o = Group.find?(@object.owner_uuid))) %>
+                  <%= link_to(o.name, folder_path(o.uuid)) %>
+                <% else %>
+                  <%= link_to(
+                      controller.controller_name.humanize.downcase,
+                      url_for({controller: params[:controller]})) %>
+                <% end %>
               </li>
               <% if params[:action] != 'index' %>
                 <li class="nav-separator">
diff --git a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
index c075610..b08e0b8 100644
--- a/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
+++ b/apps/workbench/app/views/pipeline_instances/_show_components.html.erb
@@ -6,7 +6,7 @@
 
 <%= content_for :content_top do %>
   <h2>
-    <%= render_editable_attribute @object, 'name', nil, { 'data-emptytext' => 'Unnamed pipeline' } %>
+    <%= render_editable_attribute @object, 'name', nil %>
   </h2>
   <% if template %>
   <h4>

commit 8cc28c45ca3da20e9d66aabbaf43de777c582a84
Author: Tom Clegg <tom at curoverse.com>
Date:   Sat May 31 18:04:09 2014 -0400

    2872: Start doing everything from folder perspective.

diff --git a/apps/workbench/app/assets/javascripts/select_modal.js b/apps/workbench/app/assets/javascripts/select_modal.js
index 85d97c9..278dbb5 100644
--- a/apps/workbench/app/assets/javascripts/select_modal.js
+++ b/apps/workbench/app/assets/javascripts/select_modal.js
@@ -8,18 +8,24 @@ $(document).on('click', '.selectable', function() {
     $this.toggleClass('active');
 }).on('click', '.modal button[data-action-href]', function() {
     var selection = [];
-    var data = {};
+    var data = [];
     var $modal = $(this).closest('.modal');
+    var action_data = $(this).data('action-data');
+    var selection_param = action_data.selection_param;
     $modal.find('.modal-error').removeClass('hide').hide();
     $modal.find('.selectable.active[data-object-uuid]').each(function() {
-        selection.push($(this).attr('data-object-uuid'));
+        var val = $(this).attr('data-object-uuid');
+        data.push({name: selection_param, value: val});
+    });
+    $.each(action_data, function(key, value) {
+        data.push({name: key, value: value});
     });
-    data[$(this).data('action-data').selection_param] = selection[0];
     $.ajax($(this).attr('data-action-href'),
            {dataType: 'json',
             type: $(this).attr('data-method'),
             data: data,
-            context: {modal: $modal}}).
+            traditional: true,
+            context: {modal: $modal, action_data: action_data}}).
         fail(function(jqxhr, status, error) {
             if (jqxhr.readyState == 0 || jqxhr.status == 0) {
                 message = "Cancelled."
@@ -32,8 +38,15 @@ $(document).on('click', '.selectable', function() {
                 html('<div class="alert alert-danger">' + message + '</div>').
                 show();
         }).
-        success(function() {
+        done(function(data, status, jqxhr) {
+            var event_name = this.action_data.success;
             this.modal.find('.modal-error').hide();
-            window.location.reload();
+            $(document).trigger(event_name!=null ? event_name : 'page-refresh',
+                                [data, status, jqxhr, this.action_data]);
         });
 });
+$(document).on('page-refresh', function(event, data, status, jqxhr, action_data) {
+    window.location.reload();
+}).on('redirect-to-created-object', function(event, data, status, jqxhr, action_data) {
+    window.location.href = data.href.replace(/^[^\/]*\/\/[^\/]*/, '');
+});
diff --git a/apps/workbench/app/assets/stylesheets/application.css.scss b/apps/workbench/app/assets/stylesheets/application.css.scss
index 51c96d7..d67d8dc 100644
--- a/apps/workbench/app/assets/stylesheets/application.css.scss
+++ b/apps/workbench/app/assets/stylesheets/application.css.scss
@@ -64,6 +64,9 @@ table.arv-index tbody td.arv-object-AuthorizedKey.arv-attr-public_key {
     overflow-x: hidden;
     max-width: 120px;
 }
+table.arv-index > thead > tr > th {
+    border-top: none;
+}
 table.table-fixedlayout {
     white-space: nowrap;
     table-layout: fixed;
@@ -171,23 +174,18 @@ table.table-fixed-header-row tbody {
     z-index:1055;
 }
 
-.navbar-nav.side-nav {
-    box-shadow: inset -1px 0 #e7e7e7;
-}
-.navbar-nav.side-nav > li:first-child {
-    margin-top: 5px; /* keep "hover" bg below top nav bottom border */
+/* Do not leave space for left-nav */
+div#wrapper {
+  padding-left: 0;
 }
-.navbar-nav.side-nav > li > a {
-    padding-top: 10px;
-    padding-bottom: 10px;
+
+.arv-description-as-subtitle {
+  padding-bottom: 1em;
 }
-.navbar-nav.side-nav > li.dropdown > ul.dropdown-menu > li > a {
-    padding-top: 5px;
-    padding-bottom: 5px;
+.arv-description-in-table {
+  max-height: 3.5em;
+  overflow-y: hidden;
 }
-.navbar-nav.side-nav a.active,
-.navbar-nav.side-nav a:hover,
-.navbar-nav.side-nav a:focus {
-    border-right: 1px solid #ffffff;
-    background: #ffffff;
+.arv-description-in-table:hover {
+  overflow-y: scroll;
 }
diff --git a/apps/workbench/app/assets/stylesheets/folders.css.scss b/apps/workbench/app/assets/stylesheets/folders.css.scss
index a033e87..163c188 100644
--- a/apps/workbench/app/assets/stylesheets/folders.css.scss
+++ b/apps/workbench/app/assets/stylesheets/folders.css.scss
@@ -6,8 +6,3 @@
 .arv-folder-list > .row.folder:hover {
     background: #d9edf7;
 }
-.arv-folder-list > .row.folder.active,
-.arv-folder-list > .row.folder.active:hover {
-    background: #428bca;
-    color: #fff;
-}
diff --git a/apps/workbench/app/assets/stylesheets/select_modal.css.scss b/apps/workbench/app/assets/stylesheets/select_modal.css.scss
index 6fe5651..47ae374 100644
--- a/apps/workbench/app/assets/stylesheets/select_modal.css.scss
+++ b/apps/workbench/app/assets/stylesheets/select_modal.css.scss
@@ -1,3 +1,10 @@
 .selectable.active, .selectable:hover {
     background: #d9edf7;
 }
+.selectable.active,
+.selectable.active a,
+.selectable.active:hover,
+.selectable.active:hover a {
+    background: #428bca;
+    color: #fff;
+}
diff --git a/apps/workbench/app/controllers/actions_controller.rb b/apps/workbench/app/controllers/actions_controller.rb
index 368d9a8..cbe3405 100644
--- a/apps/workbench/app/controllers/actions_controller.rb
+++ b/apps/workbench/app/controllers/actions_controller.rb
@@ -20,15 +20,44 @@ class ActionsController < ApplicationController
   end
 
   expose_action :copy_selections_into_folder do
+    link_selections = Link.filter([['uuid','in',params["selection"]]])
+    link_uuids = link_selections.collect(&:uuid)
+
+    # Given a link uuid, we'll add the link's head_uuid. Given another
+    # type, we'll add the object itself.
+    uuids_to_add = params["selection"] - link_uuids
+    uuids_to_add += link_selections.collect(&:head_uuid)
+
+    # Skip anything that's already here.
     already_named = Link.
       filter([['tail_uuid','=', at object.uuid],
-              ['head_uuid','in',params["selection"]]]).
+              ['head_uuid','in',uuids_to_add],
+              ['link_class','=','name']]).
       collect(&:head_uuid)
-    (params["selection"] - already_named).each do |s|
-      Link.create(tail_uuid: @object.uuid,
-                  head_uuid: s,
-                  link_class: 'name',
-                  name: "#{s} added #{Time.now}")
+    uuids_to_add -= already_named
+
+    # Given a name link, we'll try to add the linked object using the
+    # same name.
+    name_for = {}
+    link_selections.
+      select { |x| x.link_class == 'name' }.
+      each do |link|
+      name_for[link.head_uuid] = link.name
+    end
+
+    uuids_to_add.each do |s|
+      name = name_for[s] || s
+      begin
+        Link.create(tail_uuid: @object.uuid,
+                    head_uuid: s,
+                    link_class: 'name',
+                    name: name)
+      rescue
+        Link.create(tail_uuid: @object.uuid,
+                    head_uuid: s,
+                    link_class: 'name',
+                    name: name + " (#{Time.now.localtime})")
+      end
     end
     redirect_to @object
   end
diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 59ca350..1c92191 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -63,7 +63,7 @@ class ApplicationController < ActionController::Base
     self.render_error status: 404
   end
 
-  def index
+  def find_objects_for_index
     @limit ||= 200
     if params[:limit]
       @limit = params[:limit].to_i
@@ -85,6 +85,10 @@ class ApplicationController < ActionController::Base
 
     @objects ||= model_class
     @objects = @objects.filter(@filters).limit(@limit).offset(@offset).all
+  end
+
+  def index
+    find_objects_for_index
     respond_to do |f|
       f.json { render json: @objects }
       f.html { render }
@@ -109,6 +113,11 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def choose
+    find_objects_for_index
+    render partial: 'choose', locals: {multiple: params[:multiple]}
+  end
+
   def render_content
     if !@object
       return render_not_found("object not found")
diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index 218ba89..9371bd1 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -40,6 +40,15 @@ class CollectionsController < ApplicationController
     end
   end
 
+  def choose
+    @name_links = Link.
+      filter([['link_class','=','name'],
+              ['head_uuid','is_a','arvados#collection']])
+    @objects = Collection.
+      filter([['uuid','in', at name_links.collect(&:head_uuid)]])
+    super
+  end
+
   def index
     if params[:search].andand.length.andand > 0
       tags = Link.where(any: ['contains', params[:search]])
diff --git a/apps/workbench/app/controllers/folders_controller.rb b/apps/workbench/app/controllers/folders_controller.rb
index 8ebb1a3..bfae5fd 100644
--- a/apps/workbench/app/controllers/folders_controller.rb
+++ b/apps/workbench/app/controllers/folders_controller.rb
@@ -7,6 +7,10 @@ class FoldersController < ApplicationController
     %w(Folders)
   end
 
+  def show_pane_list
+    %w(Contents Permissions)
+  end
+
   def remove_item
     @removed_uuids = []
     links = []
@@ -76,11 +80,6 @@ class FoldersController < ApplicationController
                           buildtree.call(children_of, false)})
   end
 
-  def choose
-    index
-    render partial: 'choose'
-  end
-
   def show
     @objects = @object.contents include_linked: true
     @share_links = Link.filter([['head_uuid', '=', @object.uuid],
diff --git a/apps/workbench/app/controllers/pipeline_templates_controller.rb b/apps/workbench/app/controllers/pipeline_templates_controller.rb
index 5173d4e..afe41c4 100644
--- a/apps/workbench/app/controllers/pipeline_templates_controller.rb
+++ b/apps/workbench/app/controllers/pipeline_templates_controller.rb
@@ -8,5 +8,4 @@ class PipelineTemplatesController < ApplicationController
   def show_pane_list
     %w(Components Pipelines Attributes Metadata JSON API)
   end
-
 end
diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index d844350..81fc689 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -155,16 +155,21 @@ module ApplicationHelper
       ajax_options['data-pk'][:defaults] = object.attributes
     end
     ajax_options['data-pk'] = ajax_options['data-pk'].to_json
+    @unique_id ||= 0
+    span_id = object.uuid.to_s + '-' + attr.to_s + '-' + (@unique_id += 1).to_s
 
-    content_tag 'span', attrvalue.to_s, {
+    span_tag = content_tag 'span', attrvalue.to_s, {
       "data-emptytext" => "none",
       "data-placement" => "bottom",
       "data-type" => input_type,
       "data-title" => "Update #{attr.gsub '_', ' '}",
       "data-name" => attr,
       "data-object-uuid" => object.uuid,
+      "data-toggle" => "manual",
+      "id" => span_id,
       :class => "editable"
     }.merge(htmloptions).merge(ajax_options)
+    span_tag + raw(' <a href="#" class="btn btn-xs btn-default" data-toggle="x-editable" data-toggle-selector="#' + span_id + '"><i class="fa fa-fw fa-pencil"></i> Edit</a>')
   end
 
   def render_pipeline_component_attribute(object, attr, subattr, value_info, htmloptions={})
@@ -296,4 +301,17 @@ module ApplicationHelper
               button_href, params, *rest)
     end
   end
+
+  def fa_icon_class_for_object object
+    case object.class.to_s
+    when 'User'
+      'fa-user'
+    when 'Group'
+      object.group_class ? 'fa-folder' : 'fa-users'
+    when 'Job', 'PipelineInstance', 'PipelineTemplate'
+      'fa-gears'
+    when 'Collection'
+      'fa-archive'
+    end
+  end
 end
diff --git a/apps/workbench/app/models/pipeline_instance.rb b/apps/workbench/app/models/pipeline_instance.rb
index aad7cfc..beeba62 100644
--- a/apps/workbench/app/models/pipeline_instance.rb
+++ b/apps/workbench/app/models/pipeline_instance.rb
@@ -5,6 +5,14 @@ class PipelineInstance < ArvadosBase
     true
   end
 
+  def content_summary
+    begin
+      PipelineTemplate.find(pipeline_template_uuid).name
+    rescue
+      super
+    end
+  end
+
   def update_job_parameters(new_params)
     self.components[:steps].each_with_index do |step, i|
       step[:params].each do |param|
diff --git a/apps/workbench/app/views/application/_choose.html.erb b/apps/workbench/app/views/application/_choose.html.erb
new file mode 100644
index 0000000..cf18cdc
--- /dev/null
+++ b/apps/workbench/app/views/application/_choose.html.erb
@@ -0,0 +1,24 @@
+<div class="modal">
+  <div class="modal-dialog">
+    <div class="modal-content">
+
+      <div class="modal-header">
+        <button type="button" class="close" onClick="reset_form()" data-dismiss="modal" aria-hidden="true">×</button>
+        <h4 class="modal-title"><%= params[:title] || "Choose #{@objects.first.class_for_display}" %></h4>
+      </div>
+
+      <div class="modal-body">
+        <div class="container-fluid arv-folder-list selectable-container" style="height: 15em; overflow-y: scroll">
+          <%= render partial: 'choose_rows', locals: {multiple: multiple} %>
+        </div>
+      </div>
+
+      <div class="modal-footer">
+        <button class="btn btn-default" data-dismiss="modal" aria-hidden="true">Cancel</button>
+        <button class="btn btn-primary" aria-hidden="true"><%= params[:action_name] || 'Select' %></button>
+        <div class="modal-error hide" style="text-align: left; margin-top: 1em;">
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/apps/workbench/app/views/folders/_choose.js.erb b/apps/workbench/app/views/application/_choose.js.erb
similarity index 88%
copy from apps/workbench/app/views/folders/_choose.js.erb
copy to apps/workbench/app/views/application/_choose.js.erb
index 4ecd072..3bb3694 100644
--- a/apps/workbench/app/views/folders/_choose.js.erb
+++ b/apps/workbench/app/views/application/_choose.js.erb
@@ -1,4 +1,4 @@
-$('body > .modal-container').html("<%= escape_javascript(render partial: 'choose.html') %>");
+$('body > .modal-container').html("<%= escape_javascript(render partial: 'choose.html', locals: {multiple: multiple}) %>");
 $('body > .modal-container .modal').modal('show');
 $('body > .modal-container .modal .modal-footer .btn-primary').
     addClass('<%= j params[:action_class] %>').
diff --git a/apps/workbench/app/views/collections/_choose.js.erb b/apps/workbench/app/views/collections/_choose.js.erb
new file mode 120000
index 0000000..8420a7f
--- /dev/null
+++ b/apps/workbench/app/views/collections/_choose.js.erb
@@ -0,0 +1 @@
+../application/_choose.js.erb
\ No newline at end of file
diff --git a/apps/workbench/app/views/collections/_choose_rows.html.erb b/apps/workbench/app/views/collections/_choose_rows.html.erb
new file mode 100644
index 0000000..8622830
--- /dev/null
+++ b/apps/workbench/app/views/collections/_choose_rows.html.erb
@@ -0,0 +1,11 @@
+<% @name_links.each do |name_link| %>
+  <div class="row selectable <%= 'multiple' if multiple %>" data-object-uuid="<%= name_link.uuid %>">
+    <div class="col-sm-8" style="overflow-x:hidden">
+      <i class="fa fa-fw fa-archive"></i>
+      <%= name_link.name %>
+    </div>
+    <div class="col-sm-4" style="overflow-x:hidden">
+      <%= link_to_if_arvados_object name_link.tail_uuid, friendly_name: true %>
+    </div>
+  </div>
+<% end %>
diff --git a/apps/workbench/app/views/folders/_choose.js.erb b/apps/workbench/app/views/folders/_choose.js.erb
deleted file mode 100644
index 4ecd072..0000000
--- a/apps/workbench/app/views/folders/_choose.js.erb
+++ /dev/null
@@ -1,8 +0,0 @@
-$('body > .modal-container').html("<%= escape_javascript(render partial: 'choose.html') %>");
-$('body > .modal-container .modal').modal('show');
-$('body > .modal-container .modal .modal-footer .btn-primary').
-    addClass('<%= j params[:action_class] %>').
-    attr('data-action-href', '<%= j params[:action_href] %>').
-    attr('data-method', '<%= j params[:action_method] %>').
-    data('action-data', <%= raw params[:action_data] %>);
-$(document).trigger('ajax:complete');
diff --git a/apps/workbench/app/views/folders/_choose.js.erb b/apps/workbench/app/views/folders/_choose.js.erb
new file mode 120000
index 0000000..8420a7f
--- /dev/null
+++ b/apps/workbench/app/views/folders/_choose.js.erb
@@ -0,0 +1 @@
+../application/_choose.js.erb
\ No newline at end of file
diff --git a/apps/workbench/app/views/folders/_show_contents.html.erb b/apps/workbench/app/views/folders/_show_contents.html.erb
new file mode 100644
index 0000000..6a609cf
--- /dev/null
+++ b/apps/workbench/app/views/folders/_show_contents.html.erb
@@ -0,0 +1,96 @@
+<% content_for :content_top do %>
+
+<h2>
+  <%= render_editable_attribute @object, 'name', nil, { 'data-emptytext' => "New folder" } %>
+</h2>
+
+<div class="arv-description-as-subtitle">
+  <%= render_editable_attribute @object, 'description', nil, { 'data-emptytext' => "(No description provided)", 'data-toggle' => 'manual' } %>
+</div>
+
+<% end %>
+
+<div class="container-fluid">
+  <div class="row">
+    <div class="col-lg-4">
+      <%= link_to(
+            choose_collections_path(
+              title: 'Add data to folder:',
+              multiple: true,
+              action_name: 'Add',
+              action_href: actions_path(id: @object.uuid),
+              action_method: 'post',
+              action_data: {selection_param: 'selection[]', copy_selections_into_folder: @object.uuid, success: 'page-refresh'}.to_json),
+            { class: "btn btn-primary btn-sm", remote: true, method: 'get', data: {'event-after-select' => 'page-refresh'} }) do %>
+        <i class="fa fa-fw fa-plus"></i> Add data
+      <% end %>
+      <%= link_to(
+            choose_pipeline_templates_path(
+              title: 'Run pipeline:',
+              action_name: 'Configure...',
+              action_href: pipeline_instances_path,
+              action_method: 'post',
+              action_data: {'selection_param' => 'pipeline_instance[pipeline_template_uuid]', 'pipeline_instance[owner_uuid]' => @object.uuid, 'success' => 'redirect-to-created-object'}.to_json),
+            { class: "btn btn-primary btn-sm", remote: true, method: 'get' }) do %>
+        <i class="fa fa-fw fa-gear"></i> Run a pipeline
+      <% end %>
+    </div>
+    <div class="col-lg-4">
+      <select class="form-control" data-filter-rows-by="kind">
+        <option value="">Show everything</option>
+        <option value="arvados#collection">Data</option>
+        <option value="arvados#pipeline_instance arvados#job">Compute jobs</option>
+        <option value="arvados#pipeline_template">Pipelines</option>
+      </select>
+    </div>
+    <div class="col-lg-4">
+      <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents"/>
+    </div>
+  </div>
+</div>
+
+<table class="table table-condensed arv-index">
+  <tbody>
+    <colgroup>
+      <col width="40%" />
+      <col width="40%" />
+      <col width="10%" />
+      <col width="10%" />
+    </colgroup>
+    <% @objects_and_names.each do |object, name_link| %>
+      <tr data-object-uuid="<%= (name_link && name_link.uuid) || object.uuid %>">
+        <td>
+          <i class="fa fa-fw <%= fa_icon_class_for_object(object) %>"></i>
+          <%= render_editable_attribute name_link, 'name', nil, {data: {emptytext: "Unnamed #{object.class_for_display}"}} %>
+        </td>
+        <td>
+          <%= object.content_summary %>
+        </td>
+        <td>
+          <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
+        </td>
+        <td>
+          <% if @object.editable? %>
+            <%= link_to({action: 'remove_item', id: @object.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "Remove #{object.class_for_display} #{name_link.andand.uuid ? name_link.name : object.uuid} from this folder?"}, class: 'btn btn-xs btn-default') do %>
+              Remove <i class="fa fa-fw fa-ban"></i>
+            <% end %>
+          <% end %>
+        </td>
+      </tr>
+    <% end %>
+  </tbody>
+  <thead>
+    <tr>
+      <th>
+        name
+      </th>
+      <th>
+        description
+      </th>
+      <th>
+      </th>
+      <th>
+      </th>
+    </tr>
+  </thead>
+</table>
diff --git a/apps/workbench/app/views/folders/_show_featured.html.erb b/apps/workbench/app/views/folders/_show_featured.html.erb
new file mode 100644
index 0000000..6547b5e
--- /dev/null
+++ b/apps/workbench/app/views/folders/_show_featured.html.erb
@@ -0,0 +1,18 @@
+<div class="row">
+  <% @objects[0..3].each do |object| %>
+  <div class="card arvados-object">
+    <div class="card-top blue">
+      <a href="#">
+        <img src="/favicon.ico" alt=""/>
+      </a>
+    </div>
+    <div class="card-info">
+      <span class="title"><%= @objects.name_for(object) || object.class_for_display %></span>
+      <div class="desc"><%= object.respond_to?(:description) ? object.description : object.uuid %></div>
+    </div>
+    <div class="card-bottom">
+      <%= render :partial => "show_object_button", :locals => {object: object, htmloptions: {class: 'btn-default btn-block'}} %>
+    </div>
+  </div>
+  <% end %>
+</div>
diff --git a/apps/workbench/app/views/folders/_show_folders.html.erb b/apps/workbench/app/views/folders/_show_folders.html.erb
index 2ecfd6e..8c4f0d8 100644
--- a/apps/workbench/app/views/folders/_show_folders.html.erb
+++ b/apps/workbench/app/views/folders/_show_folders.html.erb
@@ -2,27 +2,31 @@
   <% [@my_folder_tree, @shared_folder_tree].each do |tree| %>
     <% tree.each do |foldernode| %>
       <% rowtype = foldernode[:object].class %>
-      <div class="<%= 'folder' if rowtype == Group %> row" style="padding-left: <%= 1 + foldernode[:depth] %>em;">
-        <% if rowtype == String %>
-          <i class="fa fa-fw fa-folder-open-o"></i>
-          <%= foldernode[:object] %>
-        <% elsif rowtype == User %>
-          <% if foldernode[:object].uuid == current_user.andand.uuid %>
+      <div class="<%= 'folder' if rowtype == Group %> row">
+        <div class="col-lg-4" style="padding-left: <%= 1 + foldernode[:depth] %>em;">
+          <% if rowtype == String %>
             <i class="fa fa-fw fa-folder-open-o"></i>
-            My Folders
+            <%= foldernode[:object] %>
+          <% elsif rowtype == User %>
+            <% if foldernode[:object].uuid == current_user.andand.uuid %>
+              <i class="fa fa-fw fa-folder-open-o"></i>
+              My Folders
+            <% else %>
+              <i class="fa fa-fw fa-folder-o"></i>
+              <%= foldernode[:object].friendly_link_name %>
+            <% end %>
           <% else %>
             <i class="fa fa-fw fa-folder-o"></i>
-            <%= foldernode[:object].friendly_link_name %>
+            <%= link_to foldernode[:object] do %>
+              <%= foldernode[:object].friendly_link_name %>
+            <% end %>
           <% end %>
-        <% else %>
-          <i class="fa fa-fw fa-folder-o"></i>
-          <%= link_to foldernode[:object] do %>
-            <%= foldernode[:object].friendly_link_name %>
+        </div>
+        <div class="col-lg-8 arv-description-in-table">
+          <% if rowtype == Group %>
+            <%= foldernode[:object].description %>
           <% end %>
-          <div class="pull-right">
-            <%= render partial: 'delete_object_button', locals: {object: foldernode[:object]} %>
-          </div>
-        <% end %>
+        </div>
       </div>
     <% end %>
   <% end %>
diff --git a/apps/workbench/app/views/folders/_show_permissions.html.erb b/apps/workbench/app/views/folders/_show_permissions.html.erb
new file mode 100644
index 0000000..41a7cd7
--- /dev/null
+++ b/apps/workbench/app/views/folders/_show_permissions.html.erb
@@ -0,0 +1,53 @@
+<div class="container-fluid">
+  <div class="row">
+    <div class="col-lg-6">
+      <div class="panel panel-default">
+        <div class="panel-heading">
+          Additional permissions
+        </div>
+        <div class="panel-body">
+          <p>
+            <% if not @share_links.any? %>
+              <span class="deemphasize">(No additional permissions)</span>
+            <% else %>
+              Also shared with:
+              <% @share_links.andand.each do |link| %>
+                <br /><%= link_to_if_arvados_object link.tail_uuid, friendly_name: true %>
+              <% end %>
+            <% end %>
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="col-lg-6">
+      <% if @object.owner %>
+        <div class="panel panel-default">
+          <div class="panel-heading">
+            Inherited permissions
+          </div>
+          <div class="panel-body">
+            <p>Permissions for this folder are inherited by the owner or parent folder:
+            </p>
+            <p style="margin-left: 4em">
+              <% if User == resource_class_for_uuid(@object.owner_uuid) %>
+                <i class="fa fa-fw fa-user"></i>
+              <% else %>
+                <i class="fa fa-fw fa-folder"></i>
+              <% end %>
+              <%= link_to_if_arvados_object @object.owner_uuid, friendly_name: true %>
+              <%= button_to('Move to...',
+                  choose_folders_path(
+                   title: 'Move to...',
+                   editable: true,
+                   action_name: 'Move',
+                   action_href: folder_path(@object.uuid),
+                   action_method: 'put',
+                   action_data: {selection_param: 'folder[owner_uuid]', success: 'page-refresh'}.to_json),
+                  { class: "btn btn-default btn-xs arv-move-to-folder", remote: true, method: 'get' }) %>
+            </p>
+          </div>
+        </div>
+      <% end %>
+    </div>
+  </div>
+</div>
diff --git a/apps/workbench/app/views/folders/show.html.erb b/apps/workbench/app/views/folders/show.html.erb
deleted file mode 100644
index ebf504e..0000000
--- a/apps/workbench/app/views/folders/show.html.erb
+++ /dev/null
@@ -1,214 +0,0 @@
-<div class="row row-fill-height">
-  <div class="col-md-6">
-    <div class="panel panel-info">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          <%= render_editable_attribute @object, 'name', nil, {data: {emptytext: "New folder"}} %>
-        </h3>
-      </div>
-      <div class="panel-body">
-        <img src="/favicon.ico" class="pull-right" alt="" style="opacity: 0.3"/>
-        <%= render_editable_attribute @object, 'description', nil, { 'data-emptytext' => "Created: #{@object.created_at.to_s(:long)}", 'data-toggle' => 'manual', 'id' => "#{@object.uuid}-description" } %>
-        <% if @object.attribute_editable? 'description' %>
-        <div style="margin-top: 1em;">
-          <a href="#" class="btn btn-xs btn-default" data-toggle="x-editable" data-toggle-selector="#<%= @object.uuid %>-description"><i class="fa fa-fw fa-pencil"></i> Edit description</a>
-        </div>
-        <% end %>
-      </div>
-    </div>
-  </div>
-  <div class="col-md-3">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          Activity
-        </h3>
-      </div>
-      <div class="panel-body smaller-text">
-        <!--
-        <input type="text" class="form-control" placeholder="Search"/>
-        -->
-        <div style="height:0.5em;"></div>
-        <% if @logs.any? %>
-          <%= render_arvados_object_list_start(@logs, 'Show all activity',
-                logs_path(filters: [['object_uuid','=', at object.uuid]].to_json)) do |log| %>
-          <p>
-          <%= time_ago_in_words(log.event_at) %> ago: <%= log.summary %>
-            <% if log.object_uuid %>
-            <%= link_to_if_arvados_object log.object_uuid, link_text: raw('<i class="fa fa-hand-o-right"></i>') %>
-            <% end %>
-          </p>
-          <% end %>
-        <% else %>
-          <p>
-            Created: <%= @object.created_at.to_s(:long) %>
-          </p>
-          <p>
-            Last modified: <%= @object.modified_at.to_s(:long) %> by <%= link_to_if_arvados_object @object.modified_by_user_uuid, friendly_name: true %>
-          </p>
-        <% end %>
-      </div>
-    </div>
-  </div>
-  <div class="col-md-3">
-    <div class="panel panel-default">
-      <div class="panel-heading">
-        <h3 class="panel-title">
-          Sharing and permissions
-        </h3>
-      </div>
-      <div class="panel-body">
-        <!--
-        <input type="text" class="form-control" placeholder="Search"/>
-        -->
-        <div style="height:0.5em;"></div>
-        <% if @object.owner %>
-          <p>Permissions inherited from:
-            <br />
-            <% if User == resource_class_for_uuid(@object.owner_uuid) %>
-              <i class="fa fa-fw fa-user"></i>
-            <% else %>
-              <i class="fa fa-fw fa-folder"></i>
-            <% end %>
-            <%= link_to_if_arvados_object @object.owner_uuid, friendly_name: true %>
-            <%= button_to('Move to...',
-                choose_folders_path(
-                 title: 'Move to...',
-                 editable: true,
-                 action_name: 'Move',
-                 action_href: folder_path(@object.uuid),
-                 action_method: 'put',
-                 action_data: {selection_param: 'folder[owner_uuid]'}.to_json),
-                { class: "btn btn-default btn-xs arv-move-to-folder", remote: true, method: 'get' }) %>
-          </p>
-          <hr />
-        <% end %>
-        <p>
-          <% if not @share_links.any? %>
-            <span class="deemphasize">(No additional permissions)</span>
-          <% else %>
-            Also shared with:
-            <% @share_links.andand.each do |link| %>
-              <br /><%= link_to_if_arvados_object link.tail_uuid, friendly_name: true %>
-            <% end %>
-          <% end %>
-        </p>
-      </div>
-    </div>
-  </div>
-</div>
-
-<% if @show_cards %>
-<!-- disable cards section until we have bookmarks -->
-<div class="row">
-  <% @objects[0..3].each do |object| %>
-  <div class="card arvados-object">
-    <div class="card-top blue">
-      <a href="#">
-        <img src="/favicon.ico" alt=""/>
-      </a>
-    </div>
-    <div class="card-info">
-      <span class="title"><%= @objects.name_for(object) || object.class_for_display %></span>
-      <div class="desc"><%= object.respond_to?(:description) ? object.description : object.uuid %></div>
-    </div>
-    <div class="card-bottom">
-      <%= render :partial => "show_object_button", :locals => {object: object, htmloptions: {class: 'btn-default btn-block'}} %>
-    </div>
-  </div>
-  <% end %>
-</div>
-<!-- end disabled cards section -->
-<% end %>
-
-<div class="row">
-  <div class="col-md-12">
-    <div class="panel panel-info">
-      <div class="panel-heading">
-        <div class="row">
-          <div class="col-md-6">
-            <h3 class="panel-title" style="vertical-align:middle;">
-              Contents
-            </h3>
-          </div>
-          <div class="col-md-6">
-            <div class="input-group input-group-sm pull-right">
-              <input type="text" class="form-control search-folder-contents" placeholder="Search folder contents"/>
-            </div>
-          </div>
-        </div>
-      </div>
-      <div class="panel-body">
-        <p>
-        </p>
-        <table class="table table-condensed arv-index">
-          <tbody>
-            <colgroup>
-              <col width="3%" />
-              <col width="8%" />
-              <col width="30%" />
-              <col width="15%" />
-              <col width="15%" />
-              <col width="20%" />
-              <col width="8%" />
-            </colgroup>
-            <% @objects_and_names.each do |object, name_link| %>
-              <tr data-object-uuid="<%= (name_link && name_link.uuid) || object.uuid %>">
-                <td>
-                  <%= render :partial => "selection_checkbox", :locals => {object: object} %>
-                </td>
-                <td>
-                  <%= render :partial => "show_object_button", :locals => {object: object, size: 'xs'} %>
-                </td>
-                <td>
-                  <%= render_editable_attribute name_link, 'name', nil, {data: {emptytext: "Unnamed #{object.class_for_display}"}} %>
-                </td>
-                <td>
-                  <%= object.content_summary %>
-                </td>
-                <td title="<%= object.modified_at %>">
-                  <span>
-                    <%= raw distance_of_time_in_words(object.modified_at, Time.now).sub('about ','~').sub(' ',' ') + ' ago' rescue object.modified_at %>
-                  </span>
-                </td>
-                <td class="arvados-uuid">
-                  <%= object.uuid %>
-                </td>
-                <td>
-                  <% if @object.editable? %>
-                    <%= link_to({action: 'remove_item', id: @object.uuid, item_uuid: ((name_link && name_link.uuid) || object.uuid)}, method: :delete, remote: true, data: {confirm: "You are about to remove #{object.class_for_display} #{object.uuid} from this folder.\n\nAre you sure?"}, class: 'btn btn-xs btn-default') do %>
-                      Remove <i class="fa fa-fw fa-ban"></i>
-                    <% end %>
-                  <% end %>
-                </td>
-              </tr>
-            <% end %>
-          </tbody>
-          <thead>
-            <tr>
-              <th>
-              </th>
-              <th>
-              </th>
-              <th>
-                name
-              </th>
-              <th>
-                type
-              </th>
-              <th>
-                modified
-              </th>
-              <th>
-                uuid
-              </th>
-              <th>
-              </th>
-            </tr>
-          </thead>
-        </table>
-        <p></p>
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/apps/workbench/app/views/layouts/application.html.erb b/apps/workbench/app/views/layouts/application.html.erb
index d3ea5b0..6e3618e 100644
--- a/apps/workbench/app/views/layouts/application.html.erb
+++ b/apps/workbench/app/views/layouts/application.html.erb
@@ -48,7 +48,7 @@
     }
     }
   </style>
-  <link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">
+  <link href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.css" rel="stylesheet">
 </head>
 <body>
   <div id="wrapper">
@@ -64,77 +64,6 @@
       </div>
 
       <div class="collapse navbar-collapse">
-        <% if current_user.andand.is_active %>
-          <ul class="nav navbar-nav side-nav">
-
-            <li class="<%= 'arvados-nav-active' if params[:action] == 'home' %>">
-              <a href="/"><i class="fa fa-lg fa-dashboard fa-fw"></i> Dashboard</a>
-            </li>
-
-            <li class="dropdown">
-              <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-lg fa-hand-o-up fa-fw"></i> Help <b class="caret"></b></a>
-              <ul class="dropdown-menu">
-                <li><%= link_to raw('<i class="fa fa-book fa-fw"></i> Tutorials and User guide'), "#{Rails.configuration.arvados_docsite}/user", target: "_blank" %></li>
-                <li><%= link_to raw('<i class="fa fa-book fa-fw"></i> API Reference'), "#{Rails.configuration.arvados_docsite}/api", target: "_blank" %></li>
-                <li><%= link_to raw('<i class="fa fa-book fa-fw"></i> SDK Reference'), "#{Rails.configuration.arvados_docsite}/sdk", target: "_blank" %></li>
-              </ul>
-            </li>
-
-            <li class="dropdown">
-              <a href="/folders">
-                <i class="fa fa-lg fa-folder-o fa-fw"></i> Folders
-            </a></li>
-            <li><a href="/collections">
-                <i class="fa fa-lg fa-briefcase fa-fw"></i> Collections (data files)
-            </a></li>
-            <li><a href="/jobs">
-                <i class="fa fa-lg fa-tasks fa-fw"></i> Jobs
-            </a></li>
-            <li><a href="/pipeline_instances">
-                <i class="fa fa-lg fa-tasks fa-fw"></i> Pipeline instances
-            </a></li>
-            <li><a href="/pipeline_templates">
-                <i class="fa fa-lg fa-gears fa-fw"></i> Pipeline templates
-            </a></li>
-            <li> </li>
-            <li><a href="/repositories">
-                <i class="fa fa-lg fa-code-fork fa-fw"></i> Repositories
-            </a></li>
-            <li><a href="/virtual_machines">
-                <i class="fa fa-lg fa-terminal fa-fw"></i> Virtual machines
-            </a></li>
-            <li><a href="/humans">
-                <i class="fa fa-lg fa-male fa-fw"></i> Humans
-            </a></li>
-            <li><a href="/specimens">
-                <i class="fa fa-lg fa-flask fa-fw"></i> Specimens
-            </a></li>
-            <li><a href="/traits">
-                <i class="fa fa-lg fa-clipboard fa-fw"></i> Traits
-            </a></li>
-            <li><a href="/links">
-                <i class="fa fa-lg fa-arrows-h fa-fw"></i> Links
-            </a></li>
-            <% if current_user.andand.is_admin %>
-              <li><a href="/users">
-                  <i class="fa fa-lg fa-user fa-fw"></i> Users
-              </a></li>
-            <% end %>
-            <li><a href="/groups">
-                <i class="fa fa-lg fa-users fa-fw"></i> Groups
-            </a></li>
-            <li><a href="/nodes">
-                <i class="fa fa-lg fa-cloud fa-fw"></i> Compute nodes
-            </a></li>
-            <li><a href="/keep_services">
-                <i class="fa fa-lg fa-exchange fa-fw"></i> Keep services
-            </a></li>
-            <li><a href="/keep_disks">
-                <i class="fa fa-lg fa-hdd-o fa-fw"></i> Keep disks
-            </a></li>
-          </ul>
-        <% end %>
-
         <ul class="nav navbar-nav navbar-left breadcrumbs">
           <% if current_user %>
             <% if content_for?(:breadcrumbs) %>
@@ -153,11 +82,6 @@
                 <li>
                   <%= link_to_if_arvados_object @object, {friendly_name: true}, {data: {object_uuid: @object.andand.uuid, name: 'name'}} %>
                 </li>
-                <li style="padding: 14px 0 14px">
-                  <%= form_tag do |f| %>
-                    <%= render :partial => "selection_checkbox", :locals => {:object => @object} %>
-                  <% end %>
-                </li>
               <% end %>
             <% end %>
           <% end %>
@@ -230,6 +154,44 @@
               <li role="presentation"><a href="<%= logout_path %>" role="menuitem"><i class="fa fa-sign-out fa-fw"></i> Log out</a></li>
             </ul>
           </li>
+
+          <% if current_user.is_active %>
+            <li class="dropdown">
+              <a href="#" class="dropdown-toggle" data-toggle="dropdown" id="system-menu">
+                <span class="glyphicon glyphicon-cog"></span><span class="caret"></span>
+              </a>
+              <ul class="dropdown-menu" role="menu">
+                <li role="presentation" class="dropdown-header">System objects</li>
+                <li role="presentation" class="divider"></li>
+                <li role="presentation"><a href="/repositories">
+                    <i class="fa fa-lg fa-code-fork fa-fw"></i> Repositories
+                </a></li>
+                <li role="presentation"><a href="/virtual_machines">
+                    <i class="fa fa-lg fa-terminal fa-fw"></i> Virtual machines
+                </a></li>
+                <li role="presentation"><a href="/links">
+                    <i class="fa fa-lg fa-arrows-h fa-fw"></i> Links
+                </a></li>
+                <% if current_user.andand.is_admin %>
+                  <li role="presentation"><a href="/users">
+                      <i class="fa fa-lg fa-user fa-fw"></i> Users
+                  </a></li>
+                <% end %>
+                <li role="presentation"><a href="/groups">
+                    <i class="fa fa-lg fa-users fa-fw"></i> Groups
+                </a></li>
+                <li role="presentation"><a href="/nodes">
+                    <i class="fa fa-lg fa-cloud fa-fw"></i> Compute nodes
+                </a></li>
+                <li role="presentation"><a href="/keep_services">
+                    <i class="fa fa-lg fa-exchange fa-fw"></i> Keep services
+                </a></li>
+                <li role="presentation"><a href="/keep_disks">
+                    <i class="fa fa-lg fa-hdd-o fa-fw"></i> Keep disks
+                </a></li>
+              </ul>
+            </li>
+          <% end %>
           <% else %>
             <li><a href="<%= arvados_api_client.arvados_login_url(return_to: root_url) %>">Log in</a></li>
           <% end %>
diff --git a/apps/workbench/app/views/pipeline_templates/_choose.js.erb b/apps/workbench/app/views/pipeline_templates/_choose.js.erb
new file mode 120000
index 0000000..8420a7f
--- /dev/null
+++ b/apps/workbench/app/views/pipeline_templates/_choose.js.erb
@@ -0,0 +1 @@
+../application/_choose.js.erb
\ No newline at end of file
diff --git a/apps/workbench/app/views/pipeline_templates/_choose_rows.html.erb b/apps/workbench/app/views/pipeline_templates/_choose_rows.html.erb
new file mode 100644
index 0000000..0e8c32f
--- /dev/null
+++ b/apps/workbench/app/views/pipeline_templates/_choose_rows.html.erb
@@ -0,0 +1,11 @@
+<% @objects.each do |object| %>
+  <div class="row selectable <%= 'multiple' if multiple %>" data-object-uuid="<%= object.uuid %>">
+    <div class="col-md-6" style="overflow-x:hidden">
+      <i class="fa fa-fw fa-gear"></i>
+      <%= object.name %>
+    </div>
+    <div class="col-md-6 arv-description-in-table">
+      <%= object.description %>
+    </div>
+  </div>
+<% end %>
diff --git a/apps/workbench/config/routes.rb b/apps/workbench/config/routes.rb
index b4da656..a28cc69 100644
--- a/apps/workbench/config/routes.rb
+++ b/apps/workbench/config/routes.rb
@@ -35,7 +35,9 @@ ArvadosWorkbench::Application.routes.draw do
   resources :uploaded_datasets
   resources :groups
   resources :specimens
-  resources :pipeline_templates
+  resources :pipeline_templates do
+    get 'choose', on: :collection
+  end
   resources :pipeline_instances do
     get 'compare', on: :collection
   end
@@ -46,6 +48,7 @@ ArvadosWorkbench::Application.routes.draw do
     get 'sharing_popup', :on => :member
     post 'share', :on => :member
     post 'unshare', :on => :member
+    get 'choose', on: :collection
   end
   get('/collections/download/:uuid/:reader_token/*file' => 'collections#show_file',
       format: false)

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list