Packages
phoenix_kit
1.7.83
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
Current section
Files
lib/modules/db/web/activity.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={"#{@project_title} - Live Activity"}
current_path={@current_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container flex-col mx-auto px-4 py-6">
<.admin_page_header back={PhoenixKit.Utils.Routes.path("/admin/db")}>
<div class="flex items-center justify-center gap-3">
<div class={"w-3 h-3 rounded-full #{if @paused, do: "bg-warning", else: "bg-success animate-pulse"}"}>
</div>
<h1 class="text-xl sm:text-2xl lg:text-3xl font-bold text-base-content">
Live Database Activity
</h1>
</div>
<p class="text-sm text-base-content/60 mt-0.5">
<%= if @paused do %>
Paused - {length(@activity_log)} events captured
<% else %>
Monitoring all tables in real-time
<% end %>
</p>
</.admin_page_header>
<%!-- Controls --%>
<div class="flex justify-center gap-2 mb-6">
<button
phx-click="toggle_pause"
class={"btn btn-sm #{if @paused, do: "btn-warning", else: "btn-ghost"}"}
>
<%= if @paused do %>
<.icon name="hero-play" class="w-4 h-4 mr-2" /> Resume
<% else %>
<.icon name="hero-pause" class="w-4 h-4 mr-2" /> Pause
<% end %>
</button>
<button phx-click="clear_log" class="btn btn-ghost btn-sm">
<.icon name="hero-trash" class="w-4 h-4 mr-2" /> Clear
</button>
</div>
<%!-- Filters --%>
<div class="flex gap-4">
<div class="flex flex-col gap-2">
<div class="form-control">
<label class="label py-0">
<span class="label-text text-xs">Table</span>
</label>
<select
name="table"
phx-change="filter_table"
class="select select-bordered select-sm w-56"
>
<option value="">All tables</option>
<%= for table <- @tables do %>
<option value={table} selected={@filter_table == table}>{table}</option>
<% end %>
</select>
</div>
<div class="form-control">
<label class="label py-0">
<span class="label-text text-xs">Operation</span>
</label>
<select
name="operation"
phx-change="filter_operation"
class="select select-bordered select-sm w-56"
>
<option value="">All</option>
<option value="INSERT" selected={@filter_operation == "INSERT"}>INSERT</option>
<option value="UPDATE" selected={@filter_operation == "UPDATE"}>UPDATE</option>
<option value="DELETE" selected={@filter_operation == "DELETE"}>DELETE</option>
</select>
</div>
</div>
<div class="flex-1"></div>
<div class="text-sm text-base-content/70 self-end">
{length(@activity_log)} events
</div>
</div>
<%!-- Activity Log --%>
<div class="bg-base-100 rounded-box shadow border border-base-200 overflow-hidden">
<%= if Enum.empty?(@activity_log) do %>
<div class="p-12 text-center text-base-content/50">
<.icon name="hero-signal" class="w-12 h-12 mx-auto mb-4 opacity-30" />
<p class="text-lg font-medium">Waiting for database activity...</p>
<p class="text-sm mt-2">
INSERT, UPDATE, and DELETE operations will appear here in real-time
</p>
</div>
<% else %>
<div class="divide-y divide-base-200">
<%= for entry <- @activity_log do %>
<div class="p-4 hover:bg-base-200/30 transition-colors" id={"activity-#{entry.id}"}>
<%!-- Header row --%>
<div class="flex items-center gap-3 mb-3">
<span class={"badge #{operation_badge_class(entry.operation)}"}>
{entry.operation}
</span>
<.link
navigate={
PhoenixKit.Utils.Routes.path("/admin/db/#{entry.schema}/#{entry.table}")
}
class="font-mono text-sm link link-hover"
>
{entry.schema}.{entry.table}
</.link>
<%= if entry.row_id do %>
<span class="badge badge-outline badge-sm h-auto">id: {entry.row_id}</span>
<% end %>
<span class="text-xs text-base-content/50 ml-auto font-mono">
{Calendar.strftime(entry.timestamp, "%Y-%m-%d %H:%M:%S")}
</span>
</div>
<%!-- Row data --%>
<%= if entry.row_data do %>
<div class="bg-base-200/50 rounded-lg p-3 overflow-x-auto">
<table class="table table-xs">
<tbody>
<%= for {key, value} <- entry.row_data |> Enum.sort_by(fn {k, _} -> k end) do %>
<tr class={field_highlight_class(entry, key)}>
<td class="font-mono text-xs text-base-content/70 w-40 align-top py-1">
{key}
<%= if key_new?(entry, key) do %>
<span class="badge badge-success badge-xs ml-1">new</span>
<% end %>
<%= if key_changed?(entry, key) do %>
<span class="badge badge-warning badge-xs ml-1">changed</span>
<% end %>
</td>
<td class="font-mono text-xs py-1 break-all">
<%= cond do %>
<% is_nil(value) -> %>
<span class="text-base-content/40 italic">null</span>
<% is_map(value) or is_list(value) -> %>
<details>
<summary class="cursor-pointer text-primary">
{if is_map(value), do: "{ ... }", else: "[ ... ]"}
</summary>
<pre class="mt-1 text-[10px] whitespace-pre-wrap">{format_value(value)}</pre>
</details>
<% is_binary(value) and byte_size(value) > 100 -> %>
<details>
<summary class="cursor-pointer">
{String.slice(value, 0, 100)}...
</summary>
<div class="mt-1 whitespace-pre-wrap">{value}</div>
</details>
<% true -> %>
{inspect(value)}
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% else %>
<%= if entry.operation == "DELETE" do %>
<div class="text-sm text-base-content/50 italic">
Row deleted (data not available)
</div>
<% else %>
<div class="text-sm text-base-content/50 italic">
Row data not available
<%= if is_nil(entry.row_id) do %>
(table may not have an 'id' column)
<% end %>
</div>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>