2872: Add infinite scroll to chooser modal.
[arvados.git] / apps / workbench / app / controllers / application_controller.rb
index ade586c47422b88d848612a9adf4a19330eae1bd..09419216b503be3c8c0ca6b64618ae515c903c00 100644 (file)
@@ -1,5 +1,6 @@
 class ApplicationController < ActionController::Base
   include ArvadosApiClientHelper
+  include ApplicationHelper
 
   respond_to :html, :json, :js
   protect_from_forgery
@@ -12,7 +13,6 @@ class ApplicationController < ActionController::Base
   before_filter :check_user_agreements, except: ERROR_ACTIONS
   before_filter :check_user_notifications, except: ERROR_ACTIONS
   before_filter :find_object_by_uuid, except: [:index] + ERROR_ACTIONS
-  before_filter :check_my_folders, :except => ERROR_ACTIONS
   theme :select_theme
 
   begin
@@ -64,7 +64,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,7 +85,25 @@ 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
+
+  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|
       f.json { render json: @objects }
       f.html { render }
@@ -110,6 +128,28 @@ class ApplicationController < ActionController::Base
     end
   end
 
+  def choose
+    params[:limit] ||= 20
+    find_objects_for_index if !@objects
+    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
     if !@object
       return render_not_found("object not found")
@@ -121,21 +161,21 @@ class ApplicationController < ActionController::Base
   end
 
   def update
-    updates = params[@object.class.to_s.underscore.singularize.to_sym]
-    updates.keys.each do |attr|
+    @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
-          updates[attr] = Oj.load updates[attr]
+        if @updates[attr].is_a? String
+          @updates[attr] = Oj.load @updates[attr]
         end
         if params[:merge] || params["merge_#{attr}".to_sym]
           # Merge provided Hash with current Hash, instead of
           # replacing.
-          updates[attr] = @object.send(attr).with_indifferent_access.
-            deep_merge(updates[attr].with_indifferent_access)
+          @updates[attr] = @object.send(attr).with_indifferent_access.
+            deep_merge(@updates[attr].with_indifferent_access)
         end
       end
     end
-    if @object.update_attributes updates
+    if @object.update_attributes @updates
       show
     else
       self.render_error status: 422
@@ -189,7 +229,7 @@ class ApplicationController < ActionController::Base
   end
 
   def show_pane_list
-    %w(Attributes Metadata JSON API)
+    %w(Attributes Advanced)
   end
 
   protected
@@ -236,7 +276,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
@@ -404,15 +450,6 @@ class ApplicationController < ActionController::Base
     }
   }
 
-  def check_my_folders
-    @my_top_level_folders = lambda do
-      @top_level_folders ||= Group.
-        filter([['group_class','=','folder'],
-                ['owner_uuid','=',current_user.uuid]]).
-        sort_by { |x| x.name || '' }
-    end
-  end
-
   def check_user_notifications
     @notification_count = 0
     @notifications = []
@@ -432,4 +469,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