Packages
livebook
0.2.3
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook_web/live/session_live/persistence_component.ex
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 update(assigns, socket) do
{path, assigns} = Map.pop!(assigns, :path)
{persist_outputs, assigns} = Map.pop!(assigns, :persist_outputs)
attrs = %{path: path, persist_outputs: persist_outputs}
socket =
socket
|> assign(assigns)
|> assign(attrs: attrs, new_attrs: attrs)
{:ok, socket}
end
@impl true
def render(assigns) do
~H"""
<div class="p-6 pb-4 flex flex-col space-y-8">
<h3 class="text-2xl font-semibold text-gray-800">
File
</h3>
<div class="w-full flex-col space-y-8">
<div class="flex">
<form phx-change="set_options" onsubmit="return false;" phx-target={@myself}>
<.switch_checkbox
name="persist_outputs"
label="Persist outputs"
checked={@new_attrs.persist_outputs} />
</form>
</div>
<div class="flex space-x-4">
<.choice_button
active={@new_attrs.path != nil}
phx-click="set_persistence_type"
phx-value-type="file"
phx-target={@myself}>
Save to file
</.choice_button>
<.choice_button
active={@new_attrs.path == nil}
phx-click="set_persistence_type"
phx-value-type="memory"
phx-target={@myself}>
Memory only
</.choice_button>
</div>
<%= if @new_attrs.path != nil do %>
<div class="h-full h-52">
<%= live_component LivebookWeb.PathSelectComponent,
id: "path_select",
path: @new_attrs.path,
extnames: [LiveMarkdown.extension()],
running_paths: @running_paths,
phx_target: @myself,
phx_submit: if(disabled?(@new_attrs, @attrs, @running_paths), do: nil, else: "save") %>
</div>
<% end %>
<div class="flex flex-col space-y-8">
<%= if @new_attrs.path != nil do %>
<div class="text-gray-500 text-sm">
File: <%= normalize_path(@new_attrs.path) %>
</div>
<% end %>
<div>
<button class="button button-blue"
phx-click="save"
phx-target={@myself}
disabled={disabled?(@new_attrs, @attrs, @running_paths)}>
Save
</button>
</div>
</div>
</div>
</div>
"""
end
@impl true
def handle_event("set_persistence_type", %{"type" => type}, socket) do
path =
case type do
"file" -> socket.assigns.attrs.path || default_path()
"memory" -> nil
end
{:noreply, put_new_attr(socket, :path, path)}
end
def handle_event("set_path", %{"path" => path}, socket) do
{:noreply, put_new_attr(socket, :path, path)}
end
def handle_event("set_options", %{"persist_outputs" => persist_outputs}, socket) do
persist_outputs = persist_outputs == "true"
{:noreply, put_new_attr(socket, :persist_outputs, persist_outputs)}
end
def handle_event("save", %{}, %{assigns: assigns} = socket) do
path = normalize_path(assigns.new_attrs.path)
if path != assigns.attrs.path do
Session.set_path(assigns.session_id, path)
end
Session.set_notebook_attributes(assigns.session_id, %{
persist_outputs: assigns.new_attrs.persist_outputs
})
Session.save_sync(assigns.session_id)
running_paths =
if path do
[path | assigns.running_paths]
else
List.delete(assigns.running_paths, path)
end
# After saving the file reload the directory contents,
# so that the new file gets shown.
send_update(LivebookWeb.PathSelectComponent,
id: "path_select",
running_paths: running_paths,
force_reload: true
)
{:noreply, assign(socket, running_paths: running_paths)}
end
defp put_new_attr(socket, key, value) do
new_attrs = socket.assigns.new_attrs
new_attrs = put_in(new_attrs[key], value)
assign(socket, :new_attrs, new_attrs)
end
defp default_path() do
Livebook.Config.root_path() |> 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
defp disabled?(new_attrs, attrs, running_paths) do
if normalize_path(new_attrs.path) == attrs.path do
new_attrs.persist_outputs == attrs.persist_outputs
else
not path_savable?(normalize_path(new_attrs.path), running_paths)
end
end
end