defmodule GitGudWeb.DeployKeyLive.Index do
use GitGudWeb, :live_view
alias GitGud.DeployKeys
alias GitGud.DeployKeys.DeployKey
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])
{:ok,
socket
|> assign(:repo, repo)
|> assign(:handle, Storage.repo_handle(repo))
|> GitGudWeb.RepoLive.Header.assign_chrome(repo)
|> stream(:keys, DeployKeys.list_keys(repo))
|> assign_form(DeployKey.changeset(%DeployKey{}, %{}))
|> assign(:page_title, "Deploy keys — #{owner}/#{name}")}
end
defp assign_form(socket, cs), do: assign(socket, :form, to_form(cs))
@impl true
def handle_event("validate", %{"deploy_key" => attrs}, socket) do
cs = %DeployKey{} |> DeployKey.changeset(attrs) |> Map.put(:action, :validate)
{:noreply, assign_form(socket, cs)}
end
def handle_event("add", %{"deploy_key" => attrs}, socket) do
case DeployKeys.create_key(socket.assigns.repo, attrs) do
{:ok, key} ->
{:noreply,
socket
|> stream_insert(:keys, key, at: 0)
|> assign_form(DeployKey.changeset(%DeployKey{}, %{}))
|> put_flash(:info, "Deploy key added.")}
{:error, cs} ->
{:noreply, assign_form(socket, cs)}
end
end
def handle_event("delete", %{"id" => id}, socket) do
key = DeployKeys.get_key!(id)
if key.repository_id == socket.assigns.repo.id do
{:ok, _} = DeployKeys.delete_key(key)
{:noreply, socket |> stream_delete(:keys, key) |> put_flash(:info, "Removed.")}
else
{:noreply, socket}
end
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="space-y-6">
<GitGudWeb.RepoLive.Header.header
repo={@repo}
handle={@handle}
current_scope={@current_scope}
has_packages?={@has_packages?}
can_admin?={@can_admin?}
latest_run={@latest_run}
/>
<.repo_settings_header handle={@handle} repo={@repo} current={:deploy_keys} />
<.form
for={@form}
id="deploy-key-form"
phx-change="validate"
phx-submit="add"
class="space-y-3 max-w-2xl"
>
<.input field={@form[:title]} label="Title" required />
<.input
field={@form[:key]}
type="textarea"
rows="4"
label="Public key"
required
placeholder="ssh-ed25519 AAAA..."
/>
<.input field={@form[:read_write]} type="checkbox" label="Allow write access" />
<button type="submit" class="btn btn-sm btn-primary">Add</button>
</.form>
<ul id="deploy-keys" phx-update="stream" class="divide-y divide-base-300 max-w-2xl">
<li class="hidden only:block py-6 opacity-60 text-sm">No deploy keys yet.</li>
<li :for={{id, key} <- @streams.keys} id={id} class="py-3 flex items-start gap-3">
<div class="flex-1">
<p class="font-medium">{key.title}</p>
<p class="text-xs font-mono opacity-60 break-all">{key.fingerprint}</p>
<p class="text-xs opacity-60">
{if key.read_write, do: "read+write", else: "read-only"}
<span :if={key.last_used_at}>
· last used {format_dt(key.last_used_at)}
</span>
</p>
</div>
<button
type="button"
class="btn btn-xs btn-ghost"
phx-click="delete"
phx-value-id={key.id}
data-confirm="Delete this deploy key?"
>
<.icon name="hero-trash" class="size-4" />
</button>
</li>
</ul>
</div>
</Layouts.app>
"""
end
defp format_dt(dt), do: Calendar.strftime(dt, "%Y-%m-%d %H:%M")
end
4.0 KiB · text
5af55d9