3.6 KiB · text History 6280797
defmodule GitGudWeb.SymsLive.Top do
@moduledoc """
The instance-wide syms listing.
`/syms` ranks the most-marked repositories overall; `/syms/:sym` ranks
them for one symbol. Both are scoped to what the viewer may read, and
that filtering happens inside the query so the top N is never short.
"""
use GitGudWeb, :live_view
alias GitGud.Repositories.Storage
alias GitGud.Syms
@impl true
def mount(params, _session, socket) do
viewer = socket.assigns.current_scope && socket.assigns.current_scope.user
sym = params["sym"]
cond do
is_nil(sym) ->
{:ok,
socket
|> assign_common(viewer, nil)
|> assign(:entries, Syms.top_repositories(viewer))
|> assign(:page_title, "syms")}
Syms.known?(sym) ->
{:ok,
socket
|> assign_common(viewer, sym)
|> assign(:entries, Syms.top_for_symbol(sym, viewer))
|> assign(:page_title, "syms: #{sym}")}
true ->
{:ok,
socket
|> put_flash(:error, "No such symbol on this instance.")
|> push_navigate(to: ~p"/syms")}
end
end
defp assign_common(socket, viewer, sym) do
socket
|> assign(:symbols, Syms.symbols())
|> assign(:sym, sym)
|> assign(:limit, Syms.top_limit())
|> assign(:global_counts, Syms.global_counts(viewer))
end
@impl true
def render(assigns) do
~H"""
<Layouts.app flash={@flash} current_scope={@current_scope}>
<div class="space-y-4 max-w-3xl">
<h1 class="text-xl font-semibold flex items-center gap-2">
<.link navigate={~p"/syms"} class="link link-hover">syms</.link>
<span :if={@sym} class="opacity-50">/</span>
<span :if={@sym} class="text-2xl leading-none">{@sym}</span>
</h1>
<p :if={@symbols == []} class="text-sm opacity-60">
This instance has no symbols configured, so syms are disabled.
</p>
<div :if={@symbols != []} class="flex flex-wrap items-center gap-2">
<.link
:for={s <- @symbols}
navigate={~p"/syms/#{s}"}
class={["btn btn-xs gap-1", s == @sym && "btn-primary"]}
>
<span class="text-base leading-none">{s}</span>
<span class="opacity-70">{Map.get(@global_counts, s, 0)}</span>
</.link>
</div>
<p :if={@symbols != [] and @entries == []} class="text-sm opacity-60">
Nothing marked yet.
</p>
<ol :if={@entries != []} class="divide-y divide-base-300">
<li :for={{e, i} <- Enum.with_index(@entries, 1)} class="py-3 flex items-baseline gap-3">
<span class="text-xs opacity-40 w-8 shrink-0 text-right">{i}</span>
<div class="min-w-0 flex-1">
<.link
navigate={~p"/r/#{Storage.repo_handle(e.repository)}/#{e.repository.name}"}
class="font-medium link link-hover"
>
{Storage.repo_handle(e.repository)}/{e.repository.name}
</.link>
<p :if={e.repository.description} class="text-xs opacity-60 truncate">
{e.repository.description}
</p>
</div>
<span class="flex flex-wrap items-center gap-2 shrink-0 text-xs">
<span :for={s <- @symbols} :if={Map.get(e.counts, s, 0) > 0} class="opacity-70">
{s} {Map.get(e.counts, s, 0)}
</span>
</span>
</li>
</ol>
<p :if={length(@entries) >= @limit} class="text-xs opacity-50">
Showing the top {@limit}.
</p>
</div>
</Layouts.app>
"""
end
end