[ARVADOS] created: 036b3b0ddb515f1f4f4588bfe1ea7e010dfd6bd4

git at public.curoverse.com git at public.curoverse.com
Tue May 13 17:31:51 EDT 2014


        at  036b3b0ddb515f1f4f4588bfe1ea7e010dfd6bd4 (commit)


commit 036b3b0ddb515f1f4f4588bfe1ea7e010dfd6bd4
Author: Brett Smith <brett at curoverse.com>
Date:   Tue May 13 17:31:29 2014 -0400

    2753: Workbench renders "0 bytes" for empty file sizes.

diff --git a/apps/workbench/app/helpers/application_helper.rb b/apps/workbench/app/helpers/application_helper.rb
index dbb05d6..022a313 100644
--- a/apps/workbench/app/helpers/application_helper.rb
+++ b/apps/workbench/app/helpers/application_helper.rb
@@ -17,6 +17,7 @@ module ApplicationHelper
 
   def human_readable_bytes_html(n)
     return h(n) unless n.is_a? Fixnum
+    return "0 bytes" if (n == 0)
 
     orders = {
       1 => "bytes",

commit cf117cf537c8da637c3e74f232cc97352ca98f16
Author: Brett Smith <brett at curoverse.com>
Date:   Tue May 13 13:15:30 2014 -0400

    2753: Workbench shows Collection files in a tree.

diff --git a/apps/workbench/Gemfile b/apps/workbench/Gemfile
index bcbe3ef..4d1eb29 100644
--- a/apps/workbench/Gemfile
+++ b/apps/workbench/Gemfile
@@ -37,6 +37,7 @@ group :test do
 end
 
 gem 'jquery-rails'
+gem 'jstree-rails', :git => 'git://github.com/xinlangzi/jstree-rails.git'
 gem 'bootstrap-sass', '~> 3.1.0'
 gem 'bootstrap-x-editable-rails'
 
diff --git a/apps/workbench/Gemfile.lock b/apps/workbench/Gemfile.lock
index 8e74832..676bde1 100644
--- a/apps/workbench/Gemfile.lock
+++ b/apps/workbench/Gemfile.lock
@@ -1,3 +1,10 @@
+GIT
+  remote: git://github.com/xinlangzi/jstree-rails.git
+  revision: bdf08b19a7fba167e8cdf7db57669a54dedd9bf3
+  specs:
+    jstree-rails (1.0.0)
+      rails (>= 3.2)
+
 GEM
   remote: https://rubygems.org/
   specs:
@@ -194,6 +201,7 @@ DEPENDENCIES
   headless
   httpclient
   jquery-rails
+  jstree-rails!
   less
   less-rails
   multi_json
diff --git a/apps/workbench/app/assets/javascripts/application.js b/apps/workbench/app/assets/javascripts/application.js
index d66cb92..01239c2 100644
--- a/apps/workbench/app/assets/javascripts/application.js
+++ b/apps/workbench/app/assets/javascripts/application.js
@@ -12,6 +12,7 @@
 //
 //= require jquery
 //= require jquery_ujs
+//= require jstree
 //= require bootstrap
 //= require bootstrap/dropdown
 //= require bootstrap/tab
diff --git a/apps/workbench/app/assets/stylesheets/application.css.scss b/apps/workbench/app/assets/stylesheets/application.css.scss
index 51c96d7..6fc8cd0 100644
--- a/apps/workbench/app/assets/stylesheets/application.css.scss
+++ b/apps/workbench/app/assets/stylesheets/application.css.scss
@@ -9,6 +9,7 @@
  * compiled file, but it's generally better to create a new file per style scope.
  *
  *= require_self
+ *= require jstree-themes/default/style
  *= require bootstrap
  *= require bootstrap3-editable/bootstrap-editable
  *= require_tree .
diff --git a/apps/workbench/app/views/collections/_show_files.html.erb b/apps/workbench/app/views/collections/_show_files.html.erb
index 4b63162..827cb01 100644
--- a/apps/workbench/app/views/collections/_show_files.html.erb
+++ b/apps/workbench/app/views/collections/_show_files.html.erb
@@ -2,9 +2,55 @@
 .file-list-inline-image {
   width: 50%;
   height: auto;
+  margin: auto auto;
+}
+
+div#collection_files {
+  width: 49%;
+  float: left;
+  overflow: auto;
+}
+
+i.jstree-icon {
+  font-style: normal;
+}
+
+div#collections_file_pane {
+  width: 50%;
+  float: right;
+}
+
+div#collections_file_pane h3 {
+  margin: 0;
+}
+
+.collections_file_size {
+  margin-top: 0em;
+  font-style: italic;
 }
 <% end %>
 
+<% content_for :js do %>
+$(function () {
+$("div#collection_files")
+.on("activate_node.jstree", function(event, data) {
+  if (data.instance.is_leaf(data.node)) {
+    var file_info = $("div[title=\"" + data.node.li_attr.title + "\"]").html();
+    $("div#collections_file_pane").html(file_info);
+  } else {
+    data.instance.toggle_node(data.node);
+  }
+})
+.jstree({
+  "core": {
+    "themes": {"stripes": true},
+    "multiple": false
+  },
+  "plugins": ["wholerow"],
+});
+});
+<% end %>
+
 <% content_for :tab_line_buttons do %>
 <div class="row">
   <div class="col-md-6"></div>
@@ -17,59 +63,59 @@
 </div>
 <% end %>
 
-<table class="table table-condensed table-fixedlayout">
-  <colgroup>
-    <col width="4%" />
-    <col width="35%" />
-    <col width="40%" />
-    <col width="15%" />
-    <col width="10%" />
-  </colgroup>
-  <thead>
-    <tr>
-      <th></th>
-      <th>path</th>
-      <th>file</th>
-      <th style="text-align:right">size</th>
-      <th>d/l</th>
-    </tr>
-  </thead><tbody>
-    <% if @object then @object.files.sort_by{|f|[f[0],f[1]]}.each do |file| %>
-      <% file_path = CollectionsHelper::file_path file %>
-      <tr>
-        <td>
-          <%= check_box_tag 'uuids[]', @object.uuid+'/'+file_path, false, {
-                :class => 'persistent-selection',
-                :friendly_type => "File",
-                :friendly_name => "#{@object.uuid}/#{file_path}",
-                :href => "#{url_for controller: 'collections', action: 'show', id: @object.uuid }/#{file_path}",
-                :title => "Click to add this item to your selection list"
-              } %>
-        </td>
-        <td>
-          <%= file[0] %>
-        </td>
-
-      <td>
-        <%= link_to (if CollectionsHelper::is_image file[1]
-                       image_tag "#{url_for @object}/#{file_path}", class: "file-list-inline-image"
-                     else
-                       file[1]
-                     end),
-            {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'inline'},
-            {title: file_path} %>
-      </td>
-
-        <td style="text-align:right">
-          <%= raw(human_readable_bytes_html(file[2])) %>
-        </td>
-
-        <td>
-          <div style="display:inline-block">
-            <%= link_to raw('<i class="glyphicon glyphicon-download-alt"></i>'), {controller: 'collections', action: 'show_file', uuid: @object.uuid, file: file_path, size: file[2], disposition: 'attachment'}, {class: 'btn btn-info btn-sm', title: 'Download'} %>
-          </div>
-        </td>
-      </tr>
-    <% end; end %>
-  </tbody>
-</table>
+<% file_tree = @object.andand.files_tree %>
+<% if file_tree.nil? or file_tree.empty? %>
+  <p>This collection is empty.</p>
+<% else %>
+  <div id="collection_files"><ul>
+  <% dirstack = ["."] %>
+  <% file_tree.each do |dirname, filename, size| %>
+    <% while dirstack.any? and (dirstack.last != dirname) %>
+      <% dirstack.pop %></ul></li>
+    <% end %>
+    <% if size.nil?  # This is a subdirectory. %>
+      <% dirstack.push(File.join(dirname, filename)) %>
+      <li data-jstree='{"icon": "fa-folder"}' class="jstree-open"><%= filename %><ul>
+    <% else %>
+      <% data = {'icon' => (CollectionsHelper::is_image(filename) ? 'fa-bar-chart-o' : 'fa-file') } %>
+      <li data-jstree='<%= data.to_json %>'
+          title="<%= CollectionsHelper::file_path([dirname, filename]) %>"><%= filename %></li>
+    <% end %>
+  <% end %>
+  </ul></div>
+  <div id="collections_file_pane">Select a file to view more information.</div>
+  <% file_tree.reject { |data| data.last.nil? }.each do |dirname, filename, size| %>
+    <% file_path = CollectionsHelper::file_path([dirname, filename])
+       link_params = {controller: 'collections',
+                      action: 'show_file',
+                      uuid: @object.uuid,
+                      file: file_path,
+                      size: size} %>
+    <div title="<%= file_path %>" style="display: none;">
+    <h3><%= file_path %></h3>
+    <p class="collections_file_size"><%= raw(human_readable_bytes_html(size)) %></p>
+    <%= link_to("View", link_params.merge(disposition: 'inline'),
+                {class: "btn btn-primary"}) %>
+    <%= link_to("Download", link_params.merge(disposition: 'attachment'),
+                {class: "btn btn-primary"}) %>
+    <p>
+    <%= check_box_tag 'uuids[]', "#{@object.uuid}/#{file_path}", false, {
+          :class => 'persistent-selection',
+          :friendly_type => "File",
+          :friendly_name => "#{@object.uuid}/#{file_path}",
+          :href => url_for(controller: 'collections', action: 'show_file',
+                           uuid: @object.uuid, file: file_path),
+          :title => "Include this file in your selections",
+        } %>
+    Include this file in your selections
+    </p>
+    <% if CollectionsHelper::is_image(filename) %>
+     <div style="text-align: center;">
+      <%= link_to(image_tag("#{url_for @object}/#{file_path}", class: "file-list-inline-image"),
+                  link_params.merge(disposition: 'inline'),
+                  {title: file_path}) %>
+     </div>
+    <% end %>
+    </div>
+  <% end %>
+<% end %>

commit 04ed028ca994d24046175331e3bbe74dc734118d
Author: Brett Smith <brett at curoverse.com>
Date:   Mon May 12 17:29:55 2014 -0400

    2753: Add Workbench Collection#files_tree.

diff --git a/apps/workbench/app/models/collection.rb b/apps/workbench/app/models/collection.rb
index a63bf90..20da7ec 100644
--- a/apps/workbench/app/models/collection.rb
+++ b/apps/workbench/app/models/collection.rb
@@ -22,6 +22,27 @@ class Collection < ArvadosBase
     end
   end
 
+  def files_tree
+    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|
+      until tree.include?(splitdir)
+        tree[splitdir] = []
+        splitdir = File.split(splitdir.first)
+      end
+    end
+    dir_to_tree = lambda do |dirname|
+      # First list subdirectories, with their files inside.
+      subnodes = tree.keys.select { |bd, td| (bd == dirname) and (td != '.') }
+        .sort.flat_map do |parts|
+        [parts + [nil]] + dir_to_tree.call(File.join(parts))
+      end
+      # Then extend that list with files in this directory.
+      subnodes + tree[File.split(dirname)]
+    end
+    dir_to_tree.call('.')
+  end
+
   def attribute_editable?(attr)
     false
   end
diff --git a/apps/workbench/test/unit/collection_test.rb b/apps/workbench/test/unit/collection_test.rb
index bbfc983..512ad47 100644
--- a/apps/workbench/test/unit/collection_test.rb
+++ b/apps/workbench/test/unit/collection_test.rb
@@ -13,4 +13,31 @@ class CollectionTest < ActiveSupport::TestCase
       assert_equal false, Collection.is_empty_blob_locator?(x)
     end
   end
+
+  def get_files_tree(coll_name)
+    use_token :admin
+    Collection.find(api_fixture('collections')[coll_name]['uuid']).files_tree
+  end
+
+  test "easy files_tree" do
+    files_in = lambda do |dirname|
+      (1..3).map { |n| [dirname, "file#{n}", 0] }
+    end
+    assert_equal([['.', 'dir1', nil], ['./dir1', 'subdir', nil]] +
+                 files_in['./dir1/subdir'] + files_in['./dir1'] +
+                 [['.', 'dir2', nil]] + files_in['./dir2'] + files_in['.'],
+                 get_files_tree('multilevel_collection_1'),
+                 "Collection file tree was malformed")
+  end
+
+  test "files_tree with files deep in subdirectories" do
+    # This test makes sure files_tree generates synthetic directory entries.
+    # The manifest doesn't list directories with no files.
+    assert_equal([['.', 'dir1', nil], ['./dir1', 'sub1', nil],
+                  ['./dir1/sub1', 'a', 0], ['./dir1/sub1', 'b', 0],
+                  ['.', 'dir2', nil], ['./dir2', 'sub2', nil],
+                  ['./dir2/sub2', 'c', 0], ['./dir2/sub2', 'd', 0]],
+                 get_files_tree('multilevel_collection_2'),
+                 "Collection file tree was malformed")
+  end
 end
diff --git a/services/api/test/fixtures/collections.yml b/services/api/test/fixtures/collections.yml
index ce05d18..26f5f48 100644
--- a/services/api/test/fixtures/collections.yml
+++ b/services/api/test/fixtures/collections.yml
@@ -37,3 +37,24 @@ baz_file:
   modified_at: 2014-02-03T17:22:54Z
   updated_at: 2014-02-03T17:22:54Z
   manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
+
+multilevel_collection_1:
+  uuid: 1fd08fc162a5c6413070a8bd0bffc818+150
+  owner_uuid: qr1hi-tpzed-000000000000000
+  created_at: 2014-02-03T17:22:54Z
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+  modified_at: 2014-02-03T17:22:54Z
+  updated_at: 2014-02-03T17:22:54Z
+  manifest_text: ". 0:0:file1 0:0:file2 0:0:file3\n./dir1 0:0:file1 0:0:file2 0:0:file3\n./dir1/subdir 0:0:file1 0:0:file2 0:0:file3\n./dir2 0:0:file1 0:0:file2 0:0:file3\n"
+
+multilevel_collection_2:
+  # All of this collection's files are deep in subdirectories.
+  uuid: 80cf6dd2cf079dd13f272ec4245cb4a8+48
+  owner_uuid: qr1hi-tpzed-000000000000000
+  created_at: 2014-02-03T17:22:54Z
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+  modified_at: 2014-02-03T17:22:54Z
+  updated_at: 2014-02-03T17:22:54Z
+  manifest_text: "./dir1/sub1 0:0:a 0:0:b\n./dir2/sub2 0:0:c 0:0:d\n"

commit b519a95d758587ba82a1d9b5ffaa0d84292f7aaa
Author: Brett Smith <brett at curoverse.com>
Date:   Mon May 12 11:21:12 2014 -0400

    2753: Add tests for CollectionsHelper.file_path.

diff --git a/apps/workbench/test/unit/helpers/collections_helper_test.rb b/apps/workbench/test/unit/helpers/collections_helper_test.rb
index 16a85d9..56d23c5 100644
--- a/apps/workbench/test/unit/helpers/collections_helper_test.rb
+++ b/apps/workbench/test/unit/helpers/collections_helper_test.rb
@@ -1,4 +1,12 @@
 require 'test_helper'
 
 class CollectionsHelperTest < ActionView::TestCase
+  test "file_path generates short names" do
+    assert_equal('foo', CollectionsHelper.file_path(['.', 'foo', 0]),
+                 "wrong result for filename in collection root")
+    assert_equal('foo/bar', CollectionsHelper.file_path(['foo', 'bar', 0]),
+                 "wrong result for filename in directory without leading .")
+    assert_equal('foo/bar', CollectionsHelper.file_path(['./foo', 'bar', 0]),
+                 "wrong result for filename in directory with leading .")
+  end
 end

commit a73dca721e2d1cf3c83a40c2d23e0f45d2beee82
Author: Brett Smith <brett at curoverse.com>
Date:   Mon May 12 10:37:55 2014 -0400

    2753: Make Collection filenames with existing helper.
    
    This is pure refactoring to make the code more consistent.

diff --git a/apps/workbench/app/controllers/collections_controller.rb b/apps/workbench/app/controllers/collections_controller.rb
index 4178e38..0fef60d 100644
--- a/apps/workbench/app/controllers/collections_controller.rb
+++ b/apps/workbench/app/controllers/collections_controller.rb
@@ -210,12 +210,9 @@ class CollectionsController < ApplicationController
   end
 
   def file_in_collection?(collection, filename)
-    def normalized_path(part_list)
-      File.join(part_list).sub(%r{^\./}, '')
-    end
-    target = normalized_path([filename])
+    target = CollectionsHelper.file_path(File.split(filename))
     collection.files.each do |file_spec|
-      return true if (normalized_path(file_spec[0, 2]) == target)
+      return true if (CollectionsHelper.file_path(file_spec) == target)
     end
     false
   end

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list