defmodule LivebookWeb.SessionLive.PackageSearchComponent do use LivebookWeb, :live_component @impl true def mount(socket) do {:ok, socket} end @impl true def update(assigns, socket) do initial? = socket.assigns[:search] == nil socket = assign(socket, assigns) socket = if initial? do socket |> assign( packages_source: Livebook.Runtime.packages_source(socket.assigns.runtime), search: "" ) |> do_search() else socket end {:ok, socket} end @impl true def render(assigns) do ~H"""

Search packages

Find external packages for your notebook

<.text_field name="search" value={@search} phx-debounce="250" placeholder="Search" autocomplete="off" spellcheck="false" autofocus phx-mounted={JS.focus()} />
<.async_result :let={packages} assign={@packages}> <:loading>
<.remix_icon icon="windy-line" class="text-xl" />
No results
<:failed :let={{:error, message}}>
{Livebook.Utils.upcase_first(message)}
<.remix_icon icon="windy-line" class="text-xl" />
No results
<.package :for={{package, idx} <- Enum.with_index(packages)} package={package} idx={idx} myself={@myself} />
""" end defp package(assigns) do ~H"""
<%= if @package[:url] do %> {@package.name} <% else %> {@package.name} <% end %> {@package.version}
{@package.description}
<.button color="gray" small aria-label="add" phx-click={JS.push("add", value: %{idx: @idx}, target: @myself)} > <.remix_icon icon="add-line" /> Add
""" end @impl true def handle_event("search", %{"search" => search}, socket) do {:noreply, socket |> assign(search: search) |> do_search()} end @impl true def handle_event("submit", %{}, socket) do socket = case socket.assigns.packages do %{result: [first | _]} -> add_dependency(socket, first.dependency) _ -> socket end {:noreply, socket} end @impl true def handle_event("add", %{"idx" => idx}, socket) do package = Enum.fetch!(socket.assigns.packages.result, idx) socket = add_dependency(socket, package.dependency) {:noreply, socket} end defp do_search(socket) do search = socket.assigns.search packages_source = socket.assigns.packages_source assign_async(socket, :packages, fn -> case packages_source do :hex -> case Livebook.Runtime.Dependencies.search_packages_on_hex(search) do {:ok, packages} -> {:ok, %{packages: packages}} {:error, message} -> {:error, message} end {:list, list} -> {:ok, packages} = Livebook.Runtime.Dependencies.search_packages_in_list(list, search) {:ok, %{packages: packages}} end end) end defp add_dependency(socket, dependency) do Livebook.Session.add_dependencies(socket.assigns.session_pid, [dependency]) assign(socket, search: "", packages: Phoenix.LiveView.AsyncResult.ok([])) end end