kino
kino copied to clipboard
[Feature Request] Stream of custom events
:wave: Hi!
I believe this would be a feature request, and I'm unclear whether issue tracker is the correct place to raise this?
Context
Let's say we've 2-3 heavy DB queries and I want to create a report that's available as app. Ideally, automatically refetch the data at some interval or when user clicks a button.
In edit mode, I can select most of the cells as "evaluate automatically" and it's works nicely, but it doesn't work for apps.
Actual solution as workaround
At this moment, I get around this by creating "UI" module that's appending data info in a single frame, but this mode of writing a notebook that also works as an app leaves a lot to be desired. This is also very difficult to explain to people that are just starting with Elixir and want to publish their notebook as an app.
Example:
# one cell, it might also be a more complex form, other type of user input
load_btn = Kino.Control.button("Load data") |> Kino.render()
# another cell
frame = Kino.Frame.new() |> Kino.render()
defmodule UI do
def show(frame) do
# very heavy db query
results = [1, 2, 3]
Kino.Frame.render(
frame, Kino.Markdown.new("#{Enum.join(results, ", ")} #{DateTime.utc_now()}")
)
end
end
load_btn
|> Kino.listen(fn _event ->
UI.show(frame)
end)
UI.show(frame)
Kino.nothing()
## another cell !
# another cell, wants to access "results" too!
# another cell, it must be reloaded "load_btn" is clicked!
defmodule AnotherUI do
def show(frame, results) do
Kino.Frame.render(
frame, Kino.Markdown.new("Different view #{Enum.join(results, ", ")} #{DateTime.utc_now()}")
)
end
end
another_frame = Kino.Frame.new() |> Kino.render()
load_btn
|> Kino.listen(fn _event ->
# no way to get "results"?
AnotherUI.show(another_frame, [4, 5, 6])
end)
AnotherUI.show(another_frame, [4, 5, 6])
Kino.nothing()
Expected solution
Kino already has API for streams via Kino.Control.stream/1. I would love to simplify the code above to something like:
load_btn = Kino.Control.button("Load data") |> Kino.render()
event = Kino.Control.event(:results)
load_btn
|> Kino.listen(fn _event ->
# very heavy db query
results = [1, 2, 3]
Kino.send(event, data: [results: results])
end)
# another cell
event
# or [event, ...other events] |> Kino.Control.stream()
|> Kino.animate(fn event ->
Kino.Markdown.new("Some view #{Enum.join(event.data.results, ", ")} #{DateTime.utc_now()}")
end)
## another cell !
event
|> Kino.animate(fn event ->
Kino.Markdown.new("Different view #{Enum.join(event.data.results, ", ")} #{DateTime.utc_now()}")
end)
It's also very likely that I'm doing something wrong and this is already possible but given the validation here I don't think it's easy to do nor obvious from the documentation.