Commit c64ccb86205c07fa8df0dba17b676f01ac5ab7b4

Thomas de Grivel 2022-01-28T13:42:33

[admin] repository index pagination

diff --git a/lib/kmxgit/index_params.ex b/lib/kmxgit/index_params.ex
index 1f8f7ad..da5c51c 100644
--- a/lib/kmxgit/index_params.ex
+++ b/lib/kmxgit/index_params.ex
@@ -1,5 +1,5 @@
 defmodule Kmxgit.IndexParams do
 
-  defstruct column: "id", reverse: false, search: nil
+  defstruct column: "id", page: 1, per: 4, reverse: false, search: nil
 
 end
diff --git a/lib/kmxgit/pagination.ex b/lib/kmxgit/pagination.ex
new file mode 100644
index 0000000..84422fb
--- /dev/null
+++ b/lib/kmxgit/pagination.ex
@@ -0,0 +1,41 @@
+defmodule Kmxgit.Pagination do
+  import Ecto.Query
+
+  alias Kmxgit.IndexParams
+  alias Kmxgit.Repo
+
+  def query(query, %IndexParams{page: page, per: per}) do
+    query
+    |> limit(^per + 1)
+    |> offset(^(per * (page - 1)))
+  end
+
+  def page(query, params = %IndexParams{page: page, per: per}, preload: preload) do
+    result = query
+    |> query(params)
+    |> preload(^preload)
+    |> Repo.all()
+    first_page = if page > 2, do: 1
+    prev_page = if page > 1, do: page - 1
+    {next_page, result} = if length(result) > per do
+      {page + 1, Enum.slice(result, 0..-2)}
+    else
+      {nil, result}
+    end
+    count = Repo.one(from(t in subquery(query), select: count("*")))
+    count_pages = Float.ceil(count / per) |> trunc()
+    last_page = if (page < count_pages - 1), do: count_pages
+    first = (page - 1) * per + 1
+    %{count: count,
+      count_pages: count_pages,
+      first: first,
+      first_page: first_page,
+      last: first + length(result) - 1,
+      last_page: last_page,
+      next_page: next_page,
+      page: page,
+      per: per,
+      prev_page: prev_page,
+      result: result}
+  end
+end
diff --git a/lib/kmxgit/repository_manager.ex b/lib/kmxgit/repository_manager.ex
index fb9742c..eaef52e 100644
--- a/lib/kmxgit/repository_manager.ex
+++ b/lib/kmxgit/repository_manager.ex
@@ -4,6 +4,7 @@ defmodule Kmxgit.RepositoryManager do
 
   alias Kmxgit.IndexParams
   alias Kmxgit.OrganisationManager.Organisation
+  alias Kmxgit.Pagination
   alias Kmxgit.Repo
   alias Kmxgit.RepositoryManager.Repository
   alias Kmxgit.SlugManager
@@ -19,12 +20,11 @@ defmodule Kmxgit.RepositoryManager do
     |> join(:full, [r, o, os], u in User, on: u.id == r.user_id)
     |> join(:full, [r, o, os, u], us in Slug, on: us.user_id == u.id)
     |> where([r, o, os, u, us], not is_nil(r))
-    |> preload([members: :slug,
-               organisation: [:slug, users: :slug],
-               user: :slug])
     |> search(params)
     |> index_order_by(params)
-    |> Repo.all()
+    |> Pagination.page(params, preload: [members: :slug,
+                                        organisation: [:slug, users: :slug],
+                                        user: :slug])
   end
 
   def search(query, %IndexParams{search: search}) do
diff --git a/lib/kmxgit_web.ex b/lib/kmxgit_web.ex
index 5c56545..525dabb 100644
--- a/lib/kmxgit_web.ex
+++ b/lib/kmxgit_web.ex
@@ -63,6 +63,10 @@ defmodule KmxgitWeb do
         |> FileSize.to_string()
       end
 
+      def page_link(conn, title \\ nil, page) do
+        link title || page, to: Routes.admin_repository_path(conn, :index, page: page, per: conn.assigns.pagination.per, search: conn.assigns.search, sort: conn.assigns.sort), class: "btn btn-primary"
+      end
+
       def recaptcha_site_key do
         Application.get_env :kmxgit, :recaptcha_site_key
       end
diff --git a/lib/kmxgit_web/controllers/admin.ex b/lib/kmxgit_web/controllers/admin.ex
index 781f592..971efb5 100644
--- a/lib/kmxgit_web/controllers/admin.ex
+++ b/lib/kmxgit_web/controllers/admin.ex
@@ -2,8 +2,26 @@ defmodule KmxgitWeb.Admin do
 
   alias Kmxgit.IndexParams
 
+  def page_params(index_params = %IndexParams{}, nil, nil) do
+    index_params
+  end
+  def page_params(index_params = %IndexParams{}, page, nil) do
+    %IndexParams{index_params | page: String.to_integer(page)}
+  end
+  def page_params(index_params = %IndexParams{}, nil, per) do
+    %IndexParams{index_params | per: String.to_integer(per)}
+  end
+  def page_params(index_params = %IndexParams{}, page, per) do
+    %IndexParams{index_params | page: String.to_integer(page),
+                 per: String.to_integer(per)}
+  end
+
+  def search_param(index_params = %IndexParams{}, param) do
+    %IndexParams{index_params | search: param}
+  end
+
   def sort_param(index_params = %IndexParams{}, param) do
-    if param do
+    if param && param != "" do
       case String.split(param, "-") do
         [col, _] -> %IndexParams{index_params | column: col, reverse: true}
         [col] -> %IndexParams{index_params | column: col}
@@ -13,8 +31,4 @@ defmodule KmxgitWeb.Admin do
       index_params
     end
   end
-
-  def search_param(index_params = %IndexParams{}, param) do
-    %IndexParams{index_params | search: param}
-  end
 end
diff --git a/lib/kmxgit_web/controllers/admin/repository_controller.ex b/lib/kmxgit_web/controllers/admin/repository_controller.ex
index a61b1f8..d70e044 100644
--- a/lib/kmxgit_web/controllers/admin/repository_controller.ex
+++ b/lib/kmxgit_web/controllers/admin/repository_controller.ex
@@ -11,14 +11,16 @@ defmodule KmxgitWeb.Admin.RepositoryController do
 
   def index(conn, params) do
     index_params = %IndexParams{}
-    |> KmxgitWeb.Admin.sort_param(params["sort"])
+    |> KmxgitWeb.Admin.page_params(params["page"], params["per"])
     |> KmxgitWeb.Admin.search_param(params["search"])
-    repos = RepositoryManager.list_repositories(index_params)
+    |> KmxgitWeb.Admin.sort_param(params["sort"])
+    pagination = RepositoryManager.list_repositories(index_params)
     conn
-    |> assign(:repos, repos)
     |> assign(:index, index_params)
+    |> assign(:pagination, pagination)
     |> assign(:search, params["search"])
     |> assign(:search_action, Routes.admin_repository_path(conn, :index, sort: params["sort"], search: params["search"]))
+    |> assign(:sort, params["sort"])
     |> render("index.html")
   end
 
diff --git a/lib/kmxgit_web/templates/admin/repository/index.html.heex b/lib/kmxgit_web/templates/admin/repository/index.html.heex
index 9782fa8..e2f6950 100644
--- a/lib/kmxgit_web/templates/admin/repository/index.html.heex
+++ b/lib/kmxgit_web/templates/admin/repository/index.html.heex
@@ -1,6 +1,7 @@
 <div class="container-fluid">
   <h1>Repositories</h1>
   <%= render(KmxgitWeb.LayoutView, "search.html", assigns) %>
+  <%= render(KmxgitWeb.LayoutView, "pagination.html", assigns) %>
   <table class="table admin-index">
     <thead>
       <tr>
@@ -12,7 +13,7 @@
       </tr>
     </thead>
     <tbody>
-      <%= Enum.map @repos, fn(repo) -> %>
+      <%= Enum.map @pagination.result, fn repo -> %>
         <tr>
           <td><%= link repo.id, to: Routes.admin_repository_path(@conn, :show, repo) %></td>
           <td>
@@ -32,4 +33,5 @@
       <% end %>
     </tbody>
   </table>
+  <%= render(KmxgitWeb.LayoutView, "pagination.html", assigns) %>
 </div>
diff --git a/lib/kmxgit_web/templates/layout/pagination.html.heex b/lib/kmxgit_web/templates/layout/pagination.html.heex
new file mode 100644
index 0000000..4e16e8c
--- /dev/null
+++ b/lib/kmxgit_web/templates/layout/pagination.html.heex
@@ -0,0 +1,21 @@
+<%= if @pagination.first_page do %>
+  <%= page_link @conn, raw("<i class=\"fa fa-angle-double-left\"></i>"), @pagination.first_page %>
+<% end %>
+<%= if @pagination.prev_page do %>
+  <%= page_link @conn, raw("<i class=\"fa fa-angle-left\"></i>"), @pagination.prev_page %>
+<% end %>
+<span class="btn btn-primary disabled">
+  <%= @pagination.page %>
+</span>
+<%= if @pagination.next_page do %>
+  <%= page_link @conn, raw("<i class=\"fa fa-angle-right\"></i>"), @pagination.next_page %>
+<% end %>
+<%= if @pagination.last_page do %>
+  <%= page_link @conn, raw("<i class=\"fa fa-angle-double-right\"></i>"), @pagination.last_page %>
+<% end %>
+&nbsp;
+<%= @pagination.first %>
+-
+<%= @pagination.last %>
+<%= gettext("out of") %>
+<%= @pagination.count %>