defmodule Vibe.Web.StorageLive do @moduledoc "LiveView for SQLite-backed storage search and maintenance status." use Vibe.Web, :live_view @impl true def mount(params, _session, socket) do query = Map.get(params, "q", "") {:ok, assign_storage(socket, query)} end @impl true def handle_event("search", %{"q" => query}, socket) do {:noreply, assign_storage(socket, query)} end @impl true def render(assigns) do ~H""" <.app_shell current={:storage} title="Storage" subtitle="Search sessions, memory, and indexed runtime history.">
<.metric_tile label="Sessions" value={@session_count} /> <.metric_tile label="Memory" value={@memory_count} /> <.metric_tile label="UI events" value={table_count(@storage_status, "ui_events")} /> <.metric_tile label="Artifacts" value={artifact_summary_text(@artifact_summary)} />
<%= cond do %> <% @query == "" -> %>

Search indexed sessions, UI events, and curated memory.

Try markdown, eval, storage, or session.

<% @error -> %>
{inspect(@error)}
<% @results == [] -> %>
No matches.
<% true -> %> <%= for result <- @results do %>

{result.source}

rank {Float.round(result.rank || 0.0, 3)}

{Phoenix.HTML.raw(result.snippet || result.text || "")}

<.link :if={result.source == :session} navigate={~p"/sessions/#{result.owner_id}"} class="break-words font-mono text-vibe-accent-strong hover:text-vibe-accent-strong focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-vibe-accent/70 [overflow-wrap:anywhere]">{result.owner_id} {result.owner_id} {result.at}
<% end %> <% end %>
""" end defp assign_storage(socket, query) do query = String.trim(query || "") {results, error} = case run_search(query) do {:ok, results} -> {results, nil} {:error, error} -> {[], error} end socket |> assign(:query, query) |> assign(:results, results) |> assign(:error, error) |> assign(:storage_status, Vibe.Storage.status()) |> assign(:session_count, length(Vibe.Session.Store.list())) |> assign(:memory_count, memory_count()) |> assign(:artifact_summary, artifact_summary()) end defp run_search(""), do: {:ok, []} defp run_search(query), do: Vibe.Storage.Search.query(query, limit: 25) defp memory_count do length(Vibe.Memory.list(:global)) + length(Vibe.Memory.list(:user)) end defp artifact_summary do Vibe.Session.Store.list() |> Enum.map(&Vibe.Files.Artifacts.session_artifact_summary(&1.id)) |> Enum.reduce(%{count: 0, bytes: 0}, fn summary, acc -> %{count: acc.count + summary.count, bytes: acc.bytes + summary.bytes} end) end defp artifact_summary_text(%{count: count, bytes: bytes}), do: "#{count} / #{Vibe.Format.bytes(bytes)}" defp table_count(%{tables: tables}, table), do: Map.get(tables, table, 0) defp table_count(_status, _table), do: 0 end