<.cell_body>
"""
end
defp cell_input(%{cell_view: %{input_type: :textarea}} = assigns) do
~H"""
"""
end
defp cell_input(%{cell_view: %{input_type: :range}} = assigns) do
~H"""
<%= @cell_view.props.min %>
<%= @cell_view.props.max %>
"""
end
defp cell_input(%{cell_view: %{input_type: :select}} = assigns) do
~H"""
"""
end
defp cell_input(assigns) do
~H"""
"""
end
defp html_input_type(:password), do: "password"
defp html_input_type(:number), do: "number"
defp html_input_type(:color), do: "color"
defp html_input_type(:range), do: "range"
defp html_input_type(:select), do: "select"
defp html_input_type(_), do: "text"
defp cell_body(assigns) do
~H"""
<%= render_block(@inner_block) %>
"""
end
defp cell_link_button(assigns) do
~H"""
<.remix_icon icon="link" class="text-xl" />
"""
end
defp cell_settings_button(assigns) do
~H"""
<%= live_patch to: Routes.session_path(@socket, :cell_settings, @session_id, @cell_id), class: "icon-button" do %>
<.remix_icon icon="list-settings-line" class="text-xl" />
<% end %>
"""
end
defp move_cell_up_button(assigns) do
~H"""
"""
end
defp move_cell_down_button(assigns) do
~H"""
"""
end
defp delete_cell_button(assigns) do
~H"""
"""
end
defp editor(assigns) do
~H"""
"""
end
# The whole page has to load and then hooks are mounded.
# There may be a tiny delay before the markdown is rendered
# or editors are mounted, so show neat placeholders immediately.
defp content_placeholder(assigns) do
~H"""
<%= if @empty do %>
<% else %>
<% end %>
"""
end
defp cell_status(%{cell_view: %{evaluation_status: :evaluating}} = assigns) do
~H"""
<.status_indicator circle_class="bg-blue-500" animated_circle_class="bg-blue-400" change_indicator={true}>
"""
end
defp cell_status(%{cell_view: %{evaluation_status: :queued}} = assigns) do
~H"""
<.status_indicator circle_class="bg-gray-500" animated_circle_class="bg-gray-400">
Queued
"""
end
defp cell_status(%{cell_view: %{validity_status: :evaluated}} = assigns) do
~H"""
<.status_indicator
circle_class="bg-green-400"
change_indicator={true}
tooltip={evaluated_label(@cell_view.evaluation_time_ms)}>
Evaluated
"""
end
defp cell_status(%{cell_view: %{validity_status: :stale}} = assigns) do
~H"""
<.status_indicator circle_class="bg-yellow-200" change_indicator={true}>
Stale
"""
end
defp cell_status(%{cell_view: %{validity_status: :aborted}} = assigns) do
~H"""
<.status_indicator circle_class="bg-red-400">
Aborted
"""
end
defp cell_status(assigns), do: ~H""
defp status_indicator(assigns) do
assigns =
assigns
|> assign_new(:animated_circle_class, fn -> nil end)
|> assign_new(:change_indicator, fn -> false end)
|> assign_new(:tooltip, fn -> nil end)
~H"""
<%= render_block(@inner_block) %>
<%= if @change_indicator do %>
*
<% end %>
<%= if @animated_circle_class do %>
<% end %>
"""
end
defp evaluated_label(time_ms) when is_integer(time_ms) do
evaluation_time =
if time_ms > 100 do
seconds = time_ms |> Kernel./(1000) |> Float.floor(1)
"#{seconds}s"
else
"#{time_ms}ms"
end
"Took " <> evaluation_time
end
defp evaluated_label(_time_ms), do: nil
# Outputs
defp outputs(assigns) do
~H"""
<%= for {output, index} <- @cell_view.outputs |> Enum.reverse() |> Enum.with_index(), output != :ignored do %>
"""
end
defp render_output(text, %{id: id}) when is_binary(text) do
# Captured output usually has a trailing newline that we can ignore,
# because each line is itself an HTML block anyway.
text = String.replace_suffix(text, "\n", "")
live_component(LivebookWeb.Output.TextComponent, id: id, content: text, follow: true)
end
defp render_output({:text, text}, %{id: id}) do
live_component(LivebookWeb.Output.TextComponent, id: id, content: text, follow: false)
end
defp render_output({:markdown, markdown}, %{id: id}) do
live_component(LivebookWeb.Output.MarkdownComponent, id: id, content: markdown)
end
defp render_output({:image, content, mime_type}, %{id: id}) do
live_component(LivebookWeb.Output.ImageComponent,
id: id,
content: content,
mime_type: mime_type
)
end
defp render_output({:vega_lite_static, spec}, %{id: id}) do
live_component(LivebookWeb.Output.VegaLiteStaticComponent, id: id, spec: spec)
end
defp render_output({:vega_lite_dynamic, pid}, %{id: id, socket: socket}) do
live_render(socket, LivebookWeb.Output.VegaLiteDynamicLive,
id: id,
session: %{"id" => id, "pid" => pid}
)
end
defp render_output({:table_dynamic, pid}, %{id: id, socket: socket}) do
live_render(socket, LivebookWeb.Output.TableDynamicLive,
id: id,
session: %{"id" => id, "pid" => pid}
)
end
defp render_output({:error, formatted, :runtime_restart_required}, %{}) do
assigns = %{formatted: formatted}
~H"""
<%= render_error_message_output(@formatted) %>
"""
end
defp render_output({:error, formatted, _type}, %{}) do
render_error_message_output(formatted)
end
defp render_output(output, %{}) do
render_error_message_output("""
Unknown output format: #{inspect(output)}. If you're using Kino,
you may want to update Kino and Livebook to the latest version.
""")
end
defp render_error_message_output(message) do
assigns = %{message: message}
~H"""