livebook/lib/livebook_web/live/session_live/section_component.ex
Lee Jarvis 4bacba6b1d
Remove delete prompt for empty sections (#829)
* Remove delete prompt for empty sections

If a section has no cell views or only empty cell views, avoid
prompting the user to delete the section and just go ahead and delete
it.

Closes #800

* Move delete prompt logic to SessionLive

This avoids creating two separate paths in the view for displaying
delete buttons (triggering either a prompt, or deleting the empty
section).

Instead, the `delete_section` callback is always triggered, and the
"display prompt" logic is kept here.

Couple of things I'm unsure about so will discuss on the PR.

See https://github.com/livebook-dev/livebook/pull/829#discussion_r775560671

* Check only against empty cell list in `delete_section`

* Fix indentation

* Handle section not existing on deletion

* Match empty cell list in case expression

Also explicitly set the section and then re-use it. I think this is a
bit nicer than just matching against the empty list since it matches
the following match too
2021-12-27 18:42:27 +01:00

121 lines
5.5 KiB
Elixir

defmodule LivebookWeb.SessionLive.SectionComponent do
use LivebookWeb, :live_component
def render(assigns) do
~H"""
<section data-element="section" data-section-id={@section_view.id}>
<div class="flex space-x-4 items-center"
data-element="section-headline"
id={@section_view.id}
data-focusable-id={@section_view.id}
phx-hook="Headline"
data-on-value-change="set_section_name"
data-metadata={@section_view.id}>
<h2 class="flex-grow text-gray-800 font-semibold text-2xl px-1 -ml-1 rounded-lg border border-transparent whitespace-pre-wrap cursor-text"
tabindex="0"
id={@section_view.html_id}
data-element="heading"
spellcheck="false"><%= @section_view.name %></h2>
<div class="flex space-x-2 items-center" data-element="section-actions"
role="toolbar"
aria-label="section actions">
<span class="tooltip top" data-tooltip="Link">
<a href={"##{@section_view.html_id}"} class="icon-button" aria-label="link to section">
<.remix_icon icon="link" class="text-xl" />
</a>
</span>
<%= if @section_view.valid_parents != [] and not @section_view.has_children? do %>
<.menu id={"section-#{@section_view.id}-branch-menu"}>
<:toggle>
<span class="tooltip top" data-tooltip="Branch out from">
<button class="icon-button" aria-label="branch out from other section">
<.remix_icon icon="git-branch-line" class="text-xl flip-horizontally" />
</button>
</span>
</:toggle>
<:content>
<%= for parent <- @section_view.valid_parents do %>
<%= if @section_view.parent && @section_view.parent.id == parent.id do %>
<button class="menu-item text-gray-900"
phx-click="unset_section_parent"
phx-value-section_id={@section_view.id}>
<.remix_icon icon="arrow-right-s-line" />
<span class="font-medium"><%= parent.name %></span>
</button>
<% else %>
<button class="menu-item text-gray-500"
phx-click="set_section_parent"
phx-value-section_id={@section_view.id}
phx-value-parent_id={parent.id}>
<.remix_icon icon="arrow-right-s-line" />
<span class="font-medium"><%= parent.name %></span>
</button>
<% end %>
<% end %>
</:content>
</.menu>
<% end %>
<span class="tooltip top" data-tooltip="Move up">
<button class="icon-button"
aria-label="move section up"
phx-click="move_section"
phx-value-section_id={@section_view.id}
phx-value-offset="-1">
<.remix_icon icon="arrow-up-s-line" class="text-xl" />
</button>
</span>
<span class="tooltip top" data-tooltip="Move down">
<button class="icon-button"
aria-label="move section down"
phx-click="move_section"
phx-value-section_id={@section_view.id}
phx-value-offset="1">
<.remix_icon icon="arrow-down-s-line" class="text-xl" />
</button>
</span>
<span
{if @section_view.has_children?,
do: [class: "tooltip left", data_tooltip: "Cannot delete this section because\nother sections branch from it"],
else: [class: "tooltip top", data_tooltip: "Delete"]}>
<button class={"icon-button #{if @section_view.has_children?, do: "disabled"}"}
aria-label="delete section"
phx-click="delete_section"
phx-value-section_id={@section_view.id}>
<.remix_icon icon="delete-bin-6-line" class="text-xl" />
</button>
</span>
</div>
</div>
<%= if @section_view.parent do %>
<h3 class="mt-1 flex items-end space-x-1 text-sm font-semibold text-gray-800">
<span class="tooltip bottom" data-tooltip={"This section branches out from the main flow\nand can be evaluated in parallel"}>
<.remix_icon icon="git-branch-line" class="text-lg font-normal flip-horizontally leading-none" />
</span>
<span class="leading-none">from ”<%= @section_view.parent.name %>”</span>
</h3>
<% end %>
<div class="container">
<div class="flex flex-col space-y-1">
<.live_component module={LivebookWeb.SessionLive.InsertButtonsComponent}
id={"#{@section_view.id}:first"}
persistent={@section_view.cell_views == []}
section_id={@section_view.id}
cell_id={nil} />
<%= for {cell_view, index} <- Enum.with_index(@section_view.cell_views) do %>
<.live_component module={LivebookWeb.SessionLive.CellComponent}
id={cell_view.id}
session_id={@session_id}
runtime={@runtime}
cell_view={cell_view} />
<.live_component module={LivebookWeb.SessionLive.InsertButtonsComponent}
id={"#{@section_view.id}:#{index}"}
persistent={false}
section_id={@section_view.id}
cell_id={cell_view.id} />
<% end %>
</div>
</div>
</section>
"""
end
end