Skip to main content

lib/scoria_web/components/approval_inbox_component.ex

defmodule ScoriaWeb.ApprovalInboxComponent do
  use Phoenix.Component

  import ScoriaWeb.UI

  attr(:approvals, :list, required: true)
  attr(:highlight_approval_id, :string, default: nil)
  attr(:density, :atom, default: :compact)
  attr(:on_density_change, :string, default: nil)
  attr(:select_event, :string, default: nil)

  def render(assigns) do
    ~H"""
    <.panel class="scoria-panel--flush">
      <:eyebrow>approvals</:eyebrow>
      <:title>Approval inbox</:title>

      <.table
        id="approvals"
        rows={@approvals}
        density={@density}
        on_density_change={@on_density_change}
      >
        <:col :let={approval} label="Approval">
          <span data-highlight={approval_field(approval, :id) == @highlight_approval_id && "true"}>
            <span class="font-semibold"><%= approval_field(approval, :tool_name) %></span>
            <.badge
              :if={approval_field(approval, :id) == @highlight_approval_id}
              tone={:warn}
              label="New"
              dot={false}
              class="ml-2"
            />
          </span>
        </:col>
        <:col :let={approval} label="Workflow">
          <span class="font-mono"><%= short_id(approval_field(approval, :workflow_run_id)) %></span>
        </:col>
        <:col :let={approval} label="Requested by">
          <%= approval_field(approval, :actor_id) || approval_field(approval, :session_id) || "operator" %>
        </:col>
        <:col :let={_approval} label="Consequence">
          Approval resumes when possible; rejection keeps the workflow paused.
        </:col>
        <:col :let={approval} label="Requested">
          <%= format_requested(approval_field(approval, :inserted_at)) %>
        </:col>
        <:col :let={approval} label="Status">
          <.badge tone={tone(approval_field(approval, :status))} label={status_label(approval_field(approval, :status))} />
        </:col>
        <:action :let={approval}>
          <button
            type="button"
            phx-click={@select_event}
            phx-value-id={@select_event && approval_field(approval, :id)}
            class="scoria-button scoria-button--ghost scoria-button--sm"
          >
            Inspect approval
          </button>
        </:action>
        <:empty>
          <.empty_state title="No approvals waiting">
            The first workflow-owned approval request will appear here with its consequence and status.
          </.empty_state>
        </:empty>
      </.table>
    </.panel>
    """
  end

  defp approval_field(approval, field) do
    Map.get(approval, field) || Map.get(approval, Atom.to_string(field))
  end

  defp short_id(nil), do: "Not recorded"
  defp short_id(id), do: id |> to_string() |> String.slice(0, 8)

  defp format_requested(nil), do: "Not recorded"
  defp format_requested(%DateTime{} = dt), do: Calendar.strftime(dt, "%Y-%m-%d %H:%M")
  defp format_requested(other), do: to_string(other)
end