observablehq / feedback

Customer submitted bugs and feature requests
42 stars 3 forks source link

Save `viewof` state to notebook #603

Open samestep opened 8 months ago

samestep commented 8 months ago

Is your feature request related to a problem? Please describe.

Section 4.3 of a paper from this March describes it better than I can:

although Observable cells can render UI, this UI cannot persistently modify an underlying program. That is, even though an Observable cell can render an arbitrarily rich tool as part of its output, interactions with this tool cannot be “saved” back to the notebook, and their effects will always disappear when the notebook is reloaded. If programming tools are to be part of the process of writing programs, rather than just ephemeral use thereof, rich UIs must be able to modify the underlying program.

The appeal of live, rich (& persistent) tools is strong enough that several platforms, including Observable, have added them as one-off features. Observable has a “Data Table Cell” feature, which lets the user embed a live, rich direct-manipulation table editor in place of an ordinary cell

Describe the solution you'd like

It would be incredible if the state of a viewof cell could be persisted into the notebook itself; that is, if Observable could support custom editors for the data (the code) making up the notebook itself, rather than just for the ephemeral data flowing through it.

Describe alternatives you've considered

There are a few notebooks and forum threads adjacent to this topic:

Often people end up coming up with partial solutions using either localStorage or URLSearchParams, which are OK, but are limited and fragile: the former is difficult to share with other users, and the latter becomes unwieldy when the amount of data grows. Neither of these are on the level of editing experience that one gets when using Observable's set of built-in code or data table cell types.

Additional context

I understand from @tophtucker's forum post that there's a privacy concern to the general idea of custom code editing the notebook. I'd love to know more about how fundamental a barrier this is, as well as whether it's amenable to open-source contribution (I'm guessing the relevant code for this is probably not in the runtime?), and generally whether Observable plans to pursue this direction or if I should look elsewhere for other tools instead.

(Full disclosure: the specific reason I'm interested in all this is as a developer of @penrose; I was looking at this Observable notebook showcasing usage of Penrose v3, and lamenting the fact that the contents of those Editor input boxes could not be automatically persisted to the notebook, as well as the fact that other Monaco editor features like the color picker couldn't be used to edit Penrose Style code, although the latter goes a bit beyond this issue.)

tophtucker commented 8 months ago

Love Penrose! And love this question. It’s something I personally badly want. But it has not been the company’s priority, I think partly because it feels like opening a can of worms. There are various dedicated storage solutions that you can already read/write from an Observable notebook; I think it’s hard to tell if our own solution would be the best or the worst of both worlds. The ol’ classic bundling/unbundling pendulum problem. Less a technical problem so much as a design problem. Do we want a general key-value store (document-scoped or user-scoped?), or something more like transparently cached values of cells (useful for expensive SQL queries!), or something more like a UI flow for the runtime to propose a new cell value (cf. B2)?

Could you describe more of your personal specific use case? If you want a text editor with custom syntax highlighting that persists its value so that a notebook can be a more usable Penrose REPL, it sounds like you’d also be interested in https://github.com/observablehq/feedback/issues/106.

samestep commented 8 months ago

@tophtucker Thanks for the response! That overall makes a lot of sense. I'm actually not entirely sure what you mean by the "ol' classic bundling/unbundling pendulum problem" though; could you elaborate?

To describe this specific use case more: thanks for #106, you're right that that's definitely related! I actually don't care much about syntax highlighting, though. Currently our bespoke online editor for Penrose doesn't have very sophisticated syntax highlighting anyway. I could actually implement an Observable editor experience not much worse than (and in some ways better than) the Penrose of today by just using tagged template literals for our three DSLs.

What I really care about here is room to grow beyond textual input to construct diagrams. We already have a little bit of this in the Penrose IDE; for instance, if you open our Walk on Stars - Laplace Estimator diagram and navigate to the Style program, you can click on the color lightGray = #e5e5e5 to open a popup widget to choose a different color. (This color picker widget is built into Monaco, so it's just the same one available for CSS in VS Code.)

Even here, the user experience isn't amazing: you need to click "compile" again before you can see the new color in the actual diagram. Part of the issue is that liveness is in tension with Penrose's optimization approach, but that's not super relevant here; regardless, I really want to move toward creating a diagramming experience where the user can use other widgets like this to configure not just colors, but also other numbers (scalars and vectors) like you can in The Book of Shaders editor. I've already opened microsoft/vscode#175234 about an adjacent issue, because that color picker is hardcoded into Monaco: you can't build your own.

So, Observable's viewof combined with its liveness and reactivity make up almost all of the story here! If I'm OK with using JavaScript instead of the Penrose DSLs, right now I can make an Observable notebook where I use JavaScript to define a diagram, and if I refactor out all the scalars and vectors from my code into individual viewof cells, I can drag around sliders for those and see my diagram update in real time.

But I don't want to have to pull all my scalars and vectors and colors out into their own cells. I really want to be able to have popup widgets and other GUIs for rich editing of literals in context, without manual restructuring effort. And I don't think Observable should have to implement all that for me! As I linked above, people have already created text editor components that can be used inside Observable; I could fork one of those and implement hover widgets on top of it. But then the problem is, I'm no longer editing the notebook itself, so if I reload the page, or I want to share my diagram code with others, I have to carefully manually sync the code from the custom editor state into the builtin Observable text editor.

Naïvely, if I were to approach this, my first instinct would be to allow a cell type whose contents are just JSON, but with a visual widget like viewof that is allowed to set the value of that JSON. Then other cells could read that JSON value just like they read any other value. So, a persistent scalar could be a slider that sets the JSON value to just a number, and a persistent color picker could set it to an object like { "r": 1, "g": 1, "b": 1, "a": 1 }, and a persistent text editor for a custom DSL could set it to a string with the source code the user types, etc. JSON is trivially serializable, so it can just be stored in the notebook like any other code (and you could also let the user view it if you want). Is something like this feasible, or am I missing important challenges?

samestep commented 8 months ago

just JSON

or if the widget could actually create Observable JS code for the cell which would then be evaluated, that would be even better! (I don't know whether that introduces additional challenges, though.)

tomlarkworthy commented 7 months ago

have you seen https://observablehq.com/@tomlarkworthy/local-storage-view its how I add persistence to my widgets.

samestep commented 7 months ago

@tomlarkworthy yeah I linked that in my message above; it works for some use-cases but isn't great for sharing since it's not first-class editing of the notebook.