Packages

phoenix_kit

1.7.14
1.7.211 1.7.210 1.7.209 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
phoenix_kit lib phoenix_kit_web live modules ai prompts.ex
Raw

lib/phoenix_kit_web/live/modules/ai/prompts.ex

defmodule PhoenixKitWeb.Live.Modules.AI.Prompts do
@moduledoc """
LiveView for AI prompts management.
This module provides an interface for managing reusable AI prompt templates
with variable substitution support.
## Features
- **Prompt Management**: Add, edit, delete, enable/disable AI prompts
- **Variable Display**: Shows extracted variables from prompt content
- **Usage Tracking**: View usage count and last used time
## Route
This LiveView is mounted at `{prefix}/admin/ai/prompts` and requires
appropriate admin permissions.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.AI
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
@sort_options [
{:sort_order, "Order"},
{:name, "Name"},
{:usage_count, "Usage"},
{:last_used_at, "Last Used"},
{:inserted_at, "Created"}
]
@impl true
def mount(_params, session, socket) do
current_path = get_current_path(socket, session)
project_title = Settings.get_setting("project_title", "PhoenixKit")
socket =
socket
|> assign(:current_path, current_path)
|> assign(:page_title, "AI Prompts")
|> assign(:project_title, project_title)
|> assign(:prompts, [])
|> assign(:sort_by, :sort_order)
|> assign(:sort_dir, :asc)
|> assign(:sort_options, @sort_options)
{:ok, socket}
end
@impl true
def handle_params(params, uri, socket) do
{sort_by, sort_dir} = parse_sort_params(params)
current_path = URI.parse(uri).path
socket =
socket
|> assign(:sort_by, sort_by)
|> assign(:sort_dir, sort_dir)
|> assign(:current_path, current_path)
|> reload_prompts()
{:noreply, socket}
end
@valid_sort_fields Enum.map(@sort_options, fn {field, _} -> Atom.to_string(field) end)
defp parse_sort_params(params) do
sort_by =
case params["sort"] do
field when is_binary(field) ->
if field in @valid_sort_fields do
String.to_existing_atom(field)
else
:sort_order
end
_ ->
:sort_order
end
sort_dir =
case params["dir"] do
"asc" -> :asc
"desc" -> :desc
_ -> :asc
end
{sort_by, sort_dir}
end
# ===========================================
# PROMPT ACTIONS
# ===========================================
@impl true
def handle_event("toggle_prompt", %{"id" => id}, socket) do
prompt = AI.get_prompt!(String.to_integer(id))
case AI.update_prompt(prompt, %{enabled: !prompt.enabled}) do
{:ok, _updated} ->
{:noreply,
socket
|> reload_prompts()
|> put_flash(:info, "Prompt #{if prompt.enabled, do: "disabled", else: "enabled"}")}
{:error, _changeset} ->
{:noreply, put_flash(socket, :error, "Failed to update prompt")}
end
end
@impl true
def handle_event("delete_prompt", %{"id" => id}, socket) do
prompt = AI.get_prompt!(String.to_integer(id))
case AI.delete_prompt(prompt) do
{:ok, _} ->
{:noreply,
socket
|> reload_prompts()
|> put_flash(:info, "Prompt deleted")}
{:error, _} ->
{:noreply, put_flash(socket, :error, "Failed to delete prompt")}
end
end
@impl true
def handle_event("sort", %{"by" => field}, socket) do
# Validate field before converting to atom to prevent crashes from malicious input
field =
if field in @valid_sort_fields do
String.to_existing_atom(field)
else
:sort_order
end
current_sort_by = socket.assigns.sort_by
current_sort_dir = socket.assigns.sort_dir
# Toggle direction if same field, otherwise default to desc for usage/last_used, asc for others
sort_dir =
if field == current_sort_by do
if current_sort_dir == :asc, do: :desc, else: :asc
else
if field in [:usage_count, :last_used_at, :inserted_at], do: :desc, else: :asc
end
path = Routes.ai_path() <> "/prompts?sort=#{field}&dir=#{sort_dir}"
{:noreply, push_patch(socket, to: path)}
end
# ===========================================
# PRIVATE HELPERS
# ===========================================
defp reload_prompts(socket) do
sort_by = socket.assigns.sort_by
sort_dir = socket.assigns.sort_dir
prompts = AI.list_prompts(sort_by: sort_by, sort_dir: sort_dir)
assign(socket, :prompts, prompts)
end
defp get_current_path(socket, session) do
case socket.assigns do
%{__changed__: _, current_path: path} when is_binary(path) -> path
_ -> session["current_path"] || Routes.ai_path() <> "/prompts"
end
end
end