Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static preview, live Binder in the background #811

Merged
merged 145 commits into from
Apr 1, 2021
Merged

Conversation

fonsp
Copy link
Owner

@fonsp fonsp commented Dec 29, 2020

Schermafbeelding 2020-12-29 om 17 53 46

A minimal demo of a static notebook transitioning to a live binder session

You can already run Pluto notebooks on binder, but the load times are too long without anything too look at. You would not use this to write interactive articles on the web. So we're still not revolutionizing scientific publishing! Oops!

The solution:

Show a static preview of the notebook, and start a binder session in the background.

Demo link:

https://pluto-binder-static-to-live-1.netlify.app/editor.html?notebookfile=https%3A%2F%2Fmkhj.fra1.cdn.digitaloceanspaces.com%2Fsample%2520Tower%2520of%2520Hanoi%252016.jl&statefile=https%3A%2F%2Fmkhj.fra1.cdn.digitaloceanspaces.com%2Fsample%2520Tower%2520of%2520Hanoi%252016.jl.plutostate&binder_url=https%3A%2F%2Fmybinder.org%2Fbuild%2Fgh%2Ffonsp%2Fpluto-on-binder%2Fstatic-to-live-1

Schermopname.2020-12-22.om.23.54.44.mov

How it works

We host the Pluto editor online on a CDN (i.e. we just host the /frontend folder):
https://jovial-newton-a0c386.netlify.app/
with the editor at:
https://jovial-newton-a0c386.netlify.app/editor.html

We host with a snapshot of the (React) state of the notebook:
https://mkhj.fra1.cdn.digitaloceanspaces.com/sample%20Tower%20of%20Hanoi%2016.jl.plutostate
and the notebook file itself:
https://mkhj.fra1.cdn.digitaloceanspaces.com/sample%20Tower%20of%20Hanoi%2016.jl

These two URLs are passed to the editor as URL parameters. When the editor launhces with these url parameters, it downloads the state object and applies it locally, and displays a binder button.

A Binder session can be requested headless (in the background) using a special endpoint, /build instead of /v2. This is used by https://github.com/executablebooks/thebe

Code

The important edits are on the Pluto side (this PR), with matching changes to our binder'ed repository:
fonsp/pluto-on-binder#8

Description of changes

Code to request a binder in the background, based on https://github.com/executablebooks/thebe

  • Binder.js -- modified and stripped down code from thebe
  • Editor.js -- if the right parameters are set, then dont connect to the WS immediately, but load the global state from a URL
  • Editor.js -- handle binder connection phases

Some changes to allow an export script to generate a version of editor.html with CDNified resources (http://cdn.jsdelivr.net/gh/fonsp/[email protected]/frontend/editor.css instead of ./editor.css) and a baked base64-encoded state object.

  • editor.html -- href="./ urls for easy string detection; HTML comment where JS can be inserted
  • Editor.js -- a new unified parameter object that takes things from either window.pluto_someproperty or a &someproperty= url parameter
  • Made serviceworker a single file

CSS changes:

  • editor.css -- a cool new binder button and loading bar like the video above
  • editor.css -- allow the frontend to hide all UI (for blogs) by adding a class to body and by changing the media attribute of the hide-ui.css import from print to all

Some changes to allow the Pluto server to run fully on CORS requests if security is disabled:

  • WebServer.jl -- allow random access to websocket when security is disabled
  • Static.jl -- CORS header & a new POST /open endpoint to get the created notebook ID as a response, instead of a redirect to /edit?id=<new id>, since redirects don't CORS nicely

@fonsp fonsp merged commit 48770ce into main Apr 1, 2021
@fonsp
Copy link
Owner Author

fonsp commented Apr 8, 2021

@Ellipse0934 @mbauman I merged this and #988 into Pluto and released as 0.14.1! Normal users won't see the effects, but it means that 'vanilla' Pluto now has this functionality built in.

I also updated the popup box in the top right from a single binder button (like in the demo video of this PR) to the two-click button we used on https://computationalthinking.mit.edu/.

This should make it easier to edit and add options like the juliahub button!

@OvidiusCicero
Copy link

Pointer how to actually generate an HTML file programmatically as in #899?

@Ellipse0934
Copy link
Contributor

@OvidiusCicero You mean something like

import Pluto
s = Pluto.ServerSession();
nb = Pluto.SessionActions.open(s, "./notebook.jl"; run_async=false)
html_contents = Pluto.generate_html(nb)
write("./notebook.html", html_contents)

?

@OvidiusCicero
Copy link

exactly thank you!

Is there a way to spawn this from a running Pluto session, maybe without the time intensive line

nb = Pluto.SessionActions.open(s, "./notebook.jl"; run_async=false)

?

@fonsp
Copy link
Owner Author

fonsp commented Apr 12, 2021

You can use the export button in the top right

@Ellipse0934
Copy link
Contributor

@OvidiusCicero Maybe you want to use @task to decouple it and have it run independently while you work on other stuff.

@OvidiusCicero
Copy link

@fonsp I want to trigger the export button programmatically

@Ellipse0934 i guess that works

@fonsp
Copy link
Owner Author

fonsp commented Apr 13, 2021

You can also right click the export button to get the link and do some hacking with the download function. @__FILE__ can give you the notebook ID.

@OvidiusCicero
Copy link

grafik

@fonsp this looks like an approachable idea but @__FILE__ neither returns the notebook id nor is the id part returned by it constant at all for me :(

@fonsp
Copy link
Owner Author

fonsp commented Apr 14, 2021

Ah oops, that is the cell id. Sorry! If you can convince me why this feature would be useful I can think about it more :)

pankgeorg pushed a commit that referenced this pull request Apr 25, 2021
Co-authored-by: Fons van der Plas <[email protected]>
Co-authored-by: Michiel Dral <[email protected]>
Co-authored-by: Παναγιώτης Γεωργακόπουλος <[email protected]>
@fonsp
Copy link
Owner Author

fonsp commented Apr 26, 2021

@OvidiusCicero 72cfac4

@OvidiusCicero
Copy link

@fonsp thanks, sorry I was distracted the last weeks

I can indeed get the ID of the notebook by uuid = PlutoRunner.notebook_id[]|>string but when I try Downloads.download("http://localhost:1234/notebookexport?id=$uuid" in Julia I get

ERROR: HTTP/1.1 403 Forbidden while requesting http://localhost:1234/notebookexport?id=dec4a93e-ac3a-11eb-1117-775dcefcc761

when I open the link in the browser I seemingly get the HTML

If you can convince me why this feature would be useful I can think about it more :)

I use the generated static HTML pages (okay, they're not so much static) from Pluto as reports to present results (like sending them around) and features like this would make keeping the HTML in sync with the actual notebook much easier

@fonsp
Copy link
Owner Author

fonsp commented May 3, 2021

Ah that's because the Pluto server is behind authentication. (You could disable authentication.)

Another idea is to fork Pluto and implement this directly. You could look for the places where we call save_notebook, and also save the export there.

@OvidiusCicero
Copy link

how are the authentications turned off? I foundrequire_secret_for_access= false) but to no avail?

This and other stuff like notebook="…" or the TOCs seem to not be documented anywhere, would writing mini documentation for this somewhere (like the Wiki) be appreciated?

I'll also look into forking Pluto for this some time, this seems to be the cleanest way, but it will take time

@fonsp
Copy link
Owner Author

fonsp commented May 7, 2021

@OvidiusCicero It would be great if you could figure out a way to get those things into the docstring for Pluto.Configuration, ideally without duplicates. Then we can link to https://juliahub.com/docs/Pluto/OJqMt/0.14.5/autodocs/ if we want it online

@fonsp
Copy link
Owner Author

fonsp commented May 7, 2021

To fully disable authentication you need to disable both flags:

"""
SecurityOptions([; kwargs...])
Security settings for the HTTP server. Options are:
- `require_secret_for_open_links::Bool = true`
Whether the links `http://localhost:1234/open?path=/a/b/c.jl` and `http://localhost:1234/open?path=http://www.a.b/c.jl` should be protected.
Use `true` for almost every setup. Only use `false` if Pluto is running in a safe container (like mybinder.org), where arbitrary code execution is not a problem.
- `require_secret_for_access::Bool = true`
If false, you do not need to use a `secret` in the URL to access Pluto: you will be authenticated by visiting `http://localhost:1234/` in your browser. An authentication cookie is still used for access (to prevent XSS and deceptive links or an img src to `http://localhost:1234/open?url=badpeople.org/script.jl`), and is set automatically, but this request to `/` is protected by cross-origin policy.
Use `true` on a computer used by multiple people simultaneously. Only use `false` if necessary.
**Leave these options on `true` for the most secure setup.**
Note that Pluto is quickly evolving software, maintained by designers, educators and enthusiasts — not security experts. If security is a serious concern for your application, then we recommend running Pluto inside a container and verifying the relevant security aspects of Pluto yourself.
"""
@option mutable struct SecurityOptions
require_secret_for_open_links::Bool = true
require_secret_for_access::Bool = true
end

@dralletje dralletje deleted the binder-static-to-live-1 branch November 6, 2021 00:05
@fonsp fonsp added the publishing Notebooks as static documents on the web label Oct 30, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
publishing Notebooks as static documents on the web
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Export html API Exported HTML does not show title
4 participants