Skip to content

Commit 5ded53d

Browse files
aleDszhugobaraunajonatanklosko
authored
Introduces the output size for cells (#3160)
Co-authored-by: Hugo Baraúna <hugo.barauna@gmail.com> Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
1 parent a0e3280 commit 5ded53d

19 files changed

Lines changed: 302 additions & 64 deletions

File tree

assets/css/js_interop.css

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,46 @@ server in solely client-side operations.
327327
}
328328

329329
[data-el-notebook] {
330-
/* Outputs (both session and app) */
330+
/* Output size (both session and app) */
331331

332-
[data-el-cell][data-js-amplified] {
333-
[data-el-amplify-outputs-button] > button {
334-
@apply bg-gray-100 text-gray-900;
332+
[data-output-size="default"][data-el-app-outputs-container] {
333+
@apply w-full mx-auto;
334+
335+
max-width: var(--breakpoint-lg);
336+
}
337+
338+
[data-output-size="wide"] {
339+
&[data-el-app-outputs-container] {
340+
@apply w-full mx-auto;
341+
342+
max-width: 90rem;
343+
}
344+
345+
[data-el-outputs-container] {
346+
@apply bg-white m-0 relative;
347+
348+
width: 90rem;
349+
left: calc(-45rem + 50%);
350+
}
351+
}
352+
353+
[data-output-size="full"] {
354+
&[data-el-app-outputs-container] {
355+
@apply w-full mx-auto;
356+
357+
max-width: 92vw;
335358
}
336359

337360
[data-el-outputs-container] {
338-
@apply bg-white m-0 py-16;
361+
@apply bg-white m-0 relative;
339362

340-
width: 90vw;
341-
position: relative;
342-
left: calc(-45vw + 50%);
363+
width: 92vw;
364+
left: calc(-46vw + 50%);
343365
}
344366
}
345367

368+
/* Outputs (both session and app) */
369+
346370
[data-el-output][data-border] {
347371
@apply p-4 border border-t-0 border-gray-200 divide-y divide-gray-200;
348372
}

assets/js/hooks/cell.js

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,6 @@ const Cell = {
3939

4040
this.updateInsertModeAvailability();
4141

42-
// Setup action handlers
43-
44-
const amplifyButton = this.el.querySelector(
45-
`[data-el-amplify-outputs-button]`,
46-
);
47-
48-
if (amplifyButton) {
49-
amplifyButton.addEventListener("click", (event) => {
50-
this.el.toggleAttribute("data-js-amplified");
51-
});
52-
}
53-
5442
if (this.props.type === "smart") {
5543
const toggleSourceButton = this.el.querySelector(
5644
`[data-el-toggle-source-button]`,

assets/js/hooks/js_view.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,8 @@ const JSView = {
225225
`[data-el-notebook-content]`,
226226
);
227227

228+
const outputsContainerEl = this.el.closest(`[data-el-outputs-container]`);
229+
228230
// Most placeholder position changes are accompanied by changes
229231
// to the notebook content element height (adding cells, inserting
230232
// newlines in the editor, etc). On the other hand, toggling the
@@ -238,6 +240,10 @@ const JSView = {
238240
resizeObserver.observe(notebookContentEl);
239241
resizeObserver.observe(notebookEl);
240242

243+
// We also observe the outputs container, since the outputs width is
244+
// configurable and can change dynamically.
245+
if (outputsContainerEl) resizeObserver.observe(outputsContainerEl);
246+
241247
// The placeholder may be hidden, in which case we want to hide
242248
// the iframe as well. This could be the case when viewing the
243249
// Smart cell source or in tabs output. It is possible that the

lib/livebook/live_markdown/export.ex

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -211,23 +211,34 @@ defmodule Livebook.LiveMarkdown.Export do
211211
end
212212

213213
defp render_cell(%Cell.Smart{} = cell, ctx) do
214+
metadata =
215+
Map.merge(
216+
cell_metadata(cell),
217+
%{
218+
livebook_object: "smart_cell",
219+
kind: cell.kind,
220+
# Attributes may include arbitrary values, including sequences
221+
# like "-->" that would mess our format, so we always encode them
222+
attrs: cell.attrs |> JSON.encode!(&encode_sorting/2) |> Base.encode64(padding: false),
223+
chunks: cell.chunks && Enum.map(cell.chunks, &Tuple.to_list/1)
224+
}
225+
)
226+
214227
%{Cell.Code.new() | source: cell.source, outputs: cell.outputs}
215228
|> render_cell(ctx)
216-
|> prepend_metadata(%{
217-
"livebook_object" => "smart_cell",
218-
"kind" => cell.kind,
219-
# Attributes may include arbitrary values, including sequences
220-
# like "-->" that would mess our format, so we always encode them
221-
"attrs" => cell.attrs |> JSON.encode!(&encode_sorting/2) |> Base.encode64(padding: false),
222-
"chunks" => cell.chunks && Enum.map(cell.chunks, &Tuple.to_list/1)
223-
})
229+
|> prepend_metadata(metadata)
224230
end
225231

226232
defp cell_metadata(%Cell.Code{} = cell) do
227-
keys = [:reevaluate_automatically, :continue_on_error]
233+
keys = [:reevaluate_automatically, :continue_on_error, :output_size]
228234
put_unless_default(%{}, Map.take(cell, keys), Map.take(Cell.Code.new(), keys))
229235
end
230236

237+
defp cell_metadata(%Cell.Smart{} = cell) do
238+
keys = [:output_size]
239+
put_unless_default(%{}, Map.take(cell, keys), Map.take(Cell.Smart.new(), keys))
240+
end
241+
231242
defp cell_metadata(_cell), do: %{}
232243

233244
defp render_outputs(cell, ctx) do

lib/livebook/live_markdown/import.ex

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ defmodule Livebook.LiveMarkdown.Import do
248248
{outputs, output_counter} = Notebook.index_outputs(outputs, output_counter)
249249
%{"kind" => kind, "attrs" => attrs} = data
250250

251-
attrs =
251+
smart_cell_attrs =
252252
case attrs do
253253
# Import map attributes for backward compatibility
254254
%{} ->
@@ -259,15 +259,18 @@ defmodule Livebook.LiveMarkdown.Import do
259259
end
260260

261261
chunks = if(chunks = data["chunks"], do: Enum.map(chunks, &List.to_tuple/1))
262+
attrs = cell_metadata_to_attrs(:smart, data)
262263

263-
cell = %{
264-
Notebook.Cell.new(:smart)
265-
| source: source,
266-
chunks: chunks,
267-
outputs: outputs,
268-
kind: kind,
269-
attrs: attrs
270-
}
264+
cell =
265+
%{
266+
Notebook.Cell.new(:smart)
267+
| source: source,
268+
chunks: chunks,
269+
outputs: outputs,
270+
kind: kind,
271+
attrs: smart_cell_attrs
272+
}
273+
|> Map.merge(attrs)
271274

272275
build_notebook(elems, [cell | cells], sections, messages, output_counter)
273276
end
@@ -559,6 +562,19 @@ defmodule Livebook.LiveMarkdown.Import do
559562
{"continue_on_error", continue_on_error}, attrs ->
560563
Map.put(attrs, :continue_on_error, continue_on_error)
561564

565+
{"output_size", output_size}, attrs when output_size in ["full", "wide"] ->
566+
Map.put(attrs, :output_size, String.to_atom(output_size))
567+
568+
_entry, attrs ->
569+
attrs
570+
end)
571+
end
572+
573+
defp cell_metadata_to_attrs(:smart, metadata) do
574+
Enum.reduce(metadata, %{}, fn
575+
{"output_size", output_size}, attrs when output_size in ["full", "wide"] ->
576+
Map.put(attrs, :output_size, String.to_atom(output_size))
577+
562578
_entry, attrs ->
563579
attrs
564580
end)

lib/livebook/notebook/cell.ex

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ defmodule Livebook.Notebook.Cell do
1616

1717
@type indexed_output :: {non_neg_integer(), Livebook.Runtime.output()}
1818

19+
@type output_size :: :default | :wide | :full
20+
1921
@setup_cell_id_prefix "setup"
2022
@setup_cell_id "setup"
2123

@@ -111,4 +113,16 @@ defmodule Livebook.Notebook.Cell do
111113
"""
112114
@spec extra_setup_cell_id(atom()) :: id()
113115
def extra_setup_cell_id(language), do: "#{@setup_cell_id_prefix}-#{language}"
116+
117+
@doc """
118+
Return the list of supported output sizes.
119+
"""
120+
@spec output_sizes() :: list(%{name: String.t(), size: String.t()})
121+
def output_sizes() do
122+
[
123+
%{name: "Regular width", size: "default"},
124+
%{name: "Wide width", size: "wide"},
125+
%{name: "Full-width", size: "full"}
126+
]
127+
end
114128
end

lib/livebook/notebook/cell/code.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ defmodule Livebook.Notebook.Cell.Code do
77
defstruct [
88
:id,
99
:source,
10+
:output_size,
1011
:outputs,
1112
:language,
1213
:reevaluate_automatically,
@@ -19,6 +20,7 @@ defmodule Livebook.Notebook.Cell.Code do
1920
@type t :: %__MODULE__{
2021
id: Cell.id(),
2122
source: String.t() | :__pruned__,
23+
output_size: Cell.output_size(),
2224
outputs: list(Cell.indexed_output()),
2325
language: Livebook.Runtime.language(),
2426
reevaluate_automatically: boolean(),
@@ -33,6 +35,7 @@ defmodule Livebook.Notebook.Cell.Code do
3335
%__MODULE__{
3436
id: Utils.random_id(),
3537
source: "",
38+
output_size: :default,
3639
outputs: [],
3740
language: :elixir,
3841
reevaluate_automatically: false,

lib/livebook/notebook/cell/smart.ex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ defmodule Livebook.Notebook.Cell.Smart do
1313
defstruct [
1414
:id,
1515
:source,
16+
:output_size,
1617
:chunks,
1718
:outputs,
1819
:reevaluate_automatically,
@@ -28,6 +29,7 @@ defmodule Livebook.Notebook.Cell.Smart do
2829
@type t :: %__MODULE__{
2930
id: Cell.id(),
3031
source: String.t() | :__pruned__,
32+
output_size: Cell.output_size(),
3133
chunks: Livebook.Runtime.chunks() | nil,
3234
outputs: list(Cell.indexed_output()),
3335
reevaluate_automatically: boolean(),
@@ -47,6 +49,7 @@ defmodule Livebook.Notebook.Cell.Smart do
4749
%__MODULE__{
4850
id: Utils.random_id(),
4951
source: "",
52+
output_size: :default,
5053
chunks: nil,
5154
outputs: [],
5255
reevaluate_automatically: false,

lib/livebook/session/data_sync.ex

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ defmodule Livebook.Session.DataSync do
128128
defp key(%Cell.Smart{} = cell), do: {:smart_cell, cell.source}
129129

130130
defp cell_syncable_fields(%Cell.Code{}),
131-
do: [:language, :reevaluate_automatically, :continue_on_error]
131+
do: [:language, :reevaluate_automatically, :continue_on_error, :output_size]
132+
133+
defp cell_syncable_fields(%Cell.Smart{}), do: [:output_size]
132134

133135
defp cell_syncable_fields(_other), do: []
134136

@@ -399,8 +401,15 @@ defmodule Livebook.Session.DataSync do
399401
source_op ++ attrs_op
400402

401403
%Cell.Smart{} ->
402-
# Smart cells are controlled by Livebook, we ignore external edits.
403-
[]
404+
# Smart cells are controlled by Livebook, we only sync with
405+
# common cell-related metadata, anything else must be ignored.
406+
updated_attrs = attrs_diff(before_cell, after_cell, cell_syncable_fields(before_cell))
407+
408+
if updated_attrs != %{} do
409+
[{:set_cell_attributes, acc.cid, before_cell.id, updated_attrs}]
410+
else
411+
[]
412+
end
404413
end
405414

406415
acc = %{acc | cell_idx: acc.cell_idx + 1}

lib/livebook_web/live/app_session_live.ex

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ defmodule LivebookWeb.AppSessionLive do
159159
</.menu_item>
160160
</.menu>
161161
</div>
162-
<div class="w-full max-w-(--breakpoint-lg) py-4 mx-auto" data-el-notebook-content>
162+
<div class="w-full py-4 mx-auto" data-el-notebook-content>
163163
<div data-el-js-view-iframes phx-update="ignore" id="js-view-iframes"></div>
164164
<div class="flex items-center pb-4 mb-2 space-x-4 border-b border-gray-200 pr-20 md:pr-0">
165165
<h1 class="text-3xl font-semibold text-gray-800">
@@ -178,7 +178,7 @@ defmodule LivebookWeb.AppSessionLive do
178178
<%= if @data_view.app_status.execution == :error do %>
179179
<div class={[
180180
"flex justify-between items-center px-4 py-2 border-l-4 shadow-custom-1",
181-
"text-red-400 border-red-400"
181+
"text-red-400 border-red-400 w-full mx-auto max-w-(--breakpoint-lg)"
182182
]}>
183183
<div>
184184
Something went wrong
@@ -490,7 +490,8 @@ defmodule LivebookWeb.AppSessionLive do
490490
id: cell.id,
491491
input_views: input_views_for_cell(cell, data, changed_input_ids),
492492
outputs: filter_outputs(cell.outputs, data.notebook.app_settings.output_type),
493-
outputs_batch_number: data.cell_infos[cell.id].eval.outputs_batch_number
493+
outputs_batch_number: data.cell_infos[cell.id].eval.outputs_batch_number,
494+
output_size: cell.output_size
494495
}
495496
end,
496497
app_status: data.app_data.status,

0 commit comments

Comments
 (0)