mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-09-09 14:34:42 +08:00
Add an action converting smart cell to elixir cell (#1030)
* Add an action converting smart cell to elixir cell * Simplify tests setup * Add confirmation * Update lib/livebook_web/live/session_live/cell_component.ex Co-authored-by: José Valim <jose.valim@dashbit.co> Co-authored-by: José Valim <jose.valim@dashbit.co>
This commit is contained in:
parent
29f0f54bbd
commit
aaeac6bb95
5 changed files with 119 additions and 31 deletions
|
@ -301,6 +301,14 @@ defmodule Livebook.Session do
|
|||
GenServer.cast(pid, {:move_section, self(), section_id, offset})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Sends cell convertion request to the server.
|
||||
"""
|
||||
@spec convert_smart_cell(pid(), Cell.id()) :: :ok
|
||||
def convert_smart_cell(pid, cell_id) do
|
||||
GenServer.cast(pid, {:convert_smart_cell, self(), cell_id})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Sends cell evaluation request to the server.
|
||||
"""
|
||||
|
@ -688,6 +696,26 @@ defmodule Livebook.Session do
|
|||
{:noreply, handle_operation(state, operation)}
|
||||
end
|
||||
|
||||
def handle_cast({:convert_smart_cell, client_pid, cell_id}, state) do
|
||||
state =
|
||||
with {:ok, %Cell.Smart{} = cell, section} <-
|
||||
Notebook.fetch_cell_and_section(state.data.notebook, cell_id) do
|
||||
index = Enum.find_index(section.cells, &(&1 == cell))
|
||||
|
||||
attrs = Map.take(cell, [:source, :outputs])
|
||||
|
||||
state
|
||||
|> handle_operation({:delete_cell, client_pid, cell.id})
|
||||
|> handle_operation(
|
||||
{:insert_cell, client_pid, section.id, index, :elixir, Utils.random_id(), attrs}
|
||||
)
|
||||
else
|
||||
_ -> state
|
||||
end
|
||||
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
def handle_cast({:queue_cell_evaluation, client_pid, cell_id}, state) do
|
||||
operation = {:queue_cells_evaluation, client_pid, [cell_id]}
|
||||
{:noreply, handle_operation(state, operation)}
|
||||
|
|
|
@ -706,6 +706,12 @@ defmodule LivebookWeb.SessionLive do
|
|||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("convert_smart_cell", %{"cell_id" => cell_id}, socket) do
|
||||
Session.convert_smart_cell(socket.assigns.session.pid, cell_id)
|
||||
|
||||
{:noreply, socket}
|
||||
end
|
||||
|
||||
def handle_event("queue_cell_evaluation", %{"cell_id" => cell_id}, socket) do
|
||||
Session.queue_cell_evaluation(socket.assigns.session.pid, cell_id)
|
||||
|
||||
|
|
|
@ -44,19 +44,8 @@ defmodule LivebookWeb.SessionLive.CellComponent do
|
|||
~H"""
|
||||
<.cell_actions>
|
||||
<:secondary>
|
||||
<span class="tooltip top" data-tooltip="Edit content" data-element="enable-insert-mode-button">
|
||||
<button class="icon-button" aria-label="edit content">
|
||||
<.remix_icon icon="pencil-line" class="text-xl" />
|
||||
</button>
|
||||
</span>
|
||||
<span class="tooltip top" data-tooltip="Insert image" data-element="insert-image-button">
|
||||
<%= live_patch to: Routes.session_path(@socket, :cell_upload, @session_id, @cell_view.id),
|
||||
class: "icon-button",
|
||||
aria_label: "insert image",
|
||||
role: "button" do %>
|
||||
<.remix_icon icon="image-add-line" class="text-xl" />
|
||||
<% end %>
|
||||
</span>
|
||||
<.enable_insert_mode_button />
|
||||
<.insert_image_button cell_id={@cell_view.id} session_id={@session_id} socket={@socket} />
|
||||
<.cell_link_button cell_id={@cell_view.id} />
|
||||
<.move_cell_up_button cell_id={@cell_view.id} />
|
||||
<.move_cell_down_button cell_id={@cell_view.id} />
|
||||
|
@ -127,12 +116,8 @@ defmodule LivebookWeb.SessionLive.CellComponent do
|
|||
reevaluate_automatically={false} />
|
||||
</:primary>
|
||||
<:secondary>
|
||||
<span class="tooltip top" data-tooltip="Toggle source" data-element="toggle-source-button">
|
||||
<button class="icon-button" aria-label="toggle source">
|
||||
<.remix_icon icon="code-line" class="text-xl" data-element="show-code-icon" />
|
||||
<.remix_icon icon="pencil-line" class="text-xl" data-element="show-ui-icon" />
|
||||
</button>
|
||||
</span>
|
||||
<.toggle_source_button />
|
||||
<.convert_smart_cell_button cell_id={@cell_view.id} />
|
||||
<.cell_link_button cell_id={@cell_view.id} />
|
||||
<.move_cell_up_button cell_id={@cell_view.id} />
|
||||
<.move_cell_down_button cell_id={@cell_view.id} />
|
||||
|
@ -247,6 +232,61 @@ defmodule LivebookWeb.SessionLive.CellComponent do
|
|||
"""
|
||||
end
|
||||
|
||||
defp enable_insert_mode_button(assigns) do
|
||||
~H"""
|
||||
<span class="tooltip top" data-tooltip="Edit content" data-element="enable-insert-mode-button">
|
||||
<button class="icon-button" aria-label="edit content">
|
||||
<.remix_icon icon="pencil-line" class="text-xl" />
|
||||
</button>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
defp insert_image_button(assigns) do
|
||||
~H"""
|
||||
<span class="tooltip top" data-tooltip="Insert image" data-element="insert-image-button">
|
||||
<%= live_patch to: Routes.session_path(@socket, :cell_upload, @session_id, @cell_id),
|
||||
class: "icon-button",
|
||||
aria_label: "insert image",
|
||||
role: "button" do %>
|
||||
<.remix_icon icon="image-add-line" class="text-xl" />
|
||||
<% end %>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
defp toggle_source_button(assigns) do
|
||||
~H"""
|
||||
<span class="tooltip top" data-tooltip="Toggle source" data-element="toggle-source-button">
|
||||
<button class="icon-button" aria-label="toggle source">
|
||||
<.remix_icon icon="code-line" class="text-xl" data-element="show-code-icon" />
|
||||
<.remix_icon icon="pencil-line" class="text-xl" data-element="show-ui-icon" />
|
||||
</button>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
defp convert_smart_cell_button(assigns) do
|
||||
~H"""
|
||||
<span class="tooltip top" data-tooltip="Convert to Elixir cell">
|
||||
<button class="icon-button"
|
||||
aria-label="toggle source"
|
||||
phx-click={
|
||||
with_confirm(
|
||||
JS.push("convert_smart_cell", value: %{cell_id: @cell_id}),
|
||||
title: "Convert cell",
|
||||
description: "Once you convert this Smart cell to a Code cell, the Smart cell will be moved to the bin.",
|
||||
confirm_text: "Convert",
|
||||
confirm_icon: "arrow-up-down-line",
|
||||
opt_out_id: "convert-smart-cell"
|
||||
)
|
||||
}>
|
||||
<.remix_icon icon="arrow-up-down-line" class="text-xl" />
|
||||
</button>
|
||||
</span>
|
||||
"""
|
||||
end
|
||||
|
||||
defp cell_link_button(assigns) do
|
||||
~H"""
|
||||
<span class="tooltip top" data-tooltip="Link">
|
||||
|
|
|
@ -99,6 +99,30 @@ defmodule Livebook.SessionTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "convert_smart_cell/2" do
|
||||
test "sends a delete and insert opreations to subscribers" do
|
||||
smart_cell = %{Notebook.Cell.new(:smart) | kind: "text", source: "content"}
|
||||
section = %{Notebook.Section.new() | cells: [smart_cell]}
|
||||
notebook = %{Notebook.new() | sections: [section]}
|
||||
|
||||
session = start_session(notebook: notebook)
|
||||
|
||||
Phoenix.PubSub.subscribe(Livebook.PubSub, "sessions:#{session.id}")
|
||||
pid = self()
|
||||
|
||||
Session.convert_smart_cell(session.pid, smart_cell.id)
|
||||
|
||||
cell_id = smart_cell.id
|
||||
section_id = section.id
|
||||
|
||||
assert_receive {:operation, {:delete_cell, ^pid, ^cell_id}}
|
||||
|
||||
assert_receive {:operation,
|
||||
{:insert_cell, ^pid, ^section_id, 0, :elixir, _id,
|
||||
%{source: "content", outputs: []}}}
|
||||
end
|
||||
end
|
||||
|
||||
describe "queue_cell_evaluation/2" do
|
||||
test "triggers evaluation and sends update operation once it finishes",
|
||||
%{session: session} do
|
||||
|
|
|
@ -3,7 +3,7 @@ defmodule LivebookWeb.SessionLiveTest do
|
|||
|
||||
import Phoenix.LiveViewTest
|
||||
|
||||
alias Livebook.{Sessions, Session, Delta, Runtime, Users, FileSystem}
|
||||
alias Livebook.{Sessions, Session, Runtime, Users, FileSystem}
|
||||
alias Livebook.Notebook.Cell
|
||||
alias Livebook.Users.User
|
||||
|
||||
|
@ -892,18 +892,8 @@ defmodule LivebookWeb.SessionLiveTest do
|
|||
end
|
||||
|
||||
defp insert_text_cell(session_pid, section_id, type, content \\ "") do
|
||||
Session.insert_cell(session_pid, section_id, 0, type)
|
||||
Session.insert_cell(session_pid, section_id, 0, type, %{source: content})
|
||||
%{notebook: %{sections: [%{cells: [cell]}]}} = Session.get_data(session_pid)
|
||||
|
||||
# We need to register ourselves as a client to start submitting cell deltas
|
||||
user = Livebook.Users.User.new()
|
||||
Session.register_client(session_pid, self(), user)
|
||||
|
||||
delta = Delta.new(insert: content)
|
||||
Session.apply_cell_delta(session_pid, cell.id, delta, 1)
|
||||
|
||||
wait_for_session_update(session_pid)
|
||||
|
||||
cell.id
|
||||
end
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue