mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-28 06:15:59 +08:00
Show indicators of state on session sidebar (#657)
* Added range input (Slider)
* Added range input (Slider)
* Custom css to range input
* Formatting correction
* Defined min and max values of input range
* Revert "Defined min and max values of input range"
This reverts commit 815167ab0f.
* Added input select
* working with a options like list
* Formatting correction
* swapped li for inputs in input settings
* Removed unused attribute
* Final adjustments
* Improve users connected display
* Update lib/livebook_web/live/session_live.ex
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
* Update lib/livebook_web/live/session_live.ex
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
* Adjust elements
* Change favicon based on notebook status
* Format correction
* "operation" is unused
* Improvements for better functioning of icons
* Renamed icons files
* Update favicons
* Update changelog
* Show indicators of state on session sidebar
* Changes to status colors
* Improve spacing
* Scroll to cell on status click
* global_evaluation_status -> global_status
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
parent
e16c8a5dab
commit
421b1c69a1
3 changed files with 78 additions and 38 deletions
|
|
@ -72,7 +72,7 @@ const Session = {
|
||||||
|
|
||||||
// Set initial favicon based on the current status
|
// Set initial favicon based on the current status
|
||||||
|
|
||||||
setFavicon(faviconForEvaluationStatus(this.props.globalEvaluationStatus));
|
setFavicon(faviconForEvaluationStatus(this.props.globalStatus));
|
||||||
|
|
||||||
// Load initial data
|
// Load initial data
|
||||||
|
|
||||||
|
|
@ -104,6 +104,7 @@ const Session = {
|
||||||
|
|
||||||
getSectionsList().addEventListener("click", (event) => {
|
getSectionsList().addEventListener("click", (event) => {
|
||||||
handleSectionsListClick(this, event);
|
handleSectionsListClick(this, event);
|
||||||
|
handleCellIndicatorsClick(this, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
getClientsList().addEventListener("click", (event) => {
|
getClientsList().addEventListener("click", (event) => {
|
||||||
|
|
@ -212,10 +213,8 @@ const Session = {
|
||||||
const prevProps = this.props;
|
const prevProps = this.props;
|
||||||
this.props = getProps(this);
|
this.props = getProps(this);
|
||||||
|
|
||||||
if (
|
if (this.props.globalStatus !== prevProps.globalStatus) {
|
||||||
this.props.globalEvaluationStatus !== prevProps.globalEvaluationStatus
|
setFavicon(faviconForEvaluationStatus(this.props.globalStatus));
|
||||||
) {
|
|
||||||
setFavicon(faviconForEvaluationStatus(this.props.globalEvaluationStatus));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -237,11 +236,7 @@ function getProps(hook) {
|
||||||
"data-autofocus-cell-id",
|
"data-autofocus-cell-id",
|
||||||
null
|
null
|
||||||
),
|
),
|
||||||
globalEvaluationStatus: getAttributeOrDefault(
|
globalStatus: getAttributeOrDefault(hook.el, "data-global-status", null),
|
||||||
hook.el,
|
|
||||||
"data-global-evaluation-status",
|
|
||||||
null
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
id="session"
|
id="session"
|
||||||
data-element="session"
|
data-element="session"
|
||||||
phx-hook="Session"
|
phx-hook="Session"
|
||||||
data-global-evaluation-status={elem(@data_view.global_evaluation_status, 0)}
|
data-global-status={elem(@data_view.global_status, 0)}
|
||||||
data-autofocus-cell-id={@autofocus_cell_id}>
|
data-autofocus-cell-id={@autofocus_cell_id}>
|
||||||
<SidebarHelpers.sidebar>
|
<SidebarHelpers.sidebar>
|
||||||
<SidebarHelpers.logo_item socket={@socket} />
|
<SidebarHelpers.logo_item socket={@socket} />
|
||||||
|
|
@ -120,18 +120,23 @@ defmodule LivebookWeb.SessionLive do
|
||||||
</h3>
|
</h3>
|
||||||
<div class="flex flex-col mt-4 space-y-4">
|
<div class="flex flex-col mt-4 space-y-4">
|
||||||
<%= for section_item <- @data_view.sections_items do %>
|
<%= for section_item <- @data_view.sections_items do %>
|
||||||
<button class="flex items-center space-x-1 text-left text-gray-500 hover:text-gray-900"
|
<div class="flex items-center">
|
||||||
data-element="sections-list-item"
|
<button class="flex-grow flex items-center text-gray-500 hover:text-gray-900"
|
||||||
data-section-id={section_item.id}>
|
data-element="sections-list-item"
|
||||||
<span><%= section_item.name %></span>
|
data-section-id={section_item.id}>
|
||||||
<%= if section_item.parent do %>
|
<span class="flex items-center space-x-1">
|
||||||
<%# Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
<span><%= section_item.name %></span>
|
||||||
consequently we show the tooltip wrapped to a fixed number of characters %>
|
<%= if section_item.parent do %>
|
||||||
<span {branching_tooltip_attrs(section_item.name, section_item.parent.name)}>
|
<%# Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
||||||
<.remix_icon icon="git-branch-line" class="text-lg font-normal leading-none flip-horizontally" />
|
consequently we show the tooltip wrapped to a fixed number of characters %>
|
||||||
|
<span {branching_tooltip_attrs(section_item.name, section_item.parent.name)}>
|
||||||
|
<.remix_icon icon="git-branch-line" class="text-lg font-normal leading-none flip-horizontally" />
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
</span>
|
</span>
|
||||||
<% end %>
|
</button>
|
||||||
</button>
|
<.session_status status={elem(section_item.status, 0)} cell_id={elem(section_item.status, 1)} />
|
||||||
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<button class="inline-flex items-center justify-center p-8 py-1 mt-8 space-x-2 text-sm font-medium text-gray-500 border border-gray-400 border-dashed rounded-xl hover:bg-gray-100"
|
<button class="inline-flex items-center justify-center p-8 py-1 mt-8 space-x-2 text-sm font-medium text-gray-500 border border-gray-400 border-dashed rounded-xl hover:bg-gray-100"
|
||||||
|
|
@ -259,7 +264,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
dirty: @data_view.dirty,
|
dirty: @data_view.dirty,
|
||||||
autosave_interval_s: @data_view.autosave_interval_s,
|
autosave_interval_s: @data_view.autosave_interval_s,
|
||||||
runtime: @data_view.runtime,
|
runtime: @data_view.runtime,
|
||||||
global_evaluation_status: @data_view.global_evaluation_status %>
|
global_status: @data_view.global_status %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -350,6 +355,41 @@ defmodule LivebookWeb.SessionLive do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp session_status(%{status: :evaluating} = assigns) do
|
||||||
|
~H"""
|
||||||
|
<button data-element="focus-cell-button" data-target={@cell_id}>
|
||||||
|
<.status_indicator circle_class="bg-blue-500" animated_circle_class="bg-blue-400">
|
||||||
|
</.status_indicator>
|
||||||
|
</button>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp session_status(%{status: :stale} = assigns) do
|
||||||
|
~H"""
|
||||||
|
<button data-element="focus-cell-button" data-target={@cell_id}>
|
||||||
|
<.status_indicator circle_class="bg-yellow-200">
|
||||||
|
</.status_indicator>
|
||||||
|
</button>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp session_status(assigns), do: ~H""
|
||||||
|
|
||||||
|
defp status_indicator(assigns) do
|
||||||
|
assigns = assign_new(assigns, :animated_circle_class, fn -> nil end)
|
||||||
|
|
||||||
|
~H"""
|
||||||
|
<div class="flex items-center space-x-1">
|
||||||
|
<span class="flex relative h-3 w-3">
|
||||||
|
<%= if @animated_circle_class do %>
|
||||||
|
<span class={"#{@animated_circle_class} animate-ping absolute inline-flex h-3 w-3 rounded-full opacity-75"}></span>
|
||||||
|
<% end %>
|
||||||
|
<span class={"#{@circle_class} relative inline-flex rounded-full h-3 w-3"}></span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
defp settings_component_for(%Cell.Elixir{}),
|
defp settings_component_for(%Cell.Elixir{}),
|
||||||
do: LivebookWeb.SessionLive.ElixirCellSettingsComponent
|
do: LivebookWeb.SessionLive.ElixirCellSettingsComponent
|
||||||
|
|
||||||
|
|
@ -1134,14 +1174,15 @@ defmodule LivebookWeb.SessionLive do
|
||||||
autosave_interval_s: data.notebook.autosave_interval_s,
|
autosave_interval_s: data.notebook.autosave_interval_s,
|
||||||
dirty: data.dirty,
|
dirty: data.dirty,
|
||||||
runtime: data.runtime,
|
runtime: data.runtime,
|
||||||
global_evaluation_status: global_evaluation_status(data),
|
global_status: global_status(data),
|
||||||
notebook_name: data.notebook.name,
|
notebook_name: data.notebook.name,
|
||||||
sections_items:
|
sections_items:
|
||||||
for section <- data.notebook.sections do
|
for section <- data.notebook.sections do
|
||||||
%{
|
%{
|
||||||
id: section.id,
|
id: section.id,
|
||||||
name: section.name,
|
name: section.name,
|
||||||
parent: parent_section_view(section.parent_id, data)
|
parent: parent_section_view(section.parent_id, data),
|
||||||
|
status: cells_status(section.cells, data)
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
clients:
|
clients:
|
||||||
|
|
@ -1154,12 +1195,7 @@ defmodule LivebookWeb.SessionLive do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp global_evaluation_status(data) do
|
defp cells_status(cells, data) do
|
||||||
cells =
|
|
||||||
data.notebook
|
|
||||||
|> Notebook.elixir_cells_with_section()
|
|
||||||
|> Enum.map(fn {cell, _} -> cell end)
|
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
evaluating = Enum.find(cells, &evaluating?(&1, data)) ->
|
evaluating = Enum.find(cells, &evaluating?(&1, data)) ->
|
||||||
{:evaluating, evaluating.id}
|
{:evaluating, evaluating.id}
|
||||||
|
|
@ -1175,6 +1211,15 @@ defmodule LivebookWeb.SessionLive do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp global_status(data) do
|
||||||
|
cells =
|
||||||
|
data.notebook
|
||||||
|
|> Notebook.elixir_cells_with_section()
|
||||||
|
|> Enum.map(fn {cell, _} -> cell end)
|
||||||
|
|
||||||
|
cells_status(cells, data)
|
||||||
|
end
|
||||||
|
|
||||||
defp evaluating?(cell, data), do: data.cell_infos[cell.id].evaluation_status == :evaluating
|
defp evaluating?(cell, data), do: data.cell_infos[cell.id].evaluation_status == :evaluating
|
||||||
|
|
||||||
defp stale?(cell, data), do: data.cell_infos[cell.id].validity_status == :stale
|
defp stale?(cell, data), do: data.cell_infos[cell.id].validity_status == :stale
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,9 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= if @runtime do %>
|
<%= if @runtime do %>
|
||||||
<.global_evaluation_status
|
<.global_status
|
||||||
status={elem(@global_evaluation_status, 0)}
|
status={elem(@global_status, 0)}
|
||||||
cell_id={elem(@global_evaluation_status, 1)} />
|
cell_id={elem(@global_status, 1)} />
|
||||||
<% else %>
|
<% else %>
|
||||||
<span class="tooltip left" aria-label="Choose a runtime to run the notebook in">
|
<span class="tooltip left" aria-label="Choose a runtime to run the notebook in">
|
||||||
<%= live_patch to: Routes.session_path(@socket, :runtime_settings, @session_id),
|
<%= live_patch to: Routes.session_path(@socket, :runtime_settings, @session_id),
|
||||||
|
|
@ -62,7 +62,7 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp global_evaluation_status(%{status: :evaluating} = assigns) do
|
defp global_status(%{status: :evaluating} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<span class="tooltip left" aria-label="Go to evaluating cell">
|
<span class="tooltip left" aria-label="Go to evaluating cell">
|
||||||
<button class="border-blue-400 icon-button icon-outlined-button hover:bg-blue-50 focus:bg-blue-50"
|
<button class="border-blue-400 icon-button icon-outlined-button hover:bg-blue-50 focus:bg-blue-50"
|
||||||
|
|
@ -74,7 +74,7 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp global_evaluation_status(%{status: :evaluated} = assigns) do
|
defp global_status(%{status: :evaluated} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<span class="tooltip left" aria-label="Go to last evaluated cell">
|
<span class="tooltip left" aria-label="Go to last evaluated cell">
|
||||||
<button class="border-green-300 icon-button icon-outlined-button hover:bg-green-50 focus:bg-green-50"
|
<button class="border-green-300 icon-button icon-outlined-button hover:bg-green-50 focus:bg-green-50"
|
||||||
|
|
@ -86,7 +86,7 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp global_evaluation_status(%{status: :stale} = assigns) do
|
defp global_status(%{status: :stale} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<span class="tooltip left" aria-label="Go to first stale cell">
|
<span class="tooltip left" aria-label="Go to first stale cell">
|
||||||
<button class="border-yellow-200 icon-button icon-outlined-button hover:bg-yellow-50 focus:bg-yellow-50"
|
<button class="border-yellow-200 icon-button icon-outlined-button hover:bg-yellow-50 focus:bg-yellow-50"
|
||||||
|
|
@ -98,7 +98,7 @@ defmodule LivebookWeb.SessionLive.IndicatorsComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp global_evaluation_status(%{status: :fresh} = assigns) do
|
defp global_status(%{status: :fresh} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<span class="tooltip left" aria-label="Ready to evaluate">
|
<span class="tooltip left" aria-label="Ready to evaluate">
|
||||||
<button class="border-gray-200 cursor-default icon-button icon-outlined-button hover:bg-gray-100 focus:bg-gray-100">
|
<button class="border-gray-200 cursor-default icon-button icon-outlined-button hover:bg-gray-100 focus:bg-gray-100">
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue