---
 src/app/controllers/instance_controller.rb |    4 +
 src/app/controllers/pool_controller.rb     |   95 ++++++++++++++++++++++++++
 src/app/models/image.rb                    |   23 ++++++
 src/app/models/instance.rb                 |   19 +++++
 src/app/views/instance/new.html.erb        |   53 ++++++++++++++-
 src/app/views/pool/images.html.erb         |  102 ++++++++++++++++++++++------
 src/app/views/pool/show.html.erb           |   81 ++++++++++++----------
 7 files changed, 319 insertions(+), 58 deletions(-)

diff --git a/src/app/controllers/instance_controller.rb 
b/src/app/controllers/instance_controller.rb
index 0008c06..e47432c 100644
--- a/src/app/controllers/instance_controller.rb
+++ b/src/app/controllers/instance_controller.rb
@@ -40,6 +40,10 @@ class InstanceController < ApplicationController
   def new
     @instance = Instance.new({:pool_id => params[:id]})
     @pool = Pool.find(params[:id])
+
+    image_id = (params[:image_id] || []).first.to_s
+    @image = image_id.empty? ? nil : Image.find(image_id)
+
     require_privilege(Privilege::INSTANCE_MODIFY,@pool)
   end
 
diff --git a/src/app/controllers/pool_controller.rb 
b/src/app/controllers/pool_controller.rb
index 2ae0988..c438773 100644
--- a/src/app/controllers/pool_controller.rb
+++ b/src/app/controllers/pool_controller.rb
@@ -83,4 +83,99 @@ class PoolController < ApplicationController
     require_privilege(Privilege::POOL_VIEW, @pool)
   end
 
+  def images_paginate
+    # datatables sends pagination in format:
+    #   iDisplayStart - start index
+    #   iDisplayLength - num of recs
+    # => we need to count page num
+    page = params[:iDisplayStart].to_i / Image::RECS_PER_PAGE
+
+    if params[:mode].to_s == 'simple'
+      simple_mode = true
+      cols = Image::COLUMNS_SIMPLE
+      default_order_col = 1
+    else
+      cols = Image::COLUMNS
+      simple_mode = false
+      default_order_col = 2
+    end
+
+    # FIXME: check sortable on selected column
+    order_col = (cols[params[:iSortCol_0].to_i] || 
cols[default_order_col])[:id]
+    order = order_col + " " + (params[:sSortDir_0] == 'desc' ? 'desc' : 'asc')
+
+    if params[:sSearch].to_s.empty?
+      conditions = {:pool_id => params[:id]}
+    else
+      conditions = ["pool_id = ? and name like ?", params[:id], 
"%#{params[:sSearch]}%"]
+    end
+
+    @images = Image.paginate(
+      :page => page + 1, 
+      :include => :instances,
+      :order => order,
+      :conditions => conditions
+    )
+
+    expand_button_html = "<img src='/images/dir_closed.png'>"
+
+    data = @images.map do |i|
+      if simple_mode
+        [i.id, i.name, i.architecture, i.instances.size]
+      else
+        [i.id, expand_button_html, i.name, i.architecture, i.instances.size, 
"TODO: some description here?"]
+      end
+    end
+
+    render :json => {
+      :sEcho => params[:sEcho],
+      :iTotalRecords => @images.total_entries,
+      :iTotalDisplayRecords => @images.total_entries,
+      :aaData => data
+    }
+  end
+
+  def instances_paginate
+    # datatables sends pagination in format:
+    #   iDisplayStart - start index
+    #   iDisplayLength - num of recs
+    # => we need to count page num
+    page = params[:iDisplayStart].to_i / 15
+
+    @instances = Instance.paginate(:page => page + 1, :order => "name asc", 
:conditions => {:pool_id => params[:id]})
+
+    # FIXME: default stylesheet redefines link color
+    details_html = "<a href='#' class='details_link'>Details</a>"
+
+    render :json => {
+      :sEcho => params[:sEcho],
+      :iTotalRecords => @instances.total_entries,
+      :iTotalDisplayRecords => @instances.total_entries,
+      :aaData => @instances.map {|i| [i.id, "", i.name, details_html, i.state, 
i.hardware_profile.name, i.image.name]}
+    }
+  end
+
+
+  def accounts_for_pool
+    @pool =  Pool.find(params[:pool_id])
+    require_privilege(Privilege::ACCOUNT_VIEW,@pool)
+    @cloud_accounts = []
+    all_accounts = CloudAccount.list_for_user(@current_user, 
Privilege::ACCOUNT_ADD)
+    all_accounts.each {|account|
+      @cloud_accounts << account unless @pool.cloud_accounts.map{|x| 
x.id}.include?(account.id)
+    }
+  end
+
+  def add_account
+    @pool = Pool.find(params[:pool])
+    @cloud_account = CloudAccount.find(params[:cloud_account])
+    require_privilege(Privilege::ACCOUNT_ADD,@pool)
+    require_privilege(Privilege::ACCOUNT_ADD,@cloud_account)
+    Pool.transaction do
+      @pool.cloud_accounts << @cloud_account unless 
@pool.cloud_accounts.map{|x| x.id}.include?(@cloud_account.id)
+      @pool.save!
+      @pool.populate_realms_and_images([...@cloud_account])
+    end
+    redirect_to :action => 'show', :id => @pool.id
+  end
 end
diff --git a/src/app/models/image.rb b/src/app/models/image.rb
index 86806a4..7b36c96 100644
--- a/src/app/models/image.rb
+++ b/src/app/models/image.rb
@@ -20,6 +20,11 @@
 # Likewise, all the methods added will be available for all controllers.
 
 class Image < ActiveRecord::Base
+  RECS_PER_PAGE = 15
+
+  cattr_reader :per_page
+  @@per_page = RECS_PER_PAGE
+
   has_many :instances
   belongs_to :provider
 
@@ -43,6 +48,24 @@ class Image < ActiveRecord::Base
 
   validates_presence_of :architecture, :if => :provider
 
+  # used to get sorting column in controller and in view to generate datatable 
definition and
+  # html table structure
+  COLUMNS = [
+    {:id => 'id', :header => '<input type="checkbox" id="image_id_all" 
onclick="checkAll(event)">', :opts => {:checkbox_id => 'image_id', :searchable 
=> false, :sortable => false, :width => '1px', :class => 'center'}},
+    {:id => 'expand_button', :header => '', :header => '', :opts => 
{:searchable => false, :sortable => false, :width => '1px'}},
+    {:id => 'name', :header => 'Name', :opts => {:width => "30%"}},
+    {:id => 'architecture', :header => 'Architecture', :opts => {:width => 
"10%"}},
+    {:id => 'instances', :header => 'Instances', :opts => {:sortable => false, 
:width => "10%"}},
+    {:id => 'details', :header => '', :opts => {:sortable => false, :visible 
=> false, :searchable => false}},
+  ]
+
+  COLUMNS_SIMPLE = [
+    {:id => 'id', :header => '', :opts => {:visible => false, :searchable => 
false, :sortable => false, :width => '1px', :class => 'center'}},
+    {:id => 'name', :header => 'Name', :opts => {:width => "50%"}},
+    {:id => 'architecture', :header => 'Architecture', :opts => {:width => 
"30%"}},
+    {:id => 'instances', :header => 'Instances', :opts => {:sortable => false, 
:width => "20%"}},
+  ]
+
 
   def provider_image?
     !provider.nil?
diff --git a/src/app/models/instance.rb b/src/app/models/instance.rb
index fa89844..8c2da69 100644
--- a/src/app/models/instance.rb
+++ b/src/app/models/instance.rb
@@ -20,6 +20,11 @@
 # Likewise, all the methods added will be available for all controllers.
 
 class Instance < ActiveRecord::Base
+  RECS_PER_PAGE = 15
+
+  cattr_reader :per_page
+  @@per_page = RECS_PER_PAGE
+
   belongs_to :pool
   belongs_to :cloud_account
 
@@ -56,6 +61,20 @@ class Instance < ActiveRecord::Base
      :in => [STATE_NEW, STATE_PENDING, STATE_RUNNING,
              STATE_SHUTTING_DOWN, STATE_STOPPED, STATE_CREATE_FAILED]
 
+  # used to get sorting column in controller and in view to generate datatable 
definition and
+  # html table structure
+  COLUMNS = [
+    {:id => 'id', :header => '', :opts => {:checkbox_id => 'image_id', 
:searchable => false, :sortable => false, :width => '1px', :class => 'center'}},
+    {:id => 'actions', :header => 'Actions', :opts => {:width => "15%", 
:sortable => false}},
+    {:id => 'name', :header => 'Name', :opts => {:width => "25%"}},
+    {:id => 'details', :header => '', :opts => {:width => "10%", :sortable => 
false, :searchable => false}},
+    {:id => 'state', :header => 'State', :opts => {:width => "15%"}},
+    {:id => 'hwprofile', :header => 'HW profile', :opts => {:width => "15%"}},
+    {:id => 'image', :header => 'Image', :opts => {:sortable => false}},
+  ]
+
+  RECS_PER_PAGE = 15
+
   def get_action_list(user=nil)
     # return empty list rather than nil
     # FIXME: not handling pending state now -- only current state
diff --git a/src/app/views/instance/new.html.erb 
b/src/app/views/instance/new.html.erb
index 986959a..0acc4e8 100644
--- a/src/app/views/instance/new.html.erb
+++ b/src/app/views/instance/new.html.erb
@@ -14,8 +14,9 @@
     <% end %>
     <% if @pool.images.size > 0 %>
       <li><label>Image<span>Choose a bundled image to use</span></label>
-        <%= select("instance", "image_id", @pool.images.collect {|i| [ 
truncate(i.name, 29, '...'), i.id ] }, { :include_blank => true }) %>
+      <input type="button" style="cursor:pointer" onclick="showImages(event)" 
name="image_selector" value="<%= @image ? @image.name : "click to select 
image"%>"/>
       </li>
+      <input type=hidden name="instance[image_id]" value="<%= @image ? 
@image.id : '' %>">
     <% end %>
     <% if @pool.realms.size > 0 %>
       <li><label>Realm<span>Choose a realm</span></label>
@@ -26,4 +27,54 @@
     <%= hidden_field :instance,  :pool_id %>
     <%= submit_tag "Save", :class => "submit" %>
     <% end %>
+  </div>
+
+
+
+<script type="text/javascript">
+  function showImages(ev) {
+    $("#images_table_wrapper").css('display', 'block');
+    images_dialog = $("#images_table_wrapper").dialog({
+      title: "Select image for new instance",
+      dialogClass: 'flora', 
+      width: 600, 
+      height: 500, 
+      modal: true, 
+      overlay: {opacity: 0.2, background: "black"}
+    });
+  }
+  function selectImage(ev) {
+    var image_id = dataTable_images_table.fnGetData(ev.target.parentNode)[0];
+    var image_name = dataTable_images_table.fnGetData(ev.target.parentNode)[1];
+    $("#images_table_wrapper").css('display', 'none');
+    $("#images_table_wrapper").dialog('close');
+    $('input[name="image_selector"]').attr('value', image_name);
+    $('input[name="instance[image_id]"]').attr('value', image_id);
+  }
+</script>
+
+<%= datatable(
+  Image::COLUMNS_SIMPLE.map {|c| c[:opts]}, 
+  {
+    :table_dom_id => 'images_table',
+    :per_page => Image::RECS_PER_PAGE, 
+    :sort_by => "[2, 'asc']", 
+    :serverside => true,
+    :ajax_source => url_for(:controller => 'pool', :action => 
'images_paginate') + "/#[email protected]}?mode=simple",
+    :append => ".fnSetFilteringDelay()",
+    :click_callback => "function(event) {selectImage(event)}",
+  }
+) %>
+<div style="display:none" id="images_table_wrapper">
+  <table class="datatable display" id="images_table">
+    <thead>
+      <tr>
+        <% Image::COLUMNS_SIMPLE.each do |c| %>
+          <%= "<th>#{c[:header]}</th>" %>
+        <% end %>
+      </tr>
+    </thead>
+    <tbody>
+  </tbody>
+</table>
 </div>
diff --git a/src/app/views/pool/images.html.erb 
b/src/app/views/pool/images.html.erb
index e0187a8..3fe0637 100644
--- a/src/app/views/pool/images.html.erb
+++ b/src/app/views/pool/images.html.erb
@@ -1,20 +1,82 @@
-<% if @pool.images.size == 0 %>
-<h1>There are no images to display</h1>
-<% else %>
-    <table>
-      <thead>
-        <tr>
-        <th scope="col">Name</th>
-          <th scope="col">Arch</th>
-        </tr>
-      </thead>
-      <tbody>
-  <%[email protected] {|image| %>
-        <tr>
-          <td><%= image.name %></td>
-          <td><%= image.architecture %></td>
-        </tr>
-      <% } %>
-    </tbody>
-  </table>
-<% end %>
\ No newline at end of file
+<script type="text/javascript">
+
+  function fnOpenClose() {
+    $('td img', dataTable_images_table.fnGetNodes() ).each( function () {
+      $(this).click( function () {
+        var nTr = this.parentNode.parentNode;
+        if ( this.src.match('dir_open') )
+        {
+          /* This row is already open - close it */
+          this.src = "/images/dir_closed.png";
+          /* fnClose doesn't do anything for server-side processing - do it 
ourselves :-) */
+          var nRemove = $(nTr).next()[0];
+          nRemove.parentNode.removeChild( nRemove );
+        }
+        else
+        {
+          /* Open this row */
+          this.src = "/images/dir_open.png";
+          dataTable_images_table.fnOpen( nTr, 
dataTable_images_table.fnGetData(nTr)[5], 'details' );
+        }
+      });
+    });
+  }
+ 
+  function getCheckedRows() {
+    return $('input[name="image_id[]"]:checked', 
dataTable_images_table).length;
+  }
+  
+  function showButtons() {
+    getCheckedRows();
+    $('input[name="create_image"]').attr('disabled', getCheckedRows() != 1);
+  }
+  
+  function checkRow(ev) {
+    var box = $('input[name="image_id[]"]', ev.target.parentNode);
+    if ($(ev.target).attr('name') != "image_id[]")
+      box.attr('checked', !box.attr('checked'));
+    showButtons();
+  }
+
+  function checkAll(ev) {
+    $('input[name="image_id[]"]', dataTable_images_table).attr('checked', 
$(ev.target).attr('checked'))
+  }
+
+  function drawCallback() {
+    $('#image_id_all').attr('checked', false);
+    fnOpenClose();
+  }
+</script>
+
+<%= datatable(
+  Image::COLUMNS.map {|c| c[:opts]}, 
+  {
+    :table_dom_id => 'images_table',
+    :per_page => Image::RECS_PER_PAGE, 
+    :sort_by => "[2, 'asc']", 
+    :serverside => true,
+    :ajax_source => url_for(:controller => 'pool', :action => 
'images_paginate') + "/#[email protected]}",
+    :append => ".fnSetFilteringDelay()",
+    :persist_state => false,
+    :click_callback => "function(ev) {checkRow(ev);}",
+    :draw_callback => "drawCallback",
+  }
+) %>
+             <form method=POST action="/instance/new/<%= @pool.id %>" 
style="display:block">
+  <div style="padding:20px">
+    <input type="submit" value="Create instance" name="create_image" 
disabled=true>
+  </div>
+  <table class="datatable display" id="images_table">
+    <thead>
+      <tr>
+        <% Image::COLUMNS.each do |c| %>
+          <%= "<th>#{c[:header]}</th>" %>
+        <% end %>
+      </tr>
+    </thead>
+    <tbody>
+  </tbody>
+</table>
+</form>
+
+
diff --git a/src/app/views/pool/show.html.erb b/src/app/views/pool/show.html.erb
index ef637f1..43fcec8 100644
--- a/src/app/views/pool/show.html.erb
+++ b/src/app/views/pool/show.html.erb
@@ -1,40 +1,47 @@
-<% if @instances.size == 0 %>
-<h1>There are no instances to display</h1>
-<% else %>
-  <table>
-    <thead>
-      <tr>
-      <th scope="col">Actions</th>
-      <th scope="col">Name</th>
-      <th scope="col">State</th>
-      <th scope="col">Hardware Profile</th>
-      <th scope="col">Image</th>
-      </tr>
-    </thead>
-    <tbody>
-      <%[email protected] {|instance| %>
-        <tr>
-          <td>
-            <ul class="instance_action_list">
-            <%instance.get_action_list.each {|action|%>
-              <li>
-              <%= link_to action, :controller => "instance",
-                                  :action => "instance_action",
-                                  :id => instance,
-                                 :instance_action => action %>
-              </li>
-           <% } %>
-            </ul>
-          </td>
-          <td><%= instance.name %></td>
-          <td><%= instance.state %></td>
-          <td><%= instance.hardware_profile.name %></td>
-          <td><%= instance.image.name %></td>
-        </tr>
-      <% } %>
-    </tbody>
-  </table>
-<% end %>
+<%= datatable(
+  Instance::COLUMNS.map {|c| c[:opts]}, 
+  {
+    :table_dom_id => 'instances_table',
+    :per_page => Instance::RECS_PER_PAGE, 
+    :sort_by => "[3, 'asc']", 
+    :serverside => true,
+    :ajax_source => url_for(:controller => 'pool', :action => 
'instances_paginate') + "/#[email protected]}",
+    :append => ".fnSetFilteringDelay()",
+    :persist_state => false,
+    :click_callback => "function(ev) {clickRow(ev);}",
+  }
+) %>
+<table class="datatable display" id="instances_table">
+  <thead>
+    <tr>
+        <% Instance::COLUMNS.each do |c| %>
+          <%= "<th>#{c[:header]}</th>" %>
+        <% end %>
+    </tr>
+  </thead>
+  <tbody>
+  </tbody>
+</table>
+<script type="text/javascript">
+  function showInstanceDetailsDialog() {
+    images_dialog = $("<div>TODO: show dialog</div>").dialog({
+      title: "Instance details",
+      dialogClass: 'flora', 
+      width: 600, 
+      height: 300, 
+      modal: true, 
+      overlay: {opacity: 0.2, background: "black"}
+    });
+  }
+
+  function clickRow(ev) {
+    var box = $('input[name="image_id[]"]', ev.target.parentNode);
+    if ($(ev.target).hasClass('details_link')) showInstanceDetailsDialog();
+    if ($(ev.target).attr('name') != "image_id[]")
+      box.attr('checked', !box.attr('checked'));
+  }
+</script>
+
 <%= link_to "Add a new instance", {:controller => "instance", :action => 
"new", :id => @pool}, :class=>"actionlink"%>
 <%= link_to "User access",  {:controller => "permissions", :action => "list", 
:pool_id => @pool.id}, :class=>"actionlink" if has_view_perms? %>
 <%= link_to "Hardware Profiles",  {:action => "hardware_profiles", :id => 
@pool.id}, :class=>"actionlink"%>
-- 
1.6.2.5

_______________________________________________
deltacloud-devel mailing list
[email protected]
https://fedorahosted.org/mailman/listinfo/deltacloud-devel

Reply via email to