From 20eedb3243aee88740cdbad65ced9ff9f466cf2b Mon Sep 17 00:00:00 2001 From: Zack Siri Date: Wed, 28 Feb 2024 19:46:51 +0700 Subject: [PATCH] Add filter tabs --- lib/polar_web/live/root_live.ex | 63 ++++++++------------- lib/polar_web/live/root_live/data_loader.ex | 43 ++++++++++++++ 2 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 lib/polar_web/live/root_live/data_loader.ex diff --git a/lib/polar_web/live/root_live.ex b/lib/polar_web/live/root_live.ex index e5ed90a..2065257 100644 --- a/lib/polar_web/live/root_live.ex +++ b/lib/polar_web/live/root_live.ex @@ -1,10 +1,7 @@ defmodule PolarWeb.RootLive do use PolarWeb, :live_view - alias Polar.Repo - alias Polar.Streams.Version - - import Ecto.Query, only: [from: 2] + import __MODULE__.DataLoader @arch_colors %{ "amd64" => @@ -20,6 +17,7 @@ defmodule PolarWeb.RootLive do } attr :filter, :map, default: %{} + attr :tabs, :list, default: [] def render(assigns) do ~H""" @@ -39,7 +37,6 @@ defmodule PolarWeb.RootLive do <%= gettext("opsmaru-images") %> <%= gettext("repository.") %> - <%= gettext("Click on an os to filter.") %>

@@ -48,10 +45,26 @@ defmodule PolarWeb.RootLive do patch={~p"/"} class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" > + <.icon name="hero-x-circle" class="-ml-0.5 mr-1.5 h-5 w-5 text-white" /> <%= gettext("Clear filter") %>
+
+ + <%= for {tab, index} <- @tabs do %> + <.link + patch={~p"/?os=#{tab.os}"} + class={"relative gap-x-1.5 inline-flex items-center #{if index == 1, do: "rounded-l-md"} #{if index == Enum.count(@tabs), do: "rounded-r-md"} px-3 py-2 text-sm font-semibold #{if tab.os == @filter["os"], do: "text-white bg-indigo-500", else: "bg-white text-slate-900 hover:bg-gray-50"} ring-inset focus:z-10"} + > + <%= Phoenix.Naming.humanize(tab.os) %> + + <%= tab.count %> + + + <% end %> + +
@@ -150,6 +163,8 @@ defmodule PolarWeb.RootLive do end def mount(_params, _session, socket) do + tabs = load_tabs() + socket = socket |> assign(:versions, []) @@ -158,50 +173,20 @@ defmodule PolarWeb.RootLive do |> assign(:arch_colors, @arch_colors) |> assign(:os_colors, @os_colors) |> assign(:filter, %{}) + |> assign(:tabs, tabs) {:ok, socket} end - def handle_params(%{"os" => os} = params, _uri, socket) do - versions = - from( - v in Version, - join: p in assoc(v, :product), - where: v.current_state == ^"active" and p.os == ^os, - preload: [{:product, p}], - order_by: [asc: p.os], - order_by: [desc: p.release], - order_by: [desc: v.inserted_at] - ) - |> Repo.all() - + def handle_params(params, _uri, socket) do filter = Map.take(params, ["os"]) - socket = - socket - |> assign(:versions, versions) - |> assign(:filter, filter) - - {:noreply, socket} - end - - def handle_params(_, _uri, socket) do - versions = - from( - v in Version, - where: v.current_state == ^"active", - join: p in assoc(v, :product), - preload: [{:product, p}], - order_by: [asc: p.os], - order_by: [desc: p.release], - order_by: [desc: v.inserted_at] - ) - |> Repo.all() + versions = load_versions(filter) socket = socket |> assign(:versions, versions) - |> assign(:filter, %{}) + |> assign(:filter, filter) {:noreply, socket} end diff --git a/lib/polar_web/live/root_live/data_loader.ex b/lib/polar_web/live/root_live/data_loader.ex new file mode 100644 index 0000000..dfdfa6a --- /dev/null +++ b/lib/polar_web/live/root_live/data_loader.ex @@ -0,0 +1,43 @@ +defmodule PolarWeb.RootLive.DataLoader do + alias Polar.Repo + alias Polar.Streams.Product + alias Polar.Streams.Version + + import Ecto.Query, only: [from: 2] + + def load_tabs do + from( + p in Product, + select: %{os: p.os, count: count(p.id)}, + group_by: [:os], + order_by: [:os] + ) + |> Repo.all() + |> Enum.with_index(1) + end + + def load_versions(filter) do + query = + from( + v in Version, + join: p in assoc(v, :product), + preload: [{:product, p}], + where: v.current_state == ^"active", + order_by: [asc: p.os], + order_by: [desc: p.release], + order_by: [desc: v.inserted_at] + ) + + Enum.reduce(filter, query, &filter/2) + |> Repo.all() + end + + defp filter({"os", os}, queryable) do + from(v in queryable, + join: p in assoc(v, :product), + where: p.os == ^os + ) + end + + defp filter(_, queryable), do: queryable +end