defmodule AshHqWeb.Components.Search do
use Surface.LiveComponent
require Ash.Query
alias Surface.Components.Form
alias Surface.Components.Form.{Label, Select}
prop open, :boolean, default: false
prop close, :event, required: true
data versions, :map, default: %{}
data selected_versions, :map, default: %{}
data search, :string, default: ""
data results, :map, default: %{}
data libraries, :list, default: []
# style={"display: none;"}
def render(assigns) do
~F"""
{render_results(assigns, @results)}
"""
end
defp render_results(assigns, results) do
~F"""
{#for {group, result} <- @results}
{group}
{/for}
"""
end
def mount(socket) do
socket =
AshPhoenix.LiveView.keep_live(
socket,
:libraries,
fn _socket ->
versions_query =
AshHq.Docs.LibraryVersion
|> Ash.Query.sort(version: :desc)
|> Ash.Query.filter(processed == true)
AshHq.Docs.Library.read!(load: [versions: versions_query])
end,
after_fetch: fn results, socket ->
socket
|> assign(
:selected_versions,
Map.new(results, fn library ->
version = Enum.at(library.versions, 0)
{library.id, version && version.id}
end)
)
|> search()
end
)
{:ok, socket}
end
def handle_event("change_versions", %{"versions" => versions}, socket) do
{:noreply,
socket
|> assign(:selected_versions, versions)
|> search()}
end
def handle_event("search", %{"search" => search}, socket) do
{:noreply, socket |> assign(:search, search) |> search()}
end
defp search(socket) do
if socket.assigns[:search] in [nil, ""] || socket.assigns[:selected_versions] in [nil, %{}] do
assign(socket, :results, %{})
else
docs =
AshHq.Docs.Dsl.search!(
socket.assigns.search,
Map.values(socket.assigns.selected_versions),
query: Ash.Query.limit(AshHq.Docs.Dsl, 10),
load: [:extension_type]
)
results =
AshHq.Docs.Option.search!(
socket.assigns.search,
Map.values(socket.assigns.selected_versions),
query: Ash.Query.limit(AshHq.Docs.Option, 10),
load: [:extension_type]
)
|> Enum.concat(docs)
|> tap(fn items ->
Enum.map(items, & &1.match_rank) |> IO.inspect()
end)
|> Enum.group_by(& &1.extension_type)
|> Enum.sort_by(fn {_type, items} ->
items
|> Enum.map(& &1.match_rank)
|> Enum.max()
|> Kernel.*(-1)
end)
|> tap(fn stuff ->
stuff
|> Enum.map(fn {_type, items} ->
items
|> Enum.map(& &1.match_rank)
|> Enum.max()
# |> Kernel.*(-1)
end)
|> IO.inspect()
end)
|> Enum.map(fn {type, items} ->
{type, group_by_paths(items)}
end)
assign(socket, :results, results)
end
end
defp group_by_paths(items) do
items
|> Enum.map(&{&1.path, &1})
|> do_group_by_paths()
end
defp do_group_by_paths(items, path_acc \\ []) do
{items_for_group, further} =
Enum.split_with(items, fn
{[], _} ->
true
_ ->
false
end)
further_items =
further
|> Enum.group_by(
fn {[next | _rest], _item} ->
next
end,
fn {[_next | rest], item} ->
{rest, item}
end
)
|> Enum.map(fn {nested, items} ->
{nested, do_group_by_paths(items, path_acc ++ [nested])}
end)
%{path: path_acc, items: items_for_group, further: further_items}
end
end