chore: converted scripts and templates to live components
This commit is contained in:
293
lib/bds/desktop/shell_live/script_editor.ex
Normal file
293
lib/bds/desktop/shell_live/script_editor.ex
Normal file
@@ -0,0 +1,293 @@
|
||||
defmodule BDS.Desktop.ShellLive.ScriptEditor do
|
||||
@moduledoc false
|
||||
|
||||
use Phoenix.LiveComponent
|
||||
|
||||
alias BDS.{Scripts, Scripting}
|
||||
alias BDS.Desktop.ShellData
|
||||
alias BDS.Scripts.Script
|
||||
|
||||
embed_templates("script_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(%{script_editor: nil} = assigns), do: ~H""
|
||||
|
||||
def render(assigns) do
|
||||
script_editor(assigns)
|
||||
end
|
||||
|
||||
@spec handle_event(String.t(), map(), Phoenix.LiveView.Socket.t()) ::
|
||||
{:noreply, Phoenix.LiveView.Socket.t()}
|
||||
@impl true
|
||||
def handle_event("change_script_editor", %{"script_editor" => params}, socket) do
|
||||
socket =
|
||||
socket
|
||||
|> assign(:draft, normalize_params(params))
|
||||
|> build_data()
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("save_script_editor", _params, socket) do
|
||||
{:noreply, do_save(socket)}
|
||||
end
|
||||
|
||||
def handle_event("publish_script_editor", _params, socket) do
|
||||
{:noreply, do_publish(socket)}
|
||||
end
|
||||
|
||||
def handle_event("run_script_editor", _params, socket) do
|
||||
{:noreply, do_run(socket)}
|
||||
end
|
||||
|
||||
def handle_event("check_script_editor", _params, socket) do
|
||||
{:noreply, do_check(socket)}
|
||||
end
|
||||
|
||||
def handle_event("delete_script_editor", _params, socket) do
|
||||
{:noreply, do_delete(socket)}
|
||||
end
|
||||
|
||||
defp build_data(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.get_script(script_id) do
|
||||
nil ->
|
||||
assign(socket, :script_editor, nil)
|
||||
|
||||
%Script{} = script ->
|
||||
draft = current_draft(socket.assigns, script)
|
||||
|
||||
data = %{
|
||||
id: script.id,
|
||||
title: draft["title"],
|
||||
slug: draft["slug"],
|
||||
kind: draft["kind"],
|
||||
entrypoint: draft["entrypoint"],
|
||||
enabled: draft["enabled"],
|
||||
content: draft["content"],
|
||||
entrypoints: discover_entrypoints(draft["content"]),
|
||||
status: script.status || :draft,
|
||||
can_publish?: script.status == :draft,
|
||||
created_at: script.created_at,
|
||||
updated_at: script.updated_at
|
||||
}
|
||||
|
||||
assign(socket, :script_editor, data)
|
||||
end
|
||||
end
|
||||
|
||||
defp do_save(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.get_script(script_id) do
|
||||
nil ->
|
||||
socket
|
||||
|
||||
%Script{} = script ->
|
||||
draft = current_draft(socket.assigns, script)
|
||||
|
||||
case Scripting.validate(draft["content"] || "") do
|
||||
:ok ->
|
||||
case Scripts.update_script(script.id, script_attrs(draft)) do
|
||||
{:ok, _updated} ->
|
||||
socket
|
||||
|> assign(:draft, nil)
|
||||
|> build_data()
|
||||
|> notify_output(translated("Scripts"), translated("Script saved"))
|
||||
|> notify_reload()
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp do_publish(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.get_script(script_id) do
|
||||
nil ->
|
||||
socket
|
||||
|
||||
%Script{} = script ->
|
||||
draft = current_draft(socket.assigns, script)
|
||||
|
||||
case Scripting.validate(draft["content"] || "") do
|
||||
:ok ->
|
||||
case Scripts.update_script(script.id, script_attrs(draft)) do
|
||||
{:ok, _updated} ->
|
||||
case Scripts.publish_script(script.id) do
|
||||
{:ok, _published} ->
|
||||
socket
|
||||
|> assign(:draft, nil)
|
||||
|> build_data()
|
||||
|> notify_output(translated("Scripts"), translated("Script published"))
|
||||
|> notify_reload()
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp do_check(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.get_script(script_id) do
|
||||
nil ->
|
||||
socket
|
||||
|
||||
%Script{} = script ->
|
||||
case Scripting.validate(current_draft(socket.assigns, script)["content"] || "") do
|
||||
:ok ->
|
||||
notify_output(socket, translated("Scripts"), translated("Syntax is valid"))
|
||||
|
||||
{:error, reason} ->
|
||||
notify_output(socket, translated("Scripts"), inspect(reason), "error")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp do_run(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.get_script(script_id) do
|
||||
nil ->
|
||||
socket
|
||||
|
||||
%Script{} = script ->
|
||||
draft = current_draft(socket.assigns, script)
|
||||
|
||||
case Scripting.execute_project_script(
|
||||
script.project_id,
|
||||
draft["content"] || "",
|
||||
draft["entrypoint"] || "main",
|
||||
[]
|
||||
) do
|
||||
{:ok, result} ->
|
||||
notify_output(socket, translated("Scripts"), inspect(result))
|
||||
|
||||
{:error, reason} ->
|
||||
notify_output(socket, translated("Scripts"), inspect(reason), "error")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
defp do_delete(socket) do
|
||||
script_id = socket.assigns.current_tab.id
|
||||
|
||||
case Scripts.delete_script(script_id) do
|
||||
{:ok, _deleted} ->
|
||||
send(self(), {:close_tab, :scripts, script_id})
|
||||
socket
|
||||
|
||||
{:error, reason} ->
|
||||
socket
|
||||
|> notify_output(translated("Scripts"), inspect(reason), "error")
|
||||
|> notify_reload()
|
||||
end
|
||||
end
|
||||
|
||||
defp current_draft(%{draft: draft}, _script) when is_map(draft), do: draft
|
||||
|
||||
defp current_draft(_assigns, %Script{} = script) do
|
||||
%{
|
||||
"title" => script.title || "",
|
||||
"slug" => script.slug || "",
|
||||
"kind" => to_string(script.kind || :utility),
|
||||
"entrypoint" => script.entrypoint || "main",
|
||||
"enabled" => script.enabled != false,
|
||||
"content" => script.content || ""
|
||||
}
|
||||
end
|
||||
|
||||
defp normalize_params(params) do
|
||||
%{
|
||||
"title" => Map.get(params, "title", ""),
|
||||
"slug" => Map.get(params, "slug", ""),
|
||||
"kind" => Map.get(params, "kind", "utility"),
|
||||
"entrypoint" => Map.get(params, "entrypoint", "main"),
|
||||
"enabled" => Map.get(params, "enabled") in [true, "true", "on", "1", 1],
|
||||
"content" => Map.get(params, "content", "")
|
||||
}
|
||||
end
|
||||
|
||||
defp script_attrs(draft) do
|
||||
%{
|
||||
title: draft["title"],
|
||||
slug: draft["slug"],
|
||||
kind: BDS.BoundedAtoms.script_kind(draft["kind"], :utility),
|
||||
entrypoint: draft["entrypoint"],
|
||||
enabled: draft["enabled"],
|
||||
content: draft["content"]
|
||||
}
|
||||
end
|
||||
|
||||
defp discover_entrypoints(content) do
|
||||
[
|
||||
"main"
|
||||
| Regex.scan(~r/function\s+([A-Za-z_][A-Za-z0-9_]*)\s*\(/, content || "",
|
||||
capture: :all_but_first
|
||||
)
|
||||
|> List.flatten()
|
||||
|> Enum.reject(&(&1 == "main"))
|
||||
]
|
||||
end
|
||||
|
||||
defp notify_output(socket, title, message, level \\ "info") do
|
||||
send(self(), {:script_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
|
||||
Reference in New Issue
Block a user