Packages
livebook
0.10.0
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook_web/components/confirm.ex
defmodule LivebookWeb.Confirm do
use Phoenix.Component
import LivebookWeb.CoreComponents
import Phoenix.LiveView
alias Phoenix.LiveView.JS
@doc """
Shows a confirmation modal.
On confirmation runs `on_confirm`. The function receives a socket
and should return the socket. Note that this socket always comes from
the root LV level, keep this in mind when using in a component and
dealing with assigns.
Make sure to render `confirm_root/1` in the layout.
## Options
* `:title` - title of the confirmation modal. Defaults to `"Are you sure?"`
* `:description` - content of the confirmation modal. Required
* `:confirm_text` - text of the confirm button. Defaults to `"Yes"`
* `:confirm_icon` - icon in the confirm button. Optional
* `:danger` - whether the action is destructive or regular. Defaults to `true`
* `:opt_out_id` - enables the "Don't show this message again"
checkbox. Once checked by the user, the confirmation with this
id is never shown again. Optional
"""
def confirm(socket, on_confirm, opts) do
opts =
Keyword.validate!(
opts,
title: "Are you sure?",
description: nil,
confirm_text: "Yes",
confirm_icon: nil,
danger: true,
opt_out_id: nil
)
send(self(), {:confirm, on_confirm, opts})
socket
end
@doc """
Renders the confirmation modal for `confirm/3`.
"""
attr :confirm_state, :map, required: true
def confirm_root(assigns) do
~H"""
<.confirm_modal :if={@confirm_state} id={"confirm-#{@confirm_state.id}"} {@confirm_state.attrs} />
"""
end
defp confirm_modal(assigns) do
~H"""
<.modal id={@id} width={:medium} show={true}>
<form
id={"#{@id}-confirm-content"}
class="p-6 flex flex-col"
phx-submit={JS.push("confirm") |> hide_modal(@id)}
data-el-confirm-form
>
<h3 class="text-2xl font-semibold text-gray-800">
<%= @title %>
</h3>
<p class="mt-8 text-gray-700">
<%= @description %>
</p>
<label :if={@opt_out_id} class="mt-6 text-gray-700 flex items-center">
<input class="checkbox mr-3" type="checkbox" name="opt_out_id" value={@opt_out_id} />
<span class="text-sm">
Don't show this message again
</span>
</label>
<div class="mt-8 flex justify-end">
<div class={["flex gap-2", @danger && "flex-row-reverse"]}>
<button class="button-base button-outlined-gray" type="button" phx-click={hide_modal(@id)}>
Cancel
</button>
<button
class={["button-base", if(@danger, do: "button-red", else: "button-blue")]}
type="submit"
>
<.remix_icon :if={@confirm_icon} icon={@confirm_icon} class="align-middle mr-1" />
<span><%= @confirm_text %></span>
</button>
</div>
</div>
</form>
</.modal>
"""
end
def on_mount(:default, _params, _session, socket) do
connect_params = get_connect_params(socket) || %{}
# Opting out is a per-user preference, so we store it on the client
# and send in the connect params
confirm_opt_out_ids = connect_params["confirm_opt_out_ids"] || []
socket =
socket
|> assign(confirm_state: nil, confirm_opt_out_ids: MapSet.new(confirm_opt_out_ids))
|> attach_hook(:confirm, :handle_event, &handle_event/3)
|> attach_hook(:confirm, :handle_info, &handle_info/2)
{:cont, socket}
end
defp handle_event("confirm", params, socket) do
socket =
if opt_out_id = params["opt_out_id"] do
socket
|> update(:confirm_opt_out_ids, &MapSet.put(&1, opt_out_id))
|> push_event("add_confirm_opt_out_id", %{opt_out_id: opt_out_id})
else
socket
end
socket = socket.assigns.confirm_state.on_confirm.(socket)
{:halt, socket}
end
defp handle_event(_event, _params, socket), do: {:cont, socket}
defp handle_info({:confirm, on_confirm, opts}, socket) do
socket =
if opts[:opt_out_id] && opts[:opt_out_id] in socket.assigns.confirm_opt_out_ids do
on_confirm.(socket)
else
assign(socket,
confirm_state: %{
id: Livebook.Utils.random_short_id(),
on_confirm: on_confirm,
attrs: opts
}
)
end
{:cont, socket}
end
defp handle_info(_message, socket), do: {:cont, socket}
end