From 8415ba311e2978720be0443269d7a549f62da1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonatan=20K=C5=82osko?= Date: Sun, 20 Jun 2021 17:06:30 +0200 Subject: [PATCH] Show ticking timer while cell is evaluating (#374) --- assets/js/app.js | 2 ++ assets/js/timer/index.js | 31 +++++++++++++++++++ .../live/session_live/cell_component.ex | 18 ++++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 assets/js/timer/index.js diff --git a/assets/js/app.js b/assets/js/app.js index 0aaf84e34..072b37a5f 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -20,6 +20,7 @@ import VirtualizedLines from "./virtualized_lines"; import Menu from "./menu"; import UserForm from "./user_form"; import VegaLite from "./vega_lite"; +import Timer from "./timer"; import morphdomCallbacks from "./morphdom_callbacks"; import { loadUserData } from "./lib/user"; @@ -33,6 +34,7 @@ const hooks = { Menu, UserForm, VegaLite, + Timer, }; const csrfToken = document diff --git a/assets/js/timer/index.js b/assets/js/timer/index.js new file mode 100644 index 000000000..f3de09927 --- /dev/null +++ b/assets/js/timer/index.js @@ -0,0 +1,31 @@ +const UPDATE_INTERVAL_MS = 100; + +/** + * A hook used to display a timer counting from the moment + * of mounting. + */ +const Timer = { + mounted() { + this.state = { + start: Date.now(), + interval: null, + }; + + this.state.interval = setInterval(() => { + this.__tick(); + }, UPDATE_INTERVAL_MS); + }, + + destroyed() { + clearInterval(this.state.interval); + }, + + __tick() { + const elapsedMs = Date.now() - this.state.start; + const elapsedSeconds = elapsedMs / 1_000; + + this.el.innerHTML = `${elapsedSeconds.toFixed(1)}s`; + }, +}; + +export default Timer; diff --git a/lib/livebook_web/live/session_live/cell_component.ex b/lib/livebook_web/live/session_live/cell_component.ex index 454226688..8edfb8eef 100644 --- a/lib/livebook_web/live/session_live/cell_component.ex +++ b/lib/livebook_web/live/session_live/cell_component.ex @@ -353,7 +353,15 @@ defmodule LivebookWeb.SessionLive.CellComponent do defp render_cell_status(cell_view, evaluation_status, evaluation_time_ms) defp render_cell_status(_, :evaluating, _) do - render_status_indicator("Evaluating", "bg-blue-500", + timer = + content_tag(:span, nil, + phx_hook: "Timer", + id: "evaluating-cell-timer", + phx_update: "ignore", + class: "font-mono" + ) + + render_status_indicator(timer, "bg-blue-500", animated_circle_class: "bg-blue-400", change_indicator: true ) @@ -380,9 +388,9 @@ defmodule LivebookWeb.SessionLive.CellComponent do defp render_cell_status(_, _, _), do: nil - defp render_status_indicator(text, circle_class, opts \\ []) do + defp render_status_indicator(element, circle_class, opts \\ []) do assigns = %{ - text: text, + element: element, circle_class: circle_class, animated_circle_class: Keyword.get(opts, :animated_circle_class), change_indicator: Keyword.get(opts, :change_indicator, false), @@ -392,8 +400,8 @@ defmodule LivebookWeb.SessionLive.CellComponent do ~L"""
bottom distant-medium" aria-label="<%= @tooltip %>">
-
- <%= @text %> +
+ <%= @element %> <%= if @change_indicator do %> * <% end %>