defmodule GitGudWeb.RepoLive.Commit do
use GitGudWeb, :live_view
alias GitGud.Git
alias GitGud.Repositories
alias GitGud.Repositories.Storage
@impl true
def mount(%{"owner" => owner, "name" => name, "sha" => hex}, _session, socket) do
repo =
Repositories.get_repository_by_path!(owner, name)
|> GitGud.Repo.preload([:owner, :organization])
with {:ok, sha} <- Git.from_hex(hex),
{:ok, commit} <- Repositories.get_commit(repo, sha) do
base = if commit.parent_shas == [], do: nil, else: hd(commit.parent_shas)
{:ok, stats} = Repositories.get_diff_stats(repo, base, sha)
diff_files = load_diff(repo, base, sha)
{:ok,
socket
|> assign(:repo, repo)
|> assign(:handle, Storage.repo_handle(repo))
|> GitGudWeb.RepoLive.Header.assign_chrome(repo)
|> assign(:commit, commit)
|> assign(:stats, stats)
|> assign(:diff_files, diff_files)
|> assign(:loaded_diff_idx, GitGudWeb.DiffComponents.default_loaded(diff_files))
|> assign(:page_title, "#{owner}/#{name}: #{Git.short(sha)}")}
else
_ -> {:ok, push_navigate(socket, to: ~p"/r/#{owner}/#{name}")}
end
end
defp load_diff(repo, base, head) do
case Repositories.get_diff(repo, base, head) do
{:ok, files} -> files
_ -> []
end
end
@impl true
def handle_event("expand_diff_file", params, socket),
do: {:noreply, GitGudWeb.DiffComponents.expand(socket, params)}
@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}
/>
<header class="space-y-1">
<h1 class="text-xl font-semibold">
{commit_title(@commit)}
</h1>
<p class="text-xs opacity-60 mt-1 font-mono">
{Git.short(@commit.sha)} · {@commit.author_name} · {format_dt(@commit.committed_at)}
</p>
<.commit_status_badges repo={@repo} sha={@commit.sha} class="mt-1" />
</header>
<section class="flex gap-4 text-sm">
<span><strong>{@stats.files_changed}</strong> files</span>
<span class="text-success">+{@stats.insertions}</span>
<span class="text-error">-{@stats.deletions}</span>
</section>
<details :if={commit_body(@commit) != ""} class="text-sm opacity-80">
<summary class="cursor-pointer">Message</summary>
<pre
class="mt-2 p-3 bg-base-200 rounded text-xs whitespace-pre-wrap"
phx-no-curly-interpolation
>{commit_body(@commit)}</pre>
</details>
<section>
<h2 class="font-semibold mb-2">Files changed</h2>
<GitGudWeb.DiffComponents.diff
files={@diff_files}
theme={@editor_theme}
loaded_idx={@loaded_diff_idx}
/>
</section>
<p class="text-xs opacity-60">
Parents:
<span :for={p <- @commit.parent_shas} class="font-mono">
<.link navigate={~p"/r/#{@handle}/#{@repo.name}/commit/#{Git.to_hex(p)}"}>
{Git.short(p)}
</.link>
</span>
</p>
</div>
</Layouts.app>
"""
end
defp commit_title(c), do: c.message |> String.split("\n", parts: 2) |> hd()
defp commit_body(c) do
case String.split(c.message, "\n", parts: 2) do
[_title, rest] -> String.trim(rest)
_ -> ""
end
end
defp format_dt(nil), do: "?"
defp format_dt(dt), do: Calendar.strftime(dt, "%Y-%m-%d %H:%M")
end
3.7 KiB · text
5af55d9