3504: Fix collection page rendering to work with collections as regular uuids.
authorPeter Amstutz <peter.amstutz@curoverse.com>
Tue, 19 Aug 2014 03:13:19 +0000 (23:13 -0400)
committerPeter Amstutz <peter.amstutz@curoverse.com>
Tue, 19 Aug 2014 03:13:19 +0000 (23:13 -0400)
Render tags onn project page.  Improve helper function for rendering links to
Arvados objects.

19 files changed:
apps/workbench/app/assets/javascripts/application.js
apps/workbench/app/assets/stylesheets/projects.css.scss
apps/workbench/app/controllers/collections_controller.rb
apps/workbench/app/controllers/projects_controller.rb
apps/workbench/app/helpers/application_helper.rb
apps/workbench/app/models/arvados_base.rb
apps/workbench/app/models/collection.rb
apps/workbench/app/views/application/_arvados_attr_value.html.erb
apps/workbench/app/views/application/_arvados_object_attr.html.erb
apps/workbench/app/views/application/_show_attributes.html.erb
apps/workbench/app/views/application/_show_recent.html.erb
apps/workbench/app/views/application/show.html.erb
apps/workbench/app/views/collections/_index_tbody.html.erb
apps/workbench/app/views/collections/_show_files.html.erb
apps/workbench/app/views/collections/_show_source_summary.html.erb
apps/workbench/app/views/collections/_toggle_persist.html.erb [deleted file]
apps/workbench/app/views/collections/show.html.erb
apps/workbench/app/views/links/_recent.html.erb [deleted file]
apps/workbench/app/views/projects/_show_contents_rows.html.erb

index c4cb68322f1454aac3220d8bfc0fba02a7246e86..cf0812adae935d955a60b09719e8545dc1efbe8e 100644 (file)
@@ -107,12 +107,12 @@ jQuery(function($){
                 attr('data-tag-link-uuid', new_tag_uuid).
                 text(new_tag).
                 css('opacity', '0.2').
-                append('&nbsp;<a title="Delete tag"><i class="glyphicon glyphicon-trash"></i></a>&nbsp;');
+                append('&nbsp;<span class="removable-tag"><a title="Delete tag"><i class="fa fa-fw fa-trash-o"></i></a></span>');
             $(this).
                 parent().
                 find('>span').
                 append(new_tag_span).
-                append('&nbsp; ');
+                append(' ');
             $.ajax($(this).attr('data-remote-href'),
                            {dataType: 'json',
                             type: $(this).attr('data-remote-method'),
index 53b352d5e798a0abaf1acebdd79dc4c2a866f1f6..a453a544824dc096b36cdc3612aade6345e00759 100644 (file)
@@ -10,3 +10,9 @@ div.scroll-20em {
     height: 20em;
     overflow-y: scroll;
 }
+.label-info a {
+    color: white;
+}
+.removable-tag:hover {
+    cursor: pointer;
+}
\ No newline at end of file
index bea72a4274b9d8748bffbbde9a3e7937ef616879..4003faece87778dd9cdef746be5cd25c250a12ec 100644 (file)
@@ -160,8 +160,8 @@ class CollectionsController < ApplicationController
         Job.limit(RELATION_LIMIT).where(conds)
           .results.sort_by { |j| j.finished_at || j.created_at }
       end
-      @output_of = jobs_with.call(output: @object.uuid)
-      @log_of = jobs_with.call(log: @object.uuid)
+      @output_of = jobs_with.call(output: @object.portable_data_hash)
+      @log_of = jobs_with.call(log: @object.portable_data_hash)
       @project_links = Link.limit(RELATION_LIMIT).order("modified_at DESC")
         .where(head_uuid: @object.uuid, link_class: 'name').results
       project_hash = Group.where(uuid: @project_links.map(&:tail_uuid)).to_hash
index 6287793f765bf82ddd0e15e3037f7a11c7d3c05a..a45c740a5d923e0790221ccd057bd880fe02dd20 100644 (file)
@@ -176,6 +176,13 @@ class ProjectsController < ApplicationController
                                   filters: @filters,
                                   offset: @offset)
       @next_page_href = next_page_href(partial: :contents_rows)
+
+      uuids = @objects.map { |ob| ob.uuid }
+      @object_tags = {}
+      Link.limit(uuids.length*20).filter([["head_uuid", "in", uuids], ["link_class", "=", "tag"]]).each do |t|
+        @object_tags[t.head_uuid] ||= []
+        @object_tags[t.head_uuid] << t
+      end
     end
   end
 
index 428c14f8282961f65e6ad69e9197794f62997d54..78727923070ae66d2c1051b03bd31ea399370e35 100644 (file)
@@ -87,6 +87,7 @@ module ApplicationHelper
         link_uuid = attrvalue
       end
       link_name = opts[:link_text]
+      tags = ""
       if !link_name
         link_name = object.andand.default_name || resource_class.default_name
 
@@ -112,7 +113,9 @@ module ApplicationHelper
         if !opts[:no_tags] and resource_class == Collection
           links_for_object(link_uuid).each do |tag|
             if tag.link_class.in? ["tag", "identifier"]
-              link_name += ' <span class="label label-info">' + html_escape(tag.name) + '</span>'
+              tags += ' <span class="label label-info">'
+              tags += link_to tag.name, controller: "links", filters: [["link_class", "=", "tag"], ["name", "=", tag.name]].to_json
+              tags += '</span>'
             end
           end
         end
@@ -130,11 +133,18 @@ module ApplicationHelper
       if opts[:no_link]
         raw(link_name)
       else
-        link_to raw(link_name), { controller: resource_class.to_s.tableize, action: 'show', id: ((opts[:name_link].andand.uuid) || link_uuid) }, style_opts
+        if link_name.nil? or link_name.empty?
+          link_name = "(unnamed)"
+        end
+        (link_to raw(link_name), { controller: resource_class.to_s.tableize, action: 'show', id: ((opts[:name_link].andand.uuid) || link_uuid) }, style_opts) + raw(tags)
       end
     else
       # just return attrvalue if it is not recognizable as an Arvados object or uuid.
-      attrvalue
+      if attrvalue.nil? or (attrvalue.is_a? String and attrvalue.empty?)
+        "(none)"
+      else
+        attrvalue
+      end
     end
   end
 
@@ -176,11 +186,13 @@ module ApplicationHelper
     @unique_id ||= (Time.now.to_f*1000000).to_i
     span_id = object.uuid.to_s + '-' + attr.to_s + '-' + (@unique_id += 1).to_s
 
+    puts "Span #{object.inspect} #{(object.andand.default_name || 'none')}"
+
     span_tag = content_tag 'span', attrvalue.to_s, {
-      "data-emptytext" => (object.andand.default_name || 'none'),
+      "data-emptytext" => ('(none)'),
       "data-placement" => "bottom",
       "data-type" => input_type,
-      "data-title" => "Edit #{attr.gsub '_', ' '}",
+      "data-title" => "Edit #{attr.to_s.gsub '_', ' '}",
       "data-name" => attr,
       "data-object-uuid" => object.uuid,
       "data-toggle" => "manual",
index 1dac43fa61a7ffbd2c100b3f932b4568f174ee73..c0e670dcefe65b6e0aa4d053b7c07cbf432813bb 100644 (file)
@@ -320,7 +320,7 @@ class ArvadosBase < ActiveRecord::Base
   end
 
   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)
+    if %w(created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).include? attr.to_s
       false
     elsif not (current_user.andand.is_active)
       false
index 764817509ac98ccb936a9d1d162758ef7da7cef4..1f3e0dc5ac41a0ef1cc07fbc77e67ac0fcc95b37 100644 (file)
@@ -57,7 +57,11 @@ class Collection < ArvadosBase
   end
 
   def attribute_editable? attr, *args
-    false
+    if %w(name description manifest_text).include? attr.to_s
+      true
+    else
+      super
+    end
   end
 
   def self.creatable?
@@ -72,4 +76,28 @@ class Collection < ArvadosBase
     arvados_api_client.api "collections/#{self.uuid}/", "used_by"
   end
 
+  def uuid
+    if self[:uuid].nil?
+      return self.portable_data_hash
+    else
+      super
+    end
+  end
+
+  def portable_data_hash
+    if self[:portable_data_hash].nil?
+      return self.uuid
+    else
+      super
+    end
+  end
+
+  def friendly_link_name
+    if self.respond_to? :name
+      self.name
+    else
+      self.portable_data_hash
+    end
+  end
+
 end
index 8f82b0469638b535ff86a7ff55b87d92277a05d9..52c46fbe2f9e0821fe8bbba8621814b6a4c05ce5 100644 (file)
@@ -4,11 +4,11 @@
   <% end %>
 <% else %>
       <% 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 />
-        (<%= link_to_if_arvados_object attrvalue, {referring_attr: attr, referring_object: obj, with_class_name: true, friendly_name: true} %>)
+          <%= link_to_if_arvados_object attrvalue, {referring_attr: attr, referring_object: obj, with_class_name: true, friendly_name: true} %>
+          <br>
         <% end %>
+        <%= render_editable_attribute obj, attr %>
       <% elsif attr == 'uuid' %>
         <%= link_to_if_arvados_object attrvalue, {referring_attr: attr, referring_object: obj, with_class_name: false, friendly_name: false} %>
       <% else %>
index d7e126ef84ae1f7eca8c3b1278e4a3c7f2c5f0d6..b06dd8c7569dbf1e013c725395625d6381643bd1 100644 (file)
@@ -8,7 +8,7 @@
 </tr>
 <% end %>
 <% elsif attrvalue.is_a? String or attrvalue.respond_to? :to_s %>
-<tr class="<%= 'info' if %w(uuid owner_uuid created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).index(attr.to_s).nil? %>">
+<tr class="<%= 'info' if %w(uuid owner_uuid created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).include?(attr.to_s) %>">
   <td><%= attr %></td>
   <td>
     <%= render partial: 'application/arvados_attr_value', locals: { obj: object, attr: attr, attrvalue: attrvalue } %>
index 965ec5a29eb86632b3321eee22173c5ac07835b0..a2e05484ac4b22a1f5fa598d76f256ce44594d40 100644 (file)
@@ -4,10 +4,16 @@
   </thead>
   <tbody>
     <% @object.attributes_for_display.each do |attr, attrvalue| %>
-    <%= render partial: 'application/arvados_object_attr', locals: { attr: attr, attrvalue: attrvalue } %>
+      <% if %w(uuid owner_uuid created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).include? attr.to_s %>
+        <%= render partial: 'application/arvados_object_attr', locals: { attr: attr, attrvalue: attrvalue } %>
+      <% end %>
+    <% end %>
+    <% @object.attributes_for_display.each do |attr, attrvalue| %>
+      <% if not %w(uuid owner_uuid created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at).include? attr.to_s %>
+        <%= render partial: 'application/arvados_object_attr', locals: { attr: attr, attrvalue: attrvalue } %>
+        <% end %>
     <% end %>
   </tbody>
 </table>
 
 <% end %>
-
index d94dd84be4d3a13b7da3b6facfb4264b39b7284a..57a5b74e93469c96232000d05bf83ac561b3aa66 100644 (file)
@@ -6,7 +6,7 @@
 
 <% else %>
 
-<% attr_blacklist = ' created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at owner_uuid group_class' %>
+<% attr_blacklist = ' created_at modified_at modified_by_user_uuid modified_by_client_uuid updated_at owner_uuid group_class properties' %>
 
 <%= render partial: "paging", locals: {results: objects, object: @object} %>
 
@@ -30,7 +30,7 @@
       </th>
     </tr>
   </thead>
-      
+
   <tbody>
     <% objects.each do |object| %>
     <tr data-object-uuid="<%= object.uuid %>">
       <% next if attr_blacklist.index(" "+attr) %>
       <td class="arv-object-<%= object.class.to_s %> arv-attr-<%= attr %>">
         <% if attr == 'uuid' %>
-        <span class="arvados-uuid"><%= attrvalue %></span>
-        <% else %>
-        <% if object.attribute_editable? attr %>
-        <%= render_editable_attribute object, attr %>
+          <span class="arvados-uuid"><%= attrvalue %></span>
         <% else %>
-        <%= resource_class_for_uuid(attrvalue, referring_attr: attr, referring_object: @object).to_s %>
-        <%= attrvalue %>
-        <% end %>
-        <%= link_to_if_arvados_object(attrvalue, { referring_object: @object, link_text: raw('<i class="icon-hand-right"></i>') }) if resource_class_for_uuid(attrvalue, {referring_object: @object}) %>
+          <%= link_to_if_arvados_object attrvalue, {referring_attr: attr, referring_object: object, with_class_name: true, friendly_name: true} %>
         <% end %>
       </td>
       <% end %>
index 105e1c356d69f140cc7bcc6cbf0a4069a9be2e61..97922e8331ad03d644ac0575baae8b9c2f133927 100644 (file)
@@ -1,18 +1,18 @@
 <% content_for :page_title do %>
-  <%= (@object.respond_to?(:properties) ? @object.properties[:page_title] : nil) ||
+  <%= (@object.respond_to?(:properties) and !@object.properties.nil? ? @object.properties[:page_title] : nil) ||
       @name_link.andand.name ||
       @object.friendly_link_name %>
 <% end %>
 
 <% content_for :content_top do %>
 
-<% if @object.respond_to? :properties %>
+<% if @object.respond_to? :properties and !@object.properties.nil? %>
   <% if @object.properties[:page_content] %>
     <% content_for :page_content do %>
       <h1>
         <%= render_content_from_database(@object.properties[:page_title] || @object.uuid) %>
       </h1>
-      
+
       <% if @object.properties[:page_subtitle] %>
         <h4>
           <%= render_content_from_database @object.properties[:page_subtitle] %>
index ec5a09e3c6a8a1c676cabb74d0f9fc40e75c2770..3d5c1c7a5899213fafb6bec3ab2909b18ac77e5f 100644 (file)
   <td>
     <%= c.created_at.to_s if c.created_at %>
   </td>
-  <td>
-    <% current_state = @collection_info[c.uuid][:wanted_by_me] ? 'persistent' : 'cache' %>
-    <%= render partial: 'toggle_persist', locals: { uuid: c.uuid, current_state: current_state } %>
-  </td>
   <td class="add-tag-button">
     <a class="btn btn-xs btn-info add-tag-button pull-right" data-remote-href="<%= url_for(controller: 'links', action: 'create') %>" data-remote-method="post"><i class="glyphicon glyphicon-plus"></i>&nbsp;Add</a>
     <span class="removable-tag-container">
index ea55577e7077a28d464975dc49b60a8d50b54900..d888b2e859b564c2cedba38ad60e0801d567e718 100644 (file)
@@ -18,7 +18,7 @@
       <ul class="collection_files">
     <% else %>
       <% link_params = {controller: 'collections', action: 'show_file',
-                        uuid: @object.uuid, file: file_path, size: size} %>
+                        uuid: @object.portable_data_hash, file: file_path, size: size} %>
        <div class="collection_files_row">
         <div class="collection_files_buttons pull-right">
           <%= raw(human_readable_bytes_html(size)) %>
@@ -28,7 +28,7 @@
                 :friendly_type => "File",
                 :friendly_name => "#{@object.uuid}/#{file_path}",
                 :href => url_for(controller: 'collections', action: 'show_file',
-                                 uuid: @object.uuid, file: file_path),
+                                 uuid: @object.portable_data_hash, file: file_path),
                 :title => "Include #{file_path} in your selections",
               } %>
           <% end %>
index e3f29952ff29fe58c62bf173ab3a982f7ac2c904..7479a3066ba64d216b2f1b4da1f675be3a1051bd 100644 (file)
@@ -1,3 +1,12 @@
+<% if @object.uuid.match /[0-9a-f]{32}/ %>
+<p>Found in collections:<p>
+<p>
+<% cols = Collection.filter([["portable_data_hash", "=", @object.portable_data_hash]]).each do |c| %>
+  <%= link_to_if_arvados_object c.owner_uuid, {:friendly_name => true} %> / <%= link_to_if_arvados_object c, {:friendly_name => true} %><br>
+<% end %>
+</p>
+<% end %>
+
 <% if not (@output_of.andand.any? or @log_of.andand.any?) %>
   <p><i>No source information available.</i></p>
 <% end %>
diff --git a/apps/workbench/app/views/collections/_toggle_persist.html.erb b/apps/workbench/app/views/collections/_toggle_persist.html.erb
deleted file mode 100644 (file)
index aa6ed81..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-<div class="btn-group btn-group-xs toggle-persist" data-remote-href="<%= set_persistent_collection_path(id: uuid) %>" data-persistent-state="<%= current_state %>">
-  <button type="button" class="btn btn-info <%= 'active' if current_state == 'persistent' %>"><%= current_state.capitalize %></button>
-</div>
index 83dcb4511bfbc36aaae6910492c48e777bcd9cf0..ee809d60d38dd4bbfe804a3f103e176ab7b69210 100644 (file)
@@ -3,14 +3,17 @@
     <div class="panel panel-info">
       <div class="panel-heading">
        <h3 class="panel-title">
-         <%= @name_link.andand.name || @object.uuid %>
+         <%= if @object.respond_to? :name
+                render_editable_attribute @object, :name
+              else
+                @name_link.andand.name || @object.uuid
+              end%>
        </h3>
       </div>
       <div class="panel-body">
         <img src="/favicon.ico" class="pull-right" alt="" style="opacity: 0.3"/>
        <p><i>Content hash:</i><br />
-         <span class="arvados-uuid"><%= @object.uuid %></span></p>
-
+         <span class="arvados-uuid"><%= link_to @object.portable_data_hash, collection_path(@object.portable_data_hash) %></span></p>
         <%= render partial: "show_source_summary" %>
       </div>
     </div>
         <% name_or_object = @name_link.andand.uuid ? @name_link : @object %>
         <% if name_or_object.created_at and not @logs.andand.any? %>
           <p>
-            Created: <%= name_or_object.created_at.to_s(:long) %>
+            Created: <%= name_or_object.created_at.to_s(:long) if name_or_object.created_at %>
           </p>
           <p>
-            Last modified: <%= name_or_object.modified_at.to_s(:long) %> by <%= link_to_if_arvados_object name_or_object.modified_by_user_uuid, friendly_name: true %>
+            Last modified: <%= name_or_object.modified_at.to_s(:long) if name_or_object.modified_at %> by <%= link_to_if_arvados_object name_or_object.modified_by_user_uuid, friendly_name: true %>
           </p>
         <% else %>
           <%= render_arvados_object_list_start(@logs, 'Show all activity',
@@ -90,9 +93,4 @@
   </div>
 </div>
 
-<% content_for :tab_line_buttons do %>
-  <span style="padding-left: 1em">Collection storage status:</span>
-  <%= render partial: 'toggle_persist', locals: { uuid: @object.uuid, current_state: (@is_persistent ? 'persistent' : 'cache') } %>
-<% end %>
-
 <%= render file: 'application/show.html.erb', locals: local_assigns %>
diff --git a/apps/workbench/app/views/links/_recent.html.erb b/apps/workbench/app/views/links/_recent.html.erb
deleted file mode 100644 (file)
index 1e60bf5..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<table class="table">
-  <thead>
-    <tr class="contain-align-left">
-      <th>
-       id
-      </th><th>
-       class
-      </th><th>
-       name
-      </th><th>
-       tail
-      </th><th>
-       head
-      </th><th>
-       properties
-      </th><th>
-      </th>
-    </tr>
-  </thead>
-  <tbody>
-
-    <% @objects.sort_by { |link| link[:created_at] }.each do |link| %>
-
-    <tr>
-      <td>
-        <%= link_to_if_arvados_object link %>
-      </td><td>
-        <%= render_editable_attribute link, 'link_class' %>
-      </td><td>
-        <%= render_editable_attribute link, 'name' %>
-      </td><td>
-        <%= render_editable_attribute link, 'tail_uuid' %>
-      </td><td>
-        <%= render_editable_attribute link, 'head_uuid' %>
-      </td><td>
-        <%= link.properties %>
-      </td>
-
-      <td>
-        <% if current_user and (current_user.is_admin or current_user.uuid == link.owner_uuid) %>
-        <%= link_to raw('<i class="glyphicon glyphicon-trash"></i>'), { action: 'destroy', id: link.uuid }, data: {confirm: 'Delete this link?', method: 'delete'} %>
-        <% end %>
-      </td>
-
-    </tr>
-
-    <% end %>
-    <% if @objects.count == 0 %>
-    <tr>
-      <td colspan="7">
-        (no links)
-      </td>
-    </tr>
-    <% end %>
-
-  </tbody>
-</table>
index e1996a7f406f2700dbfb291b07cd1d7962d6164e..a1c8fe8207da95b95360c8fc1942a51c2b39e92d 100644 (file)
 
     <td>
       <%= render_editable_attribute (name_link || object), 'name', nil, {tiptitle: 'rename'} %>
+      <br>
+      <span class="tags-span">
+    <span class="removable-tag-container">
+    <% if @object_tags[object.uuid] %>
+      <% @object_tags[object.uuid].each do |tag_link| %>
+        <span class="label label-info" data-tag-link-uuid="<%= tag_link.uuid %>">
+          <%= link_to tag_link.name, controller: "links", filters: [["link_class", "=", "tag"], ["name", "=", tag_link.name]].to_json %>
+          <% if tag_link.owner_uuid == current_user.uuid or current_user.is_admin %>
+            <span class="removable-tag">
+              &nbsp;<a title="Delete tag"><i class="fa fa-fw fa-trash-o"></i></a>
+            </span>
+          <% end %>
+        </span>&nbsp;
+      <% end %>
+    <% end %>
+    </span>
+    <a class="btn btn-xs btn-info add-tag-button" data-remote-href="<%= url_for(controller: 'links', action: 'create') %>" data-remote-method="post"><i class="glyphicon glyphicon-plus"></i>&nbsp;Tag</a>
+    </span>
     </td>
 
     <td class="arv-description-in-table">