defmodule AshHqWeb.Components.Search do @moduledoc "The search overlay modal" use Surface.LiveComponent require Ash.Query alias AshHqWeb.Components.CalloutText alias AshHqWeb.DocRoutes alias Surface.Components.{Form, LivePatch} alias Surface.Components.Form.{Checkbox, Label} prop open, :boolean, default: false prop close, :event, required: true prop libraries, :list, required: true prop selected_versions, :map, required: true prop change_versions, :event, required: true prop selected_types, :list, required: true prop change_types, :event, required: true prop uri, :string, required: true data versions, :map, default: %{} data search, :string, default: "" data item_list, :list, default: [] data selected_item, :string def render(assigns) do ~F""" """ end defp render_items(assigns, items) do ~F""" {#for item <- items}
{render_item_type(assigns, item)}
{#for {path_item, index} <- Enum.with_index(item_path(item))} {#if index != 0} {/if}
{path_item}
{/for}
{#if item.name_matches} {#else} {item_name(item)} {/if}
{raw(item.search_headline)}
{/for} """ end defp render_item_type(assigns, item) do case item_type(item) do "Function" -> case item.type do type when type in [:function, :macro] -> ~F""" """ :callback -> ~F""" """ :type -> ~F""" """ end "Module" -> ~F""" """ type when type in ["Dsl", "Option"] -> AshHqWeb.Components.DocSidebar.render_icon(assigns, item.extension_type) "Guide" -> ~F""" """ _ -> ~F""" """ end end defp item_name(%{name: name}), do: name defp item_name(%{version: version}), do: version defp item_path(%{ library_name: library_name, extension_name: extension_name, path: path }) do [library_name, extension_name, path] |> List.flatten() end defp item_path(%{ library_name: library_name, module_name: module_name }) do [library_name, module_name] end defp item_path(%{library_name: library_name}) do [library_name] end defp item_path(%{library_version: %{library_name: library_name}}) do [library_name] end defp item_path(_) do [] end def mount(socket) do {:ok, socket} end def update(assigns, socket) do {:ok, socket |> assign(assigns) |> search()} end def handle_event("search", %{"search" => search}, socket) do {:noreply, socket |> assign(:search, search) |> search()} end def handle_event("select-next", _, socket) do if socket.assigns[:selected_item] && socket.assigns[:item_list] do next = socket.assigns.item_list |> Enum.drop_while(&(&1.id != socket.assigns.selected_item.id)) |> Enum.at(1) {:noreply, set_selected_item(socket, next)} else {:noreply, socket} end end def handle_event("select-previous", _, socket) do if socket.assigns[:selected_item] && socket.assigns[:item_list] do next = socket.assigns.item_list |> Enum.reverse() |> Enum.drop_while(&(&1.id != socket.assigns.selected_item.id)) |> Enum.at(1) {:noreply, set_selected_item(socket, next)} else {:noreply, socket} end end def handle_event("go-to-doc", _, socket) do case Enum.find(socket.assigns.item_list, fn item -> item.id == socket.assigns.selected_item.id end) do nil -> {:noreply, socket} item -> {:noreply, push_redirect(socket, to: DocRoutes.doc_link(item))} end end defp item_type(%resource{}) do AshHq.Docs.Extensions.Search.item_type(resource) end defp search(socket) do if socket.assigns[:search] in [nil, ""] || socket.assigns[:selected_versions] in [nil, %{}] || socket.assigns[:selected_types] == [] do assign(socket, results: %{}, item_list: []) else versions = Enum.map(socket.assigns.selected_versions, fn {library_id, "latest"} -> Enum.find_value(socket.assigns.libraries, fn library -> if library.id == library_id do case AshHqWeb.Helpers.latest_version(library) do nil -> nil version -> version.id end end end) {_, version_id} -> version_id end) |> Enum.reject(&(&1 == "" || is_nil(&1))) item_list = AshHq.Docs.Search.run!( socket.assigns.search, versions, %{types: socket.assigns[:selected_types]} ) selected_item = Enum.at(item_list, 0) socket |> assign(:item_list, item_list) |> set_selected_item(selected_item) end end defp set_selected_item(socket, nil), do: socket defp set_selected_item(socket, selected_item) do socket |> assign(:selected_item, selected_item) |> push_event("js:scroll-to", %{id: selected_item.id}) end end