diff --git a/lib/livebook/session/data.ex b/lib/livebook/session/data.ex index e1e051100..bf0e134ad 100644 --- a/lib/livebook/session/data.ex +++ b/lib/livebook/session/data.ex @@ -154,7 +154,7 @@ defmodule Livebook.Session.Data do # Note that technically the first state is :initial, but we always # expect app to start evaluating right away, so distinguishing that # state from :executing would not bring any value - execution: :executing | :executed | :error, + execution: :executing | :executed | :error | :interrupted, lifecycle: :active | :shutting_down | :deactivated } diff --git a/lib/livebook_web/live/app_session_live.ex b/lib/livebook_web/live/app_session_live.ex index 656d0d504..cbc485905 100644 --- a/lib/livebook_web/live/app_session_live.ex +++ b/lib/livebook_web/live/app_session_live.ex @@ -139,22 +139,30 @@ defmodule LivebookWeb.AppSessionLive do
+
+ +
<%= if @data_view.app_status.execution == :error do %> -
- <.remix_icon icon="error-warning-line" class="text-xl" /> - Something went wrong -
- <% else %> -
- +
+
+ <.remix_icon icon="error-warning-line" class="text-xl" /> + Something went wrong +
+ <.link + :if={@livebook_authenticated?} + navigate={~p"/sessions/#{@session.id}" <> "#cell-#{@data_view.errored_cell_id}"} + > + Debug + <.remix_icon icon="arrow-right-line" /> +
<% end %>
@@ -303,10 +311,19 @@ defmodule LivebookWeb.AppSessionLive do app_status: data.app_data.status, show_source: data.notebook.app_settings.show_source, slug: data.notebook.app_settings.slug, - multi_session: data.notebook.app_settings.multi_session + multi_session: data.notebook.app_settings.multi_session, + errored_cell_id: errored_cell_id(data) } end + defp errored_cell_id(data) do + data.notebook + |> Notebook.evaluable_cells_with_section() + |> Enum.find_value(fn {cell, _section} -> + data.cell_infos[cell.id].eval.errored && cell.id + end) + end + defp input_values_for_output(output, data) do input_ids = for attrs <- Cell.find_inputs_in_output(output), do: attrs.id Map.take(data.input_values, input_ids) diff --git a/lib/livebook_web/live/session_live.ex b/lib/livebook_web/live/session_live.ex index 412c28ba6..2beba296d 100644 --- a/lib/livebook_web/live/session_live.ex +++ b/lib/livebook_web/live/session_live.ex @@ -62,6 +62,17 @@ defmodule LivebookWeb.SessionLive do session = Session.get_by_pid(session_pid) platform = platform_from_socket(socket) + socket = + if data.mode == :app do + put_flash( + socket, + :info, + "This session is a deployed app. Any changes will be reflected live." + ) + else + socket + end + {:ok, socket |> assign( diff --git a/test/livebook_web/live/app_session_live_test.exs b/test/livebook_web/live/app_session_live_test.exs index 92f4937d3..003c3e202 100644 --- a/test/livebook_web/live/app_session_live_test.exs +++ b/test/livebook_web/live/app_session_live_test.exs @@ -108,7 +108,7 @@ defmodule LivebookWeb.AppSessionLiveTest do Livebook.App.close(app.pid) end - test "only shows an error message when session errors", %{conn: conn} do + test "shows an error message when session errors", %{conn: conn} do slug = Livebook.Utils.random_short_id() app_settings = %{Livebook.Notebook.AppSettings.new() | slug: slug} @@ -125,7 +125,8 @@ defmodule LivebookWeb.AppSessionLiveTest do }, %{ Livebook.Notebook.Cell.new(:code) - | source: ~s/raise "oops"/ + | source: ~s/raise "oops"/, + id: "error-cell" } ] } @@ -138,12 +139,16 @@ defmodule LivebookWeb.AppSessionLiveTest do assert_receive {:app_created, %{pid: ^app_pid} = app} assert_receive {:app_updated, - %{pid: ^app_pid, sessions: [%{app_status: %{execution: :error}}]}} + %{ + pid: ^app_pid, + sessions: [%{id: session_id, app_status: %{execution: :error}}] + }} {:ok, view, _} = conn |> live(~p"/apps/#{slug}") |> follow_redirect(conn) + assert render(view) =~ "Printed output" assert render(view) =~ "Something went wrong" - refute render(view) =~ "Printed output" + assert render(view) =~ ~p"/sessions/#{session_id}" <> "#cell-error-cell" Livebook.App.close(app.pid) end