diff --git a/frontend/components/Cell.js b/frontend/components/Cell.js index ea30b29e07..247740152a 100644 --- a/frontend/components/Cell.js +++ b/frontend/components/Cell.js @@ -311,7 +311,9 @@ export const Cell = ({ set_cm_highlighted_line=${set_cm_highlighted_line} onerror=${remount} /> - ${show_logs ? html`<${Logs} logs=${Object.values(logs)} line_heights=${line_heights} set_cm_highlighted_line=${set_cm_highlighted_line} />` : null} + ${show_logs && cell_api_ready + ? html`<${Logs} logs=${Object.values(logs)} line_heights=${line_heights} set_cm_highlighted_line=${set_cm_highlighted_line} />` + : null} <${RunArea} cell_id=${cell_id} running_disabled=${running_disabled} diff --git a/src/evaluation/WorkspaceManager.jl b/src/evaluation/WorkspaceManager.jl index 9412903f4a..55fb090655 100644 --- a/src/evaluation/WorkspaceManager.jl +++ b/src/evaluation/WorkspaceManager.jl @@ -229,6 +229,10 @@ function start_relaying_logs((session, notebook)::SN, log_channel::Distributed.R @assert !isnothing(display_cell) + # this handles the use of published_to_js inside logs: objects that were newly published during the rendering of the log args. + merge!(display_cell.published_objects, next_log["new_published_objects"]) + delete!(next_log, "new_published_objects") + push!(display_cell.logs, next_log) Pluto.@asynclog update_throttled() catch e diff --git a/src/runner/PlutoRunner.jl b/src/runner/PlutoRunner.jl index 5e3b49e81f..8ff95058ac 100644 --- a/src/runner/PlutoRunner.jl +++ b/src/runner/PlutoRunner.jl @@ -2125,28 +2125,26 @@ end""" """ const currently_running_cell_id = Ref{UUID}(uuid4()) -function _publish(x, id_start)::String - assertpackable(x) - - id = string(notebook_id[], "/", currently_running_cell_id[], "/", id_start) - d = get!(Dict{String,Any}, cell_published_objects, currently_running_cell_id[]) +function _publish(x, id_start, cell_id)::String + id = "$(notebook_id[])/$cell_id/$id_start" + d = get!(Dict{String,Any}, cell_published_objects, cell_id) d[id] = x return id end -_publish(x) = _publish(x, objectid2str(x)) - # TODO? Possibly move this to it's own package, with fallback that actually msgpack? # ..... Ideally we'd make this require `await` on the javascript side too... Base.@kwdef struct PublishedToJavascript - published_id + published_object + published_id_start cell_id end function Base.show(io::IO, ::MIME"text/javascript", published::PublishedToJavascript) - if published.cell_id != currently_running_cell_id[] - error("Showing result from PlutoRunner.publish_to_js() in a cell different from where it was created, not (yet?) supported.") - end - write(io, "/* See the documentation for PlutoRunner.publish_to_js */ getPublishedObject(\"$(published.published_id)\")") + id = _publish(published.published_object, published.published_id_start, published.cell_id) + # if published.cell_id != currently_running_cell_id[] + # error("Showing result from PlutoRunner.publish_to_js() in a cell different from where it was created, not (yet?) supported.") + # end + write(io, "/* See the documentation for PlutoRunner.publish_to_js */ getPublishedObject(\"$(id)\")") end Base.show(io::IO, ::MIME"text/plain", published::PublishedToJavascript) = show(io, MIME("text/javascript"), published) Base.show(io::IO, published::PublishedToJavascript) = show(io, MIME("text/javascript"), published) @@ -2179,9 +2177,13 @@ let end ``` """ -function publish_to_js(args...) +publish_to_js(x) = publish_to_js(x, objectid2str(x)) + +function publish_to_js(x, id_start) + assertpackable(x) PublishedToJavascript( - published_id=_publish(args...), + published_object=x, + published_id_start=id_start, cell_id=currently_running_cell_id[], ) end @@ -2387,18 +2389,32 @@ function Logging.handle_message(pl::PlutoCellLogger, level, msg, _module, group, end try - yield() + po() = get(cell_published_objects, pl.cell_id, Dict{String,Any}()) + before_published_object_keys = collect(keys(po())) + + # Render the log arguments: + msg_formatted = format_output_default(msg isa AbstractString ? Text(msg) : msg) + kwargs_formatted = Tuple{String,Any}[(string(k), format_log_value(v)) for (k, v) in kwargs if k != :maxlog] + + after_published_object_keys = collect(keys(po())) + new_published_object_keys = setdiff(after_published_object_keys, before_published_object_keys) + + # (Running `put!(pl.log_channel, x)` will send `x` to the pluto server. See `start_relaying_logs` for the receiving end.) put!(pl.log_channel, Dict{String,Any}( "level" => string(level), - "msg" => format_output_default(msg isa AbstractString ? Text(msg) : msg), + "msg" => msg_formatted, + # This is a dictionary containing all published objects that were published during the rendering of the log arguments (we cannot track which objects were published during the execution of the log statement itself i think...) + "new_published_objects" => Dict{String,Any}( + key => po()[key] for key in new_published_object_keys + ), "group" => string(group), "id" => string(id), "file" => string(file), "cell_id" => pl.cell_id, "line" => line isa Union{Int32,Int64} ? line : nothing, - "kwargs" => Tuple{String,Any}[(string(k), format_log_value(v)) for (k, v) in kwargs if k != :maxlog], + "kwargs" => kwargs_formatted, )) yield() diff --git a/src/webserver/Dynamic.jl b/src/webserver/Dynamic.jl index 8fcfe2a21d..60e3677510 100644 --- a/src/webserver/Dynamic.jl +++ b/src/webserver/Dynamic.jl @@ -133,7 +133,7 @@ function notebook_to_js(notebook::Notebook) "cell_id" => cell.cell_id, "depends_on_disabled_cells" => cell.depends_on_disabled_cells, "output" => FirebaseyUtils.ImmutableMarker(cell.output), - "published_object_keys" => keys(cell.published_objects), + "published_object_keys" => collect(keys(cell.published_objects)), "queued" => cell.queued, "running" => cell.running, "errored" => cell.errored, diff --git a/test/Dynamic.jl b/test/Dynamic.jl index ed0e3e12c8..f833933ff6 100644 --- a/test/Dynamic.jl +++ b/test/Dynamic.jl @@ -194,17 +194,19 @@ end @testset "PlutoRunner API" begin 🍭 = ServerSession() 🍭.options.evaluation.workspace_use_distributed = true + + cid = uuid1() notebook = Notebook([ Cell("PlutoRunner.notebook_id[] |> Text"), - Cell(""" + Cell(cid, """ let # not actually public API but we test it anyways a = PlutoRunner._publish(Dict( "hello" => "world", "xx" => UInt8[6,7,8], - )) - b = PlutoRunner._publish("cool") + ), "aaa", Base.UUID("$cid")) + b = PlutoRunner._publish("cool", "bbb", Base.UUID("$cid")) Text((a, b)) end """),