diff --git a/assets/js/session/index.js b/assets/js/session/index.js index d6e722b6d..69c8143ae 100644 --- a/assets/js/session/index.js +++ b/assets/js/session/index.js @@ -60,6 +60,8 @@ const Session = { this.pushEvent("queue_section_cells_evaluation", {}); } else if (keyBuffer.tryMatch(["e", "j"])) { this.pushEvent("queue_child_cells_evaluation", {}); + } else if (keyBuffer.tryMatch(["e", "x"])) { + this.pushEvent("cancel_focused_cell_evaluation", {}); } else if (keyBuffer.tryMatch(["?"])) { this.pushEvent("show_shortcuts", {}); } else if (key === "i") { diff --git a/lib/live_book_web/live/cell_component.ex b/lib/live_book_web/live/cell_component.ex index 0205ee936..737279e94 100644 --- a/lib/live_book_web/live/cell_component.ex +++ b/lib/live_book_web/live/cell_component.ex @@ -44,9 +44,15 @@ defmodule LiveBookWeb.CellComponent do ~L""" <%= if @focused do %>
- + <%= if @cell_info.evaluation_status == :ready do %> + + <% else %> + + <% end %> diff --git a/lib/live_book_web/live/icons.ex b/lib/live_book_web/live/icons.ex index ededc949d..5cb6557db 100644 --- a/lib/live_book_web/live/icons.ex +++ b/lib/live_book_web/live/icons.ex @@ -138,6 +138,17 @@ defmodule LiveBookWeb.Icons do """ end + def svg(:stop, attrs) do + assigns = %{attrs: heroicon_svg_attrs(attrs)} + + ~L""" + <%= tag(:svg, @attrs) %> + + + + """ + end + # https://heroicons.com defp heroicon_svg_attrs(attrs) do heroicon_svg_attrs = [ diff --git a/lib/live_book_web/live/session_live.ex b/lib/live_book_web/live/session_live.ex index 0162aafd5..892632e70 100644 --- a/lib/live_book_web/live/session_live.ex +++ b/lib/live_book_web/live/session_live.ex @@ -348,6 +348,14 @@ defmodule LiveBookWeb.SessionLive do {:noreply, socket} end + def handle_event("cancel_focused_cell_evaluation", %{}, socket) do + if socket.assigns.focused_cell_id do + Session.cancel_cell_evaluation(socket.assigns.session_id, socket.assigns.focused_cell_id) + end + + {:noreply, socket} + end + def handle_event("show_shortcuts", %{}, socket) do {:noreply, push_patch(socket, to: Routes.session_path(socket, :shortcuts, socket.assigns.session_id))} diff --git a/lib/live_book_web/live/session_live/shortcuts_component.ex b/lib/live_book_web/live/session_live/shortcuts_component.ex index cf3405aaf..6b9925a94 100644 --- a/lib/live_book_web/live/session_live/shortcuts_component.ex +++ b/lib/live_book_web/live/session_live/shortcuts_component.ex @@ -18,7 +18,8 @@ defmodule LiveBookWeb.SessionLive.ShortcutsComponent do %{seq: "dd", desc: "Delete cell"}, %{seq: "ee", desc: "Evaluate cell"}, %{seq: "es", desc: "Evaluate section"}, - %{seq: "ej", desc: "Evaluate cells below"} + %{seq: "ej", desc: "Evaluate cells below"}, + %{seq: "ex", desc: "Cancel cell evaluation"} ] } diff --git a/test/live_book_web/live/session_live_test.exs b/test/live_book_web/live/session_live_test.exs index 664fca9e0..3dc7a65d1 100644 --- a/test/live_book_web/live/session_live_test.exs +++ b/test/live_book_web/live/session_live_test.exs @@ -108,6 +108,26 @@ defmodule LiveBookWeb.SessionLiveTest do Session.get_data(session_id) end + test "cancelling focused cell evaluation", %{conn: conn, session_id: session_id} do + section_id = insert_section(session_id) + cell_id = insert_cell(session_id, section_id, :elixir, "Process.sleep(2000)") + + {:ok, view, _} = live(conn, "/sessions/#{session_id}") + + focus_cell(view, cell_id) + + view + |> element("#session") + |> render_hook("queue_focused_cell_evaluation", %{}) + + view + |> element("#session") + |> render_hook("cancel_focused_cell_evaluation", %{}) + + assert %{cell_infos: %{^cell_id => %{evaluation_status: :ready}}} = + Session.get_data(session_id) + end + test "inserting a cell below the focused cell", %{conn: conn, session_id: session_id} do section_id = insert_section(session_id) cell_id = insert_cell(session_id, section_id, :elixir)