mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-09 21:16:26 +08:00
Add support for anchor links during navigation (#1327)
This commit is contained in:
parent
6853bbd9a1
commit
e8920257cd
2 changed files with 49 additions and 13 deletions
|
@ -1,5 +1,8 @@
|
||||||
defmodule LivebookWeb.SessionHelpers do
|
defmodule LivebookWeb.SessionHelpers do
|
||||||
import Phoenix.LiveView
|
import Phoenix.LiveView
|
||||||
|
|
||||||
|
alias Phoenix.LiveView.Socket
|
||||||
|
alias Livebook.Session
|
||||||
alias LivebookWeb.Router.Helpers, as: Routes
|
alias LivebookWeb.Router.Helpers, as: Routes
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -8,7 +11,7 @@ defmodule LivebookWeb.SessionHelpers do
|
||||||
|
|
||||||
Accepts the same options as `Livebook.Sessions.create_session/1`.
|
Accepts the same options as `Livebook.Sessions.create_session/1`.
|
||||||
"""
|
"""
|
||||||
@spec create_session(Phoenix.LiveView.Socket.t(), keyword()) :: Phoenix.LiveView.Socket.t()
|
@spec create_session(Socket.t(), keyword()) :: Socket.t()
|
||||||
def create_session(socket, opts \\ []) do
|
def create_session(socket, opts \\ []) do
|
||||||
# Revert persistence options to default values if there is
|
# Revert persistence options to default values if there is
|
||||||
# no file attached to the new session
|
# no file attached to the new session
|
||||||
|
@ -21,19 +24,36 @@ defmodule LivebookWeb.SessionHelpers do
|
||||||
|
|
||||||
case Livebook.Sessions.create_session(opts) do
|
case Livebook.Sessions.create_session(opts) do
|
||||||
{:ok, session} ->
|
{:ok, session} ->
|
||||||
push_redirect(socket, to: Routes.session_path(socket, :page, session.id))
|
redirect_path = session_path(socket, session.id, opts)
|
||||||
|
push_redirect(socket, to: redirect_path)
|
||||||
|
|
||||||
{:error, reason} ->
|
{:error, reason} ->
|
||||||
put_flash(socket, :error, "Failed to create session: #{reason}")
|
put_flash(socket, :error, "Failed to create session: #{reason}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generate the session path based on the provided options.
|
||||||
|
"""
|
||||||
|
@spec session_path(Socket.t(), Session.id(), keyword()) :: String.t()
|
||||||
|
def session_path(socket, session_id, opts \\ []) do
|
||||||
|
socket
|
||||||
|
|> Routes.session_path(:page, session_id)
|
||||||
|
|> maybe_add_url_hash(opts)
|
||||||
|
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
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Formats the given list of notebook import messages and puts
|
Formats the given list of notebook import messages and puts
|
||||||
into the warning flash.
|
into the warning flash.
|
||||||
"""
|
"""
|
||||||
@spec put_import_warnings(Phoenix.LiveView.Socket.t(), list(String.t())) ::
|
@spec put_import_warnings(Socket.t(), list(String.t())) :: Socket.t()
|
||||||
Phoenix.LiveView.Socket.t()
|
|
||||||
def put_import_warnings(socket, messages)
|
def put_import_warnings(socket, messages)
|
||||||
|
|
||||||
def put_import_warnings(socket, []), do: socket
|
def put_import_warnings(socket, []), do: socket
|
||||||
|
|
|
@ -674,7 +674,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
|
|
||||||
def handle_params(
|
def handle_params(
|
||||||
%{"path_parts" => path_parts},
|
%{"path_parts" => path_parts},
|
||||||
_url,
|
requested_url,
|
||||||
%{assigns: %{live_action: :catch_all}} = socket
|
%{assigns: %{live_action: :catch_all}} = socket
|
||||||
) do
|
) do
|
||||||
if socket.assigns.policy.edit do
|
if socket.assigns.policy.edit do
|
||||||
|
@ -685,7 +685,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
path = Path.join(path_parts)
|
path = Path.join(path_parts)
|
||||||
{:noreply, handle_relative_path(socket, path)}
|
{:noreply, handle_relative_path(socket, path, requested_url)}
|
||||||
else
|
else
|
||||||
{:noreply, socket |> put_flash(:error, "No access to navigate") |> redirect_to_self()}
|
{:noreply, socket |> put_flash(:error, "No access to navigate") |> redirect_to_self()}
|
||||||
end
|
end
|
||||||
|
@ -1130,10 +1130,10 @@ defmodule LivebookWeb.SessionLive do
|
||||||
|
|
||||||
def handle_info(_message, socket), do: {:noreply, socket}
|
def handle_info(_message, socket), do: {:noreply, socket}
|
||||||
|
|
||||||
defp handle_relative_path(socket, path) do
|
defp handle_relative_path(socket, path, requested_url) do
|
||||||
cond do
|
cond do
|
||||||
String.ends_with?(path, LiveMarkdown.extension()) ->
|
String.ends_with?(path, LiveMarkdown.extension()) ->
|
||||||
handle_relative_notebook_path(socket, path)
|
handle_relative_notebook_path(socket, path, requested_url)
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
socket
|
socket
|
||||||
|
@ -1145,7 +1145,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp handle_relative_notebook_path(socket, relative_path) do
|
defp handle_relative_notebook_path(socket, relative_path, requested_url) do
|
||||||
resolution_location = location(socket.private.data)
|
resolution_location = location(socket.private.data)
|
||||||
|
|
||||||
case resolution_location do
|
case resolution_location do
|
||||||
|
@ -1162,10 +1162,13 @@ defmodule LivebookWeb.SessionLive do
|
||||||
|
|
||||||
case session_id_by_location(origin) do
|
case session_id_by_location(origin) do
|
||||||
{:ok, session_id} ->
|
{:ok, session_id} ->
|
||||||
push_redirect(socket, to: Routes.session_path(socket, :page, session_id))
|
redirect_path =
|
||||||
|
session_path(socket, session_id, url_hash: get_url_hash(requested_url))
|
||||||
|
|
||||||
|
push_redirect(socket, to: redirect_path)
|
||||||
|
|
||||||
{:error, :none} ->
|
{:error, :none} ->
|
||||||
open_notebook(socket, origin)
|
open_notebook(socket, origin, requested_url)
|
||||||
|
|
||||||
{:error, :many} ->
|
{:error, :many} ->
|
||||||
origin_str =
|
origin_str =
|
||||||
|
@ -1188,7 +1191,14 @@ defmodule LivebookWeb.SessionLive do
|
||||||
defp location(%{file: file}) when is_map(file), do: {:file, file}
|
defp location(%{file: file}) when is_map(file), do: {:file, file}
|
||||||
defp location(%{origin: origin}), do: origin
|
defp location(%{origin: origin}), do: origin
|
||||||
|
|
||||||
defp open_notebook(socket, origin) do
|
defp get_url_hash(requested_url) do
|
||||||
|
case String.split(requested_url, "#") do
|
||||||
|
[_, url_hash] -> url_hash
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp open_notebook(socket, origin, requested_url) do
|
||||||
case Notebook.ContentLoader.fetch_content_from_location(origin) do
|
case Notebook.ContentLoader.fetch_content_from_location(origin) do
|
||||||
{:ok, content} ->
|
{:ok, content} ->
|
||||||
{notebook, messages} = Livebook.LiveMarkdown.notebook_from_livemd(content)
|
{notebook, messages} = Livebook.LiveMarkdown.notebook_from_livemd(content)
|
||||||
|
@ -1196,10 +1206,16 @@ defmodule LivebookWeb.SessionLive do
|
||||||
# If the current session has no path, fork the notebook
|
# If the current session has no path, fork the notebook
|
||||||
fork? = socket.private.data.file == nil
|
fork? = socket.private.data.file == nil
|
||||||
{file, notebook} = file_and_notebook(fork?, origin, notebook)
|
{file, notebook} = file_and_notebook(fork?, origin, notebook)
|
||||||
|
url_hash = get_url_hash(requested_url)
|
||||||
|
|
||||||
socket
|
socket
|
||||||
|> put_import_warnings(messages)
|
|> put_import_warnings(messages)
|
||||||
|> create_session(notebook: notebook, origin: origin, file: file)
|
|> create_session(
|
||||||
|
notebook: notebook,
|
||||||
|
origin: origin,
|
||||||
|
file: file,
|
||||||
|
url_hash: url_hash
|
||||||
|
)
|
||||||
|
|
||||||
{:error, message} ->
|
{:error, message} ->
|
||||||
socket
|
socket
|
||||||
|
|
Loading…
Add table
Reference in a new issue