Packages
phoenix_kit
1.7.76
1.7.208
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/publishing/web/settings.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={@page_title}
current_path={@current_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="container flex flex-col mx-auto px-4 py-6">
<%!-- Header Section --%>
<.admin_page_header
back={PhoenixKit.Utils.Routes.path("/admin")}
title={gettext("Publishing Settings")}
subtitle={gettext("Manage caching and performance settings for the publishing module.")}
/>
<div class="max-w-2xl mx-auto space-y-6">
<%!-- Cache Management Section --%>
<div class="card bg-base-100 shadow-xl border border-base-200">
<div class="card-body space-y-6">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div>
<h2 class="text-2xl font-semibold text-base-content">
<.icon name="hero-bolt" class="w-6 h-6 inline-block mr-2" />
{gettext("Listing Cache")}
</h2>
<p class="text-sm text-base-content/70">
{gettext(
"Cached listing data speeds up listing pages. Cache is automatically updated when posts change."
)}
</p>
</div>
<% any_listing_cache = @memory_cache_enabled %>
<%= if @cache_groups != [] and any_listing_cache do %>
<button
type="button"
phx-click="regenerate_all_caches"
class="btn btn-primary btn-sm whitespace-nowrap"
>
<.icon name="hero-arrow-path" class="w-4 h-4 mr-1" />
{gettext("Regenerate All")}
</button>
<% end %>
</div>
<%!-- Cache Settings Toggles --%>
<div class="grid grid-cols-1 gap-4">
<%!-- Memory Cache Toggle --%>
<div class="flex items-center justify-between p-4 bg-base-200 rounded-lg">
<div class="flex items-center gap-3">
<.icon name="hero-cpu-chip" class="w-5 h-5 text-base-content/70" />
<div>
<p class="font-medium">{gettext("Memory Cache")}</p>
<p class="text-xs text-base-content/60">
{gettext("Store in :persistent_term for sub-microsecond reads")}
</p>
</div>
</div>
<input
type="checkbox"
class="toggle toggle-primary"
checked={@memory_cache_enabled}
phx-click="toggle_memory_cache"
/>
</div>
</div>
<%= if not @memory_cache_enabled do %>
<div class="alert alert-warning">
<.icon name="hero-exclamation-triangle" class="w-5 h-5" />
<span>
{gettext(
"Memory cache is disabled. Listing pages will query the database on every request."
)}
</span>
</div>
<% end %>
<%= if @cache_groups == [] do %>
<div class="alert">
<.icon name="hero-information-circle" class="w-5 h-5" />
<span>{gettext("Create a publishing group to manage its cache.")}</span>
</div>
<% else %>
<% any_cache_enabled = @memory_cache_enabled %>
<%= if any_cache_enabled do %>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th>{gettext("Group")}</th>
<th class="text-center">{gettext("Posts")}</th>
<%= if @memory_cache_enabled do %>
<th class="text-center">
<span class="flex items-center justify-center gap-1">
<.icon name="hero-cpu-chip" class="w-4 h-4" />
{gettext("Memory")}
</span>
</th>
<% end %>
<th class="text-right">{gettext("Actions")}</th>
</tr>
</thead>
<tbody>
<%= for group <- @cache_groups do %>
<% cache = @cache_status[group["slug"]] %>
<tr>
<td class="font-medium">{group["name"]}</td>
<td class="text-center">
<%= if cache.post_count do %>
<span class="font-mono text-sm">{cache.post_count}</span>
<% else %>
<span class="text-base-content/50">—</span>
<% end %>
</td>
<%= if @memory_cache_enabled do %>
<td class="text-center">
<%= if cache.in_memory do %>
<.icon name="hero-check-circle" class="w-5 h-5 text-success" />
<% else %>
<.icon name="hero-x-circle" class="w-5 h-5 text-base-content/30" />
<% end %>
</td>
<% end %>
<td class="text-right">
<div class="flex justify-end gap-2">
<%= if cache.exists or cache.in_memory do %>
<button
type="button"
phx-click="invalidate_cache"
phx-value-slug={group["slug"]}
class="btn btn-outline btn-xs text-error tooltip tooltip-bottom"
data-tip={gettext("Clear cache")}
>
<.icon name="hero-trash" class="w-4 h-4 hidden sm:inline" />
<span class="sm:hidden whitespace-nowrap">
{gettext("Clear cache")}
</span>
</button>
<% end %>
<button
type="button"
phx-click="regenerate_cache"
phx-value-slug={group["slug"]}
class="btn btn-outline btn-xs tooltip tooltip-bottom"
data-tip={gettext("Regenerate cache")}
>
<.icon name="hero-arrow-path" class="w-4 h-4 hidden sm:inline" />
<span class="sm:hidden whitespace-nowrap">
{gettext("Regenerate cache")}
</span>
</button>
</div>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<div class="text-xs text-base-content/50 space-y-1">
<p>
<.icon name="hero-information-circle" class="w-3 h-3 inline" />
{gettext(
"\"In Memory\" means the cache is loaded into :persistent_term for sub-microsecond reads."
)}
</p>
<p>
<.icon name="hero-arrow-path" class="w-3 h-3 inline" />
{gettext("Regenerate scans all posts and rebuilds the cache.")}
</p>
</div>
<% end %>
<% end %>
</div>
</div>
<%!-- Render Cache Section --%>
<div class="card bg-base-100 shadow-xl border border-base-200">
<div class="card-body space-y-4">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div>
<h2 class="text-2xl font-semibold text-base-content">
<.icon name="hero-document-text" class="w-6 h-6 inline-block mr-2" />
{gettext("Render Cache")}
</h2>
<p class="text-sm text-base-content/70">
{gettext(
"Cached rendered HTML for published posts. Uses content-hash keys so edits auto-invalidate."
)}
</p>
</div>
<%= if @render_cache_enabled do %>
<button
type="button"
phx-click="clear_render_cache"
class="btn btn-outline btn-error btn-sm whitespace-nowrap"
data-confirm={
gettext(
"Clear all cached rendered posts? They will be re-rendered on next view."
)
}
>
<.icon name="hero-trash" class="w-4 h-4 mr-1" />
{gettext("Clear All")}
</button>
<% end %>
</div>
<%!-- Global Render Cache Toggle --%>
<div class="flex items-center justify-between p-4 bg-base-200 rounded-lg">
<div class="flex items-center gap-3">
<.icon name="hero-bolt" class="w-5 h-5 text-base-content/70" />
<div>
<p class="font-medium">{gettext("Render Cache")}</p>
<p class="text-xs text-base-content/60">
{gettext("Cache rendered HTML for published posts (6-hour TTL)")}
</p>
</div>
</div>
<input
type="checkbox"
class="toggle toggle-primary"
checked={@render_cache_enabled}
phx-click="toggle_render_cache"
/>
</div>
<%= if not @render_cache_enabled do %>
<div class="alert alert-warning">
<.icon name="hero-exclamation-triangle" class="w-5 h-5" />
<span>
{gettext("Render cache is disabled. Posts will be rendered on every request.")}
</span>
</div>
<% else %>
<%!-- Stats Display --%>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="stat bg-base-200 rounded-lg p-4">
<div class="stat-title text-xs">{gettext("Cache Hits")}</div>
<div class="stat-value text-lg font-mono">{@render_cache_stats[:hits] || 0}</div>
</div>
<div class="stat bg-base-200 rounded-lg p-4">
<div class="stat-title text-xs">{gettext("Cache Misses")}</div>
<div class="stat-value text-lg font-mono">
{@render_cache_stats[:misses] || 0}
</div>
</div>
<div class="stat bg-base-200 rounded-lg p-4">
<div class="stat-title text-xs">{gettext("Entries Cached")}</div>
<div class="stat-value text-lg font-mono">{@render_cache_stats[:puts] || 0}</div>
</div>
<div class="stat bg-base-200 rounded-lg p-4">
<div class="stat-title text-xs">{gettext("Hit Rate")}</div>
<div class="stat-value text-lg font-mono">
<%= if @render_cache_stats[:hit_rate] do %>
{Float.round(@render_cache_stats[:hit_rate] * 100, 1)}%
<% else %>
0%
<% end %>
</div>
</div>
</div>
<%!-- Per-Group Render Cache Table --%>
<%= if @cache_groups != [] do %>
<div class="overflow-x-auto">
<table class="table table-zebra">
<thead>
<tr>
<th>{gettext("Group")}</th>
<th class="text-center">{gettext("Enabled")}</th>
<th class="text-right">{gettext("Actions")}</th>
</tr>
</thead>
<tbody>
<%= for group <- @cache_groups do %>
<% slug = group["slug"] %>
<% enabled = @render_cache_per_group[slug] %>
<tr>
<td class="font-medium">{group["name"]}</td>
<td class="text-center">
<input
type="checkbox"
class="toggle toggle-primary toggle-sm"
checked={enabled}
phx-click="toggle_group_render_cache"
phx-value-slug={slug}
/>
</td>
<td class="text-right">
<%= if enabled do %>
<button
type="button"
phx-click="clear_group_render_cache"
phx-value-slug={slug}
class="btn btn-outline btn-xs text-error tooltip tooltip-bottom"
data-tip={gettext("Clear cache for this group")}
>
<.icon name="hero-trash" class="w-4 h-4 hidden sm:inline" />
<span class="sm:hidden whitespace-nowrap">
{gettext("Clear cache for this group")}
</span>
</button>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
<% end %>
<% end %>
<div class="text-xs text-base-content/50">
<p>
<.icon name="hero-information-circle" class="w-3 h-3 inline" />
{gettext(
"Render cache stores pre-rendered HTML for published posts. Cache keys include content hashes, so edits automatically use fresh renders. TTL: 6 hours."
)}
</p>
</div>
</div>
</div>
</div>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>