diff --git a/lib/livebook/session.ex b/lib/livebook/session.ex index 91781ac94ad..56f8337b5a7 100644 --- a/lib/livebook/session.ex +++ b/lib/livebook/session.ex @@ -684,6 +684,18 @@ defmodule Livebook.Session do end end + @doc """ + Looks up file entry with the given name and returns a local path + for accessing the file. + + When a file is available remotely, it is first downloaded into a + cached location. + """ + @spec fetch_file_entry_path(pid(), String.t()) :: {:ok, String.t()} | {:error, String.t()} + def fetch_file_entry_path(pid, name) do + GenServer.call(pid, {:fetch_file_entry_path, name}, :infinity) + end + @doc """ Closes one or more sessions. @@ -990,6 +1002,14 @@ defmodule Livebook.Session do {:reply, :ok, state} end + def handle_call({:fetch_file_entry_path, name}, from, state) do + file_entry_path(state, name, fn reply -> + GenServer.reply(from, reply) + end) + + {:noreply, state} + end + @impl true def handle_cast({:set_notebook_attributes, client_pid, attrs}, state) do client_id = client_id(state, client_pid) diff --git a/lib/livebook_web/controllers/session_controller.ex b/lib/livebook_web/controllers/session_controller.ex index ce64fc18aca..6d8e6f0d66c 100644 --- a/lib/livebook_web/controllers/session_controller.ex +++ b/lib/livebook_web/controllers/session_controller.ex @@ -39,6 +39,16 @@ defmodule LivebookWeb.SessionController do end end + def download_file(conn, %{"id" => id, "name" => name}) do + with {:ok, session} <- Sessions.fetch_session(id), + {:ok, path} <- Session.fetch_file_entry_path(session.pid, name) do + send_download(conn, {:file, path}, filename: name) + else + _ -> + send_resp(conn, 404, "Not found") + end + end + def download_source(conn, %{"id" => id, "format" => format}) do case Sessions.fetch_session(id) do {:ok, session} -> diff --git a/lib/livebook_web/live/home_live/session_list_component.ex b/lib/livebook_web/live/home_live/session_list_component.ex index 2a1d8be1580..a186ac1b58f 100644 --- a/lib/livebook_web/live/home_live/session_list_component.ex +++ b/lib/livebook_web/live/home_live/session_list_component.ex @@ -151,7 +151,7 @@ defmodule LivebookWeb.HomeLive.SessionListComponent do <.menu_item> <.remix_icon icon="download-2-line" /> diff --git a/lib/livebook_web/live/session_live/export_live_markdown_component.ex b/lib/livebook_web/live/session_live/export_live_markdown_component.ex index 9aaebcca309..b1b80a24a39 100644 --- a/lib/livebook_web/live/session_live/export_live_markdown_component.ex +++ b/lib/livebook_web/live/session_live/export_live_markdown_component.ex @@ -51,7 +51,7 @@ defmodule LivebookWeb.SessionLive.ExportLiveMarkdownComponent do class="icon-button" aria-label="download source" href={ - ~p"/sessions/#{@session.id}/export/download/livemd?include_outputs=#{@include_outputs}" + ~p"/sessions/#{@session.id}/download/export/livemd?include_outputs=#{@include_outputs}" } > <.remix_icon icon="download-2-line" class="text-lg" /> diff --git a/lib/livebook_web/live/session_live/files_list_component.ex b/lib/livebook_web/live/session_live/files_list_component.ex index ca9deca6a03..01798ada92d 100644 --- a/lib/livebook_web/live/session_live/files_list_component.ex +++ b/lib/livebook_web/live/session_live/files_list_component.ex @@ -97,6 +97,12 @@ defmodule LivebookWeb.SessionLive.FilesListComponent do Clear cache + <.menu_item> + + <.remix_icon icon="download-2-line" /> + Download + + <.menu_item variant={:danger}>