defmodule LivebookWeb.Hub.New.FlyComponent do use LivebookWeb, :live_component import Ecto.Changeset, only: [get_field: 2, add_error: 3] alias Livebook.EctoTypes.HexColor alias Livebook.Hubs.{Fly, FlyClient} @impl true def update(assigns, socket) do {:ok, socket |> assign(assigns) |> assign( base: %Fly{}, changeset: Fly.change_hub(%Fly{}), selected_app: nil, select_options: [], apps: [] )} end @impl true def render(assigns) do ~H"""
<.form :let={f} id={@id} class="flex flex-col space-y-4" for={@changeset} phx-submit="save" phx-change="validate" phx-target={@myself} phx-debounce="blur" > <.input_wrapper form={f} field={:access_token} class="flex flex-col space-y-1">
Access Token
<%= password_input(f, :access_token, phx_change: "fetch_data", phx_debounce: "blur", phx_target: @myself, value: access_token(@changeset), class: "input w-full phx-form-error:border-red-300", autofocus: true, spellcheck: "false", autocomplete: "off" ) %> <%= if length(@apps) > 0 do %> <.input_wrapper form={f} field={:application_id} class="flex flex-col space-y-1">
Application
<%= select(f, :application_id, @select_options, class: "input") %>
<.input_wrapper form={f} field={:hub_name} class="flex flex-col space-y-1">
Name
<%= text_input(f, :hub_name, class: "input") %> <.input_wrapper form={f} field={:hub_color} class="flex flex-col space-y-1">
Color
<.hex_color_input form={f} field={:hub_color} randomize={JS.push("randomize_color", target: @myself)} />
<%= submit("Add Hub", class: "button-base button-blue", phx_disable_with: "Add...", disabled: not @changeset.valid? ) %> <% end %>
""" end @impl true def handle_event("fetch_data", %{"fly" => %{"access_token" => token}}, socket) do case FlyClient.fetch_apps(token) do {:ok, apps} -> opts = select_options(apps) base = %Fly{access_token: token, hub_color: HexColor.random()} changeset = Fly.change_hub(base) {:noreply, assign(socket, changeset: changeset, base: base, select_options: opts, apps: apps)} {:error, _} -> changeset = %Fly{} |> Fly.change_hub(%{access_token: token}) |> add_error(:access_token, "is invalid") {:noreply, assign(socket, changeset: changeset, base: %Fly{}, select_options: [], apps: [])} end end def handle_event("randomize_color", _, socket) do handle_event("validate", %{"fly" => %{"hub_color" => HexColor.random()}}, socket) end def handle_event("save", %{"fly" => params}, socket) do if socket.assigns.changeset.valid? do case Fly.create_hub(socket.assigns.selected_app, params) do {:ok, hub} -> {:noreply, socket |> put_flash(:success, "Hub added successfully") |> push_redirect(to: Routes.hub_path(socket, :edit, hub.id))} {:error, changeset} -> {:noreply, assign(socket, changeset: changeset)} end else {:noreply, socket} end end def handle_event("validate", %{"fly" => attrs}, socket) do params = Map.merge(socket.assigns.changeset.params, attrs) application_id = params["application_id"] selected_app = Enum.find(socket.assigns.apps, &(&1.application_id == application_id)) opts = select_options(socket.assigns.apps, application_id) changeset = Fly.change_hub(selected_app || socket.assigns.base, params) {:noreply, assign(socket, changeset: changeset, selected_app: selected_app, select_options: opts)} end defp select_options(hubs, app_id \\ nil) do disabled_option = [key: "Select one application", value: "", selected: true, disabled: true] options = for fly <- hubs do [ key: "#{fly.organization_name} - #{fly.application_id}", value: fly.application_id, selected: fly.application_id == app_id ] end [disabled_option] ++ options end defp access_token(changeset), do: get_field(changeset, :access_token) end