2021-06-03 03:51:43 +08:00
|
|
|
defmodule LivebookWeb.SessionHelpers do
|
|
|
|
import Phoenix.LiveView
|
2022-08-05 03:24:19 +08:00
|
|
|
|
2023-02-23 02:34:54 +08:00
|
|
|
use LivebookWeb, :verified_routes
|
|
|
|
|
2022-08-05 03:24:19 +08:00
|
|
|
alias Phoenix.LiveView.Socket
|
|
|
|
alias Livebook.Session
|
2023-03-07 01:14:33 +08:00
|
|
|
alias Livebook.FileSystem
|
2021-06-03 03:51:43 +08:00
|
|
|
|
|
|
|
@doc """
|
|
|
|
Creates a new session, redirects on success,
|
|
|
|
puts an error flash message on failure.
|
|
|
|
|
2021-09-05 01:16:01 +08:00
|
|
|
Accepts the same options as `Livebook.Sessions.create_session/1`.
|
2021-06-03 03:51:43 +08:00
|
|
|
"""
|
2022-08-05 03:24:19 +08:00
|
|
|
@spec create_session(Socket.t(), keyword()) :: Socket.t()
|
2021-06-03 03:51:43 +08:00
|
|
|
def create_session(socket, opts \\ []) do
|
2021-08-14 03:17:43 +08:00
|
|
|
# Revert persistence options to default values if there is
|
|
|
|
# no file attached to the new session
|
|
|
|
opts =
|
|
|
|
if opts[:notebook] != nil and opts[:file] == nil do
|
|
|
|
Keyword.update!(opts, :notebook, &Livebook.Notebook.reset_persistence_options/1)
|
|
|
|
else
|
|
|
|
opts
|
|
|
|
end
|
|
|
|
|
2021-09-05 01:16:01 +08:00
|
|
|
case Livebook.Sessions.create_session(opts) do
|
|
|
|
{:ok, session} ->
|
2023-02-23 02:34:54 +08:00
|
|
|
redirect_path = session_path(session.id, opts)
|
|
|
|
push_navigate(socket, to: redirect_path)
|
2021-06-03 03:51:43 +08:00
|
|
|
|
|
|
|
{:error, reason} ->
|
|
|
|
put_flash(socket, :error, "Failed to create session: #{reason}")
|
|
|
|
end
|
|
|
|
end
|
2021-07-09 01:35:11 +08:00
|
|
|
|
2022-08-05 03:24:19 +08:00
|
|
|
@doc """
|
|
|
|
Generate the session path based on the provided options.
|
|
|
|
"""
|
2023-02-23 02:34:54 +08:00
|
|
|
@spec session_path(Session.id(), keyword()) :: String.t()
|
|
|
|
def session_path(session_id, opts \\ []) do
|
|
|
|
maybe_add_url_hash(~p"/sessions/#{session_id}", opts)
|
2022-08-05 03:24:19 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
defp maybe_add_url_hash(redirect_path, opts) do
|
|
|
|
case opts[:url_hash] do
|
|
|
|
nil -> redirect_path
|
|
|
|
url_hash -> "#{redirect_path}##{url_hash}"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-07-09 01:35:11 +08:00
|
|
|
@doc """
|
|
|
|
Formats the given list of notebook import messages and puts
|
2021-10-22 05:21:54 +08:00
|
|
|
into the warning flash.
|
2021-07-09 01:35:11 +08:00
|
|
|
"""
|
2022-08-05 03:24:19 +08:00
|
|
|
@spec put_import_warnings(Socket.t(), list(String.t())) :: Socket.t()
|
2021-10-22 05:21:54 +08:00
|
|
|
def put_import_warnings(socket, messages)
|
2021-07-09 01:35:11 +08:00
|
|
|
|
2021-10-22 05:21:54 +08:00
|
|
|
def put_import_warnings(socket, []), do: socket
|
2021-07-09 01:35:11 +08:00
|
|
|
|
2021-10-22 05:21:54 +08:00
|
|
|
def put_import_warnings(socket, messages) do
|
2021-07-09 01:35:11 +08:00
|
|
|
list =
|
|
|
|
messages
|
|
|
|
|> Enum.map(fn message -> ["- ", message] end)
|
|
|
|
|> Enum.intersperse("\n")
|
|
|
|
|
|
|
|
flash =
|
|
|
|
IO.iodata_to_binary([
|
|
|
|
"We found problems while importing the file and tried to autofix them:\n" | list
|
|
|
|
])
|
|
|
|
|
2021-10-22 05:21:54 +08:00
|
|
|
put_flash(socket, :warning, flash)
|
2021-07-09 01:35:11 +08:00
|
|
|
end
|
2022-01-22 06:24:47 +08:00
|
|
|
|
|
|
|
def uses_memory?(%{runtime: %{total: total}}) when total > 0, do: true
|
|
|
|
def uses_memory?(_), do: false
|
2023-02-28 22:08:49 +08:00
|
|
|
|
|
|
|
@doc """
|
|
|
|
Updates a list of sessions based on the given `Sessions` event.
|
|
|
|
"""
|
|
|
|
@spec update_session_list(
|
|
|
|
list(Session.t()),
|
|
|
|
{:session_created | :session_updated | :session_closed, Session.t()}
|
|
|
|
) :: list(Session.t())
|
|
|
|
def update_session_list(sessions, {:session_created, session}) do
|
|
|
|
if session in sessions do
|
|
|
|
sessions
|
|
|
|
else
|
|
|
|
[session | sessions]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_session_list(sessions, {:session_updated, session}) do
|
|
|
|
Enum.map(sessions, fn other ->
|
|
|
|
if other.id == session.id, do: session, else: other
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_session_list(sessions, {:session_closed, session}) do
|
|
|
|
Enum.reject(sessions, &(&1.id == session.id))
|
|
|
|
end
|
2023-03-07 01:14:33 +08:00
|
|
|
|
|
|
|
@doc """
|
|
|
|
Creates a new session by forking the given notebook file.
|
|
|
|
"""
|
|
|
|
@spec fork_notebook(Socket.t(), FileSystem.File.t()) :: Socket.t()
|
|
|
|
def fork_notebook(socket, file) do
|
|
|
|
case import_notebook(file) do
|
|
|
|
{:ok, {notebook, messages}} ->
|
|
|
|
notebook = Livebook.Notebook.forked(notebook)
|
|
|
|
images_dir = Session.images_dir_for_notebook(file)
|
|
|
|
|
|
|
|
socket
|
|
|
|
|> put_import_warnings(messages)
|
|
|
|
|> create_session(
|
|
|
|
notebook: notebook,
|
|
|
|
copy_images_from: images_dir,
|
|
|
|
origin: {:file, file}
|
|
|
|
)
|
|
|
|
|
|
|
|
{:error, error} ->
|
|
|
|
put_flash(socket, :error, Livebook.Utils.upcase_first(error))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@doc """
|
|
|
|
Creates a new session by opening the given notebook file.
|
|
|
|
"""
|
|
|
|
@spec open_notebook(Socket.t(), FileSystem.File.t()) :: Socket.t()
|
|
|
|
def open_notebook(socket, file) do
|
|
|
|
case import_notebook(file) do
|
|
|
|
{:ok, {notebook, messages}} ->
|
|
|
|
socket
|
|
|
|
|> put_import_warnings(messages)
|
|
|
|
|> create_session(notebook: notebook, file: file, origin: {:file, file})
|
|
|
|
|
|
|
|
{:error, error} ->
|
|
|
|
put_flash(socket, :error, Livebook.Utils.upcase_first(error))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
defp import_notebook(file) do
|
|
|
|
with {:ok, content} <- FileSystem.File.read(file) do
|
|
|
|
{:ok, Livebook.LiveMarkdown.notebook_from_livemd(content)}
|
|
|
|
end
|
|
|
|
end
|
2021-06-03 03:51:43 +08:00
|
|
|
end
|