241 lines
6.8 KiB
Elixir
241 lines
6.8 KiB
Elixir
defmodule BDS.Desktop.ShellLive.TemplateEditor do
|
|
@moduledoc false
|
|
|
|
use Phoenix.LiveComponent
|
|
|
|
alias BDS.{MCP, Templates}
|
|
alias BDS.Desktop.ShellData
|
|
alias BDS.Templates.Template
|
|
|
|
embed_templates("template_editor_html/*")
|
|
|
|
@spec update(map(), Phoenix.LiveView.Socket.t()) :: {:ok, Phoenix.LiveView.Socket.t()}
|
|
@impl true
|
|
def update(%{action: :save} = assigns, socket) do
|
|
socket =
|
|
socket
|
|
|> assign(Map.drop(assigns, [:action]))
|
|
|> do_save()
|
|
|
|
{:ok, socket}
|
|
end
|
|
|
|
def update(assigns, socket) do
|
|
socket =
|
|
socket
|
|
|> assign(assigns)
|
|
|> build_data()
|
|
|
|
{:ok, socket}
|
|
end
|
|
|
|
@spec render(map()) :: Phoenix.LiveView.Rendered.t()
|
|
@impl true
|
|
def render(%{template_editor: nil} = assigns), do: ~H""
|
|
|
|
def render(assigns) do
|
|
template_editor(assigns)
|
|
end
|
|
|
|
@spec handle_event(String.t(), map(), Phoenix.LiveView.Socket.t()) ::
|
|
{:noreply, Phoenix.LiveView.Socket.t()}
|
|
@impl true
|
|
def handle_event("change_template_editor", %{"template_editor" => params}, socket) do
|
|
socket =
|
|
socket
|
|
|> assign(:draft, normalize_params(params))
|
|
|> build_data()
|
|
|
|
{:noreply, socket}
|
|
end
|
|
|
|
def handle_event("save_template_editor", _params, socket) do
|
|
{:noreply, do_save(socket)}
|
|
end
|
|
|
|
def handle_event("publish_template_editor", _params, socket) do
|
|
{:noreply, do_publish(socket)}
|
|
end
|
|
|
|
def handle_event("validate_template_editor", _params, socket) do
|
|
{:noreply, do_validate(socket)}
|
|
end
|
|
|
|
def handle_event("delete_template_editor", _params, socket) do
|
|
{:noreply, do_delete(socket)}
|
|
end
|
|
|
|
defp build_data(socket) do
|
|
template_id = socket.assigns.current_tab.id
|
|
|
|
case Templates.get_template(template_id) do
|
|
nil ->
|
|
assign(socket, :template_editor, nil)
|
|
|
|
%Template{} = template ->
|
|
draft = current_draft(socket.assigns, template)
|
|
|
|
data = %{
|
|
id: template.id,
|
|
title: draft["title"],
|
|
slug: draft["slug"],
|
|
kind: draft["kind"],
|
|
enabled: draft["enabled"],
|
|
content: draft["content"],
|
|
status: template.status || :draft,
|
|
can_publish?: template.status == :draft,
|
|
created_at: template.created_at,
|
|
updated_at: template.updated_at
|
|
}
|
|
|
|
assign(socket, :template_editor, data)
|
|
end
|
|
end
|
|
|
|
defp do_save(socket) do
|
|
template_id = socket.assigns.current_tab.id
|
|
|
|
case Templates.get_template(template_id) do
|
|
nil ->
|
|
socket
|
|
|
|
%Template{} = template ->
|
|
draft = current_draft(socket.assigns, template)
|
|
|
|
with {:ok, %{valid: true}} <- MCP.validate_template(draft["content"] || ""),
|
|
{:ok, _updated} <- Templates.update_template(template.id, template_attrs(draft)) do
|
|
socket
|
|
|> assign(:draft, nil)
|
|
|> build_data()
|
|
|> notify_output(translated("Templates"), translated("Template saved"))
|
|
|> notify_reload()
|
|
else
|
|
{:ok, %{valid: false, errors: errors}} ->
|
|
socket
|
|
|> notify_output(translated("Templates"), Enum.join(errors, "; "), "error")
|
|
|> notify_reload()
|
|
|
|
{:error, reason} ->
|
|
socket
|
|
|> notify_output(translated("Templates"), inspect(reason), "error")
|
|
|> notify_reload()
|
|
end
|
|
end
|
|
end
|
|
|
|
defp do_publish(socket) do
|
|
template_id = socket.assigns.current_tab.id
|
|
|
|
case Templates.get_template(template_id) do
|
|
nil ->
|
|
socket
|
|
|
|
%Template{} = template ->
|
|
draft = current_draft(socket.assigns, template)
|
|
|
|
with {:ok, %{valid: true}} <- MCP.validate_template(draft["content"] || ""),
|
|
{:ok, _updated} <- Templates.update_template(template.id, template_attrs(draft)),
|
|
{:ok, _published} <- Templates.publish_template(template.id) do
|
|
socket
|
|
|> assign(:draft, nil)
|
|
|> build_data()
|
|
|> notify_output(translated("Templates"), translated("Template published"))
|
|
|> notify_reload()
|
|
else
|
|
{:ok, %{valid: false, errors: errors}} ->
|
|
socket
|
|
|> notify_output(translated("Templates"), Enum.join(errors, "; "), "error")
|
|
|> notify_reload()
|
|
|
|
{:error, reason} ->
|
|
socket
|
|
|> notify_output(translated("Templates"), inspect(reason), "error")
|
|
|> notify_reload()
|
|
end
|
|
end
|
|
end
|
|
|
|
defp do_validate(socket) do
|
|
template_id = socket.assigns.current_tab.id
|
|
|
|
case Templates.get_template(template_id) do
|
|
nil ->
|
|
socket
|
|
|
|
%Template{} = template ->
|
|
case MCP.validate_template(current_draft(socket.assigns, template)["content"] || "") do
|
|
{:ok, %{valid: true}} ->
|
|
notify_output(socket, translated("Templates"), translated("Template syntax is valid"))
|
|
|
|
{:ok, %{valid: false, errors: errors}} ->
|
|
notify_output(socket, translated("Templates"), Enum.join(errors, "; "), "error")
|
|
end
|
|
end
|
|
end
|
|
|
|
defp do_delete(socket) do
|
|
template_id = socket.assigns.current_tab.id
|
|
|
|
case Templates.delete_template(template_id, force: true) do
|
|
{:ok, _deleted} ->
|
|
send(self(), {:close_tab, :templates, template_id})
|
|
socket
|
|
|
|
{:error, reason} ->
|
|
socket
|
|
|> notify_output(translated("Templates"), inspect(reason), "error")
|
|
|> notify_reload()
|
|
end
|
|
end
|
|
|
|
defp current_draft(%{draft: draft}, _template) when is_map(draft), do: draft
|
|
|
|
defp current_draft(_assigns, %Template{} = template) do
|
|
%{
|
|
"title" => template.title || "",
|
|
"slug" => template.slug || "",
|
|
"kind" => to_string(template.kind || :post),
|
|
"enabled" => template.enabled != false,
|
|
"content" => template.content || ""
|
|
}
|
|
end
|
|
|
|
defp normalize_params(params) do
|
|
%{
|
|
"title" => Map.get(params, "title", ""),
|
|
"slug" => Map.get(params, "slug", ""),
|
|
"kind" => Map.get(params, "kind", "post"),
|
|
"enabled" => Map.get(params, "enabled") in [true, "true", "on", "1", 1],
|
|
"content" => Map.get(params, "content", "")
|
|
}
|
|
end
|
|
|
|
defp template_attrs(draft) do
|
|
%{
|
|
title: draft["title"],
|
|
slug: draft["slug"],
|
|
kind: normalize_template_kind(draft["kind"]),
|
|
enabled: draft["enabled"],
|
|
content: draft["content"]
|
|
}
|
|
end
|
|
|
|
defp normalize_template_kind("post"), do: :post
|
|
defp normalize_template_kind("list"), do: :list
|
|
defp normalize_template_kind("not-found"), do: :"not-found"
|
|
defp normalize_template_kind("partial"), do: :partial
|
|
defp normalize_template_kind(_kind), do: :post
|
|
|
|
defp notify_output(socket, title, message, level \\ "info") do
|
|
send(self(), {:template_editor_output, title, message, level})
|
|
socket
|
|
end
|
|
|
|
defp notify_reload(socket) do
|
|
send(self(), :reload_shell)
|
|
socket
|
|
end
|
|
|
|
defp translated(text, bindings \\ %{}),
|
|
do: ShellData.translate(text, bindings, BDS.Desktop.UILocale.current())
|
|
end |