Packages

phoenix_kit

1.7.49
1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib modules db web index.ex
Raw

lib/modules/db/web/index.ex

defmodule PhoenixKit.Modules.DB.Web.Index do
@moduledoc """
Admin DB index - lists all tables with stats.
Supports live updates - when any table changes, the stats and
table list are refreshed automatically.
"""
use PhoenixKitWeb, :live_view
alias PhoenixKit.Modules.DB
alias PhoenixKit.Modules.DB.Listener
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@impl true
def mount(params, _session, socket) do
locale = params["locale"] || Routes.get_default_admin_locale()
page = parse_int(params["page"], 1)
search = params["search"] || ""
# Subscribe to all table changes for live updates
if connected?(socket) do
Listener.subscribe_all()
end
tables = DB.list_tables(%{page: page, search: search})
socket =
socket
|> assign(:page_title, "DB")
|> assign(:project_title, Settings.get_project_title())
|> assign(:current_locale, locale)
|> assign(:current_path, Routes.path("/admin/db", locale: locale))
|> assign(:search, search)
|> assign(:tables, tables)
|> assign(:stats, DB.database_stats())
{:ok, socket}
end
@impl true
def handle_params(params, _uri, socket) do
page = parse_int(params["page"], 1)
search = params["search"] || ""
tables = DB.list_tables(%{page: page, search: search})
{:noreply,
socket
|> assign(:search, search)
|> assign(:tables, tables)}
end
@impl true
def handle_event("search", %{"search" => value}, socket) do
{:noreply, push_patch(socket, to: build_path(socket, %{search: value, page: 1}))}
end
@impl true
def handle_event("change_page", %{"page" => page}, socket) do
{:noreply, push_patch(socket, to: build_path(socket, %{page: page}))}
end
# Debounce interval for live updates (ms)
@refresh_debounce_ms 2000
# Handle live updates from PostgreSQL NOTIFY
@impl true
def handle_info({:table_changed, _schema, _table, _operation, _row_id}, socket) do
# Debounce: schedule a refresh instead of doing it immediately
socket = schedule_debounced_refresh(socket)
{:noreply, socket}
end
@impl true
def handle_info(:debounced_refresh, socket) do
# Clear the pending refresh flag and do the actual refresh
socket = assign(socket, :refresh_scheduled, false)
# Refresh tables list and stats
tables =
DB.list_tables(%{
page: socket.assigns.tables.page,
search: socket.assigns.search
})
socket =
socket
|> assign(:tables, tables)
|> assign(:stats, DB.database_stats())
{:noreply, socket}
end
# Schedule a debounced refresh - only schedules if one isn't already pending
defp schedule_debounced_refresh(socket) do
if socket.assigns[:refresh_scheduled] do
socket
else
Process.send_after(self(), :debounced_refresh, @refresh_debounce_ms)
assign(socket, :refresh_scheduled, true)
end
end
defp parse_int(nil, default), do: default
defp parse_int(value, default) when is_binary(value) do
case Integer.parse(value) do
{int, _} when int > 0 -> int
_ -> default
end
end
defp parse_int(value, _default) when is_integer(value) and value > 0, do: value
defp parse_int(_, default), do: default
defp build_path(socket, overrides) do
# Normalize overrides to string keys
overrides = Map.new(overrides, fn {k, v} -> {to_string(k), v} end)
params =
%{
"search" => socket.assigns.search,
"page" => socket.assigns.tables.page
}
|> Map.merge(overrides)
|> Enum.reject(fn {_k, v} -> v in [nil, "", 1, "1"] end)
|> Map.new()
base = Routes.path("/admin/db", locale: socket.assigns.current_locale)
if map_size(params) == 0 do
base
else
base <> "?" <> URI.encode_query(params)
end
end
end