3.8 KiB · text 5af55d9
defmodule GitGudWeb.RepoLive.Fork do
use GitGudWeb, :live_view
alias GitGud.Organizations
alias GitGud.Repositories
alias GitGud.Repositories.Storage
@impl true
def mount(%{"owner" => owner, "name" => name}, _session, socket) do
repo =
Repositories.get_repository_by_path!(owner, name)
|> GitGud.Repo.preload([:owner, :organization])
user = socket.assigns.current_scope.user
orgs = Organizations.list_organizations_for(user) |> admin_only(user)
{:ok,
socket
|> assign(:repo, repo)
|> assign(:handle, Storage.repo_handle(repo))
|> GitGudWeb.RepoLive.Header.assign_chrome(repo)
|> assign(:user, user)
|> assign(:orgs, orgs)
|> assign(:page_title, "Fork #{owner}/#{name}")
|> assign(:namespace_choice, "user")
|> assign(:new_name, repo.name)}
end
defp admin_only(orgs, user),
do: Enum.filter(orgs, &Organizations.org_admin?(&1, user))
@impl true
def handle_event("validate", params, socket) do
{:noreply,
socket
|> assign(:namespace_choice, params["namespace"] || socket.assigns.namespace_choice)
|> assign(:new_name, params["name"] || socket.assigns.new_name)}
end
def handle_event("save", %{"namespace" => ns, "name" => name}, socket) do
user = socket.assigns.user
dest =
case ns do
"user" -> user
"org:" <> handle -> Organizations.get_organization_by_handle!(handle)
end
case Repositories.fork(socket.assigns.repo, dest, user, %{"name" => name}) do
{:ok, fork} ->
handle = namespace_handle(ns, user)
{:noreply,
socket
|> put_flash(:info, "Forked.")
|> push_navigate(to: ~p"/r/#{handle}/#{fork.name}")}
{:error, %Ecto.Changeset{} = cs} ->
{:noreply, put_flash(socket, :error, "Could not fork: #{inspect(errors_on(cs))}")}
{:error, reason} ->
{:noreply, put_flash(socket, :error, "Could not fork: #{inspect(reason)}")}
end
end
defp namespace_handle("user", user), do: Storage.owner_handle(user)
defp namespace_handle("org:" <> h, _), do: h
# ExUnit-style errors_on for in-LV inspection (no test_helper dependency).
defp errors_on(cs) do
Ecto.Changeset.traverse_errors(cs, fn {msg, opts} ->
Regex.replace(~r"%{(\w+)}", msg, fn _, k ->
opts |> Keyword.get(String.to_existing_atom(k), k) |> to_string()
end)
end)
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="space-y-4 max-w-xl">
<GitGudWeb.RepoLive.Header.header
repo={@repo}
handle={@handle}
current_scope={@current_scope}
has_packages?={@has_packages?}
can_admin?={@can_admin?}
latest_run={@latest_run}
/>
<h1 class="text-xl font-semibold">Fork</h1>
<form phx-change="validate" phx-submit="save" class="space-y-3">
<label class="flex flex-col gap-1">
<span class="text-sm opacity-70">Destination</span>
<select name="namespace" class="select select-bordered">
<option value="user" selected={@namespace_choice == "user"}>
{Storage.owner_handle(@user)} (you)
</option>
<option
:for={org <- @orgs}
value={"org:" <> org.handle}
selected={@namespace_choice == "org:" <> org.handle}
>
{org.handle}
</option>
</select>
</label>
<label class="flex flex-col gap-1">
<span class="text-sm opacity-70">Name in destination</span>
<input type="text" name="name" value={@new_name} class="input input-bordered" required />
</label>
<button type="submit" class="btn btn-primary">Create fork</button>
</form>
</div>
</Layouts.app>
"""
end
end