defmodule LivebookWeb.SessionLive.PersistenceComponent do use LivebookWeb, :live_component alias Livebook.{Session, SessionSupervisor, LiveMarkdown} @impl true def mount(socket) do session_summaries = SessionSupervisor.get_session_summaries() running_paths = Enum.map(session_summaries, & &1.path) {:ok, assign(socket, running_paths: running_paths)} end @impl true def render(assigns) do ~L"""

Specify where the notebook should be automatically persisted.

<%= content_tag :button, "Save to file", class: "choice-button #{if(@path != nil, do: "active")}", phx_click: "set_persistence_type", phx_value_type: "file", phx_target: @myself %> <%= content_tag :button, "Memory only", class: "choice-button #{if(@path == nil, do: "active")}", phx_click: "set_persistence_type", phx_value_type: "memory", phx_target: @myself %>
<%= if @path != nil do %>
<%= live_component @socket, LivebookWeb.PathSelectComponent, id: "path_select", path: @path, extnames: [LiveMarkdown.extension()], running_paths: @running_paths, target: @myself %>
<% end %>
<%= if @path != nil do %>
File: <%= normalize_path(@path) %>
<% end %>
<%= content_tag :button, "Save", class: "button button-blue", phx_click: "save", phx_target: @myself, disabled: not path_savable?(normalize_path(@path), @running_paths) or normalize_path(@path) == @current_path %>
""" end @impl true def handle_event("set_persistence_type", %{"type" => type}, socket) do path = case type do "file" -> default_path() "memory" -> nil end {:noreply, assign(socket, path: path)} end def handle_event("set_path", %{"path" => path}, socket) do {:noreply, assign(socket, path: path)} end def handle_event("save", %{}, socket) do path = normalize_path(socket.assigns.path) Session.set_path(socket.assigns.session_id, path) running_paths = if path do [path | socket.assigns.running_paths] else List.delete(socket.assigns.running_paths, path) end {:noreply, assign(socket, running_paths: running_paths)} end defp default_path() do File.cwd!() |> Path.join("notebook") end defp path_savable?(nil, _running_paths), do: true defp path_savable?(path, running_paths) do if File.exists?(path) do File.regular?(path) and path not in running_paths else true end end defp normalize_path(nil), do: nil defp normalize_path(path) do if String.ends_with?(path, LiveMarkdown.extension()) do path else path <> LiveMarkdown.extension() end end end