mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-09-04 03:54:24 +08:00
Add 'Render ... Markdown blocks' option to published apps
> Disclaimer: it's a proof-of-a-concept for an idea discussion. It's an attempt to introduce a "Render ... Markdown blocks" feature to the published apps as an option. It shall consider to render markdown block from the original notebook as an addition to the evaluable cells. Due to the limited understanding of how app rendering pipeline works, this commit should be considered only as a proof-of-a-concept, that most likely will be reworked fully. P.S. Eventually, it should also take image and section titles cells and render them.
This commit is contained in:
parent
ba95bf7e57
commit
99ea48ae9d
8 changed files with 84 additions and 10 deletions
|
@ -14,7 +14,8 @@ defmodule Livebook.Notebook.AppSettings do
|
|||
access_type: access_type(),
|
||||
password: String.t() | nil,
|
||||
show_source: boolean(),
|
||||
output_type: output_type()
|
||||
output_type: output_type(),
|
||||
render_static: boolean()
|
||||
}
|
||||
|
||||
@type access_type :: :public | :protected
|
||||
|
@ -33,6 +34,7 @@ defmodule Livebook.Notebook.AppSettings do
|
|||
field :password, :string
|
||||
field :show_source, :boolean
|
||||
field :output_type, Ecto.Enum, values: [:all, :rich]
|
||||
field :render_static, :boolean
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -49,7 +51,8 @@ defmodule Livebook.Notebook.AppSettings do
|
|||
access_type: :protected,
|
||||
password: generate_password(),
|
||||
show_source: false,
|
||||
output_type: :all
|
||||
output_type: :all,
|
||||
render_static: false
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -82,14 +85,16 @@ defmodule Livebook.Notebook.AppSettings do
|
|||
:auto_shutdown_ms,
|
||||
:access_type,
|
||||
:show_source,
|
||||
:output_type
|
||||
:output_type,
|
||||
:render_static
|
||||
])
|
||||
|> validate_required([
|
||||
:slug,
|
||||
:multi_session,
|
||||
:access_type,
|
||||
:show_source,
|
||||
:output_type
|
||||
:output_type,
|
||||
:render_static
|
||||
])
|
||||
|> validate_format(:slug, ~r/^[a-z0-9-]+$/,
|
||||
message: "should only contain lowercase alphanumeric characters and dashes"
|
||||
|
|
|
@ -49,6 +49,13 @@ defmodule Livebook.Notebook.Cell do
|
|||
def evaluable?(%Cell.Smart{}), do: true
|
||||
def evaluable?(_cell), do: false
|
||||
|
||||
@doc """
|
||||
Checks if the given cell can be statically rendered
|
||||
"""
|
||||
@spec static?(t()) :: boolean()
|
||||
def static?(%Cell.Markdown{}), do: true
|
||||
def static?(_), do: false
|
||||
|
||||
@doc """
|
||||
Extracts all inputs from the given indexed output.
|
||||
"""
|
||||
|
|
|
@ -442,17 +442,42 @@ defmodule LivebookWeb.AppSessionLive do
|
|||
defp data_to_view(data) do
|
||||
changed_input_ids = Session.Data.changed_input_ids(data)
|
||||
|
||||
%{
|
||||
notebook_name: data.notebook.name,
|
||||
cell_views:
|
||||
for {cell, _section} <- Notebook.evaluable_cells_with_section(data.notebook) do
|
||||
shall_render = fn cell ->
|
||||
if data.notebook.app_settings.render_static do
|
||||
Cell.evaluable?(cell) or Cell.static?(cell)
|
||||
else
|
||||
Cell.evaluable?(cell)
|
||||
end
|
||||
end
|
||||
|
||||
cell_views =
|
||||
data.notebook
|
||||
|> Notebook.cells_with_section()
|
||||
|> Enum.filter(fn {cell, _section} -> shall_render.(cell) end)
|
||||
|> Enum.map(fn
|
||||
{%Livebook.Notebook.Cell.Markdown{} = cell, _section} ->
|
||||
out_id = :rand.uniform(31337)
|
||||
output = {out_id, %{type: :markdown_static, text: cell.source, chunk: false}}
|
||||
|
||||
%{
|
||||
id: cell.id,
|
||||
input_views: [],
|
||||
outputs: [output],
|
||||
outputs_batch_number: 0
|
||||
}
|
||||
|
||||
{cell, _section} ->
|
||||
%{
|
||||
id: cell.id,
|
||||
input_views: input_views_for_cell(cell, data, changed_input_ids),
|
||||
outputs: filter_outputs(cell.outputs, data.notebook.app_settings.output_type),
|
||||
outputs_batch_number: data.cell_infos[cell.id].eval.outputs_batch_number
|
||||
}
|
||||
end,
|
||||
end)
|
||||
|
||||
%{
|
||||
notebook_name: data.notebook.name,
|
||||
cell_views: cell_views,
|
||||
app_status: data.app_data.status,
|
||||
show_source: data.notebook.app_settings.show_source,
|
||||
slug: data.notebook.app_settings.slug,
|
||||
|
|
|
@ -64,6 +64,19 @@ defmodule LivebookWeb.Output do
|
|||
"""
|
||||
end
|
||||
|
||||
defp render_output(%{type: :markdown_static} = output, %{id: id, session_id: session_id}) do
|
||||
assigns = %{id: id, session_id: session_id, output: output}
|
||||
|
||||
~H"""
|
||||
<.live_component
|
||||
module={Output.MarkdownStaticComponent}
|
||||
id={@id}
|
||||
session_id={@session_id}
|
||||
output={@output}
|
||||
/>
|
||||
"""
|
||||
end
|
||||
|
||||
defp render_output(%{type: :image} = output, %{id: id}) do
|
||||
assigns = %{id: id, content: output.content, mime_type: output.mime_type}
|
||||
|
||||
|
|
12
lib/livebook_web/live/output/markdown_static_component.ex
Normal file
12
lib/livebook_web/live/output/markdown_static_component.ex
Normal file
|
@ -0,0 +1,12 @@
|
|||
defmodule LivebookWeb.Output.MarkdownStaticComponent do
|
||||
use LivebookWeb, :live_component
|
||||
|
||||
@impl true
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div>{to_html(@output.text)}</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp to_html(markdown), do: Earmark.as_html!(markdown) |> Phoenix.HTML.raw()
|
||||
end
|
|
@ -105,6 +105,17 @@ defmodule LivebookWeb.SessionLive.AppSettingsComponent do
|
|||
'''
|
||||
}
|
||||
/>
|
||||
<.checkbox_field
|
||||
field={f[:render_static]}
|
||||
label="Render sections and Markdown blocks"
|
||||
help={
|
||||
~S'''
|
||||
When enabled, renders all the added
|
||||
h2-sections and Markdown blocks of
|
||||
the original notebook.
|
||||
'''
|
||||
}
|
||||
/>
|
||||
<%= if Ecto.Changeset.get_field(@changeset, :multi_session) do %>
|
||||
<.checkbox_field
|
||||
field={f[:show_existing_sessions]}
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -114,7 +114,7 @@ defmodule Livebook.MixProject do
|
|||
{:bandit, "~> 1.0"},
|
||||
{:plug, "~> 1.16"},
|
||||
{:plug_crypto, "~> 2.0"},
|
||||
{:earmark_parser, "~> 1.4"},
|
||||
{:earmark, "~> 1.4"},
|
||||
{:ecto, "~> 3.10"},
|
||||
{:phoenix_ecto, "~> 4.4"},
|
||||
{:aws_credentials, "~> 0.3.0", runtime: false},
|
||||
|
|
1
mix.lock
1
mix.lock
|
@ -9,6 +9,7 @@
|
|||
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
|
||||
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
|
||||
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"},
|
||||
"earmark": {:hex, :earmark, "1.4.47", "7e7596b84fe4ebeb8751e14cbaeaf4d7a0237708f2ce43630cfd9065551f94ca", [:mix], [], "hexpm", "3e96bebea2c2d95f3b346a7ff22285bc68a99fbabdad9b655aa9c6be06c698f8"},
|
||||
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
|
||||
"ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"},
|
||||
"eini": {:hex, :eini_beam, "2.2.4", "02143b1dce4dda4243248e7d9b3d8274b8d9f5a666445e3d868e2cce79e4ff22", [:rebar3], [], "hexpm", "12de479d144b19e09bb92ba202a7ea716739929afdf9dff01ad802e2b1508471"},
|
||||
|
|
Loading…
Add table
Reference in a new issue