defmodule TarakanWeb.InfestationComponents do @moduledoc """ Functional infestation surfaces: ranked pattern table and per-pattern repo matrix. """ use Phoenix.Component use Phoenix.VerifiedRoutes, endpoint: TarakanWeb.Endpoint, router: TarakanWeb.Router, statics: TarakanWeb.static_paths() alias TarakanWeb.RepositoryPaths attr :infestations, :list, required: true attr :id, :string, default: "infestation-constellation" attr :compact, :boolean, default: false @doc "Ranked multi-repo patterns (homepage / index)." def constellation(assigns) do max_repos = assigns.infestations |> Enum.map(& &1.repo_count) |> Enum.max(fn -> 1 end) assigns = assign(assigns, :max_repos, max(max_repos, 1)) ~H"""
# Pattern Spread Repos
{i} <.link id={"#{@id}-hub-#{infestation.pattern_key}"} navigate={~p"/infestations/#{infestation.pattern_key}"} class="block min-w-0" > {infestation.severity} {infestation.title} {String.slice(infestation.pattern_key, 0, 12)}…
{infestation.repo_count}
""" end attr :repos, :list, required: true, doc: "pattern_repos rows: one per repository" attr :infestation, :map, required: true attr :pattern_key, :string, required: true attr :id, :string, default: "infestation-graph" @doc """ Per-repo infestation matrix for one pattern. One row per repository, rolled up from that repo's instances. The instance grain (one row per finding) is the separate ledger on the same page. """ def infestation_graph(assigns) do ~H"""
No listed public repositories.
Repository Status Findings
<.link :if={repo[:host]} navigate={RepositoryPaths.repository_path(repo)} class="block truncate font-mono text-xs font-semibold text-ink hover:text-signal hover:underline" > {repo.owner}/{repo.name} {repo.owner}/{repo.name} {repo.status} {repo[:instance_count] || 1} 0 && "text-phosphor", (repo[:open_count] || 0) == 0 && "text-ink-faint" ]}> {repo[:open_count] || 0} <.link :if={repo.occurrence_public_id} navigate={~p"/findings/#{repo.occurrence_public_id}"} class="font-mono text-[11px] text-signal hover:underline" > Finding →
""" end defp bar_pct(count, max) when max > 0 do count |> Kernel./(max) |> Kernel.*(100) |> Float.round(1) |> max(4) |> min(100) end defp bar_pct(_, _), do: 0 end