Skip to content

Commit

Permalink
Device health liveview (#1484)
Browse files Browse the repository at this point in the history
* Add liveview with simple metrics graphs

* Add time frame options for metrics

* Add basic tests for health liveview
  • Loading branch information
elinol authored Sep 5, 2024
1 parent b5cc843 commit df29583
Show file tree
Hide file tree
Showing 15 changed files with 660 additions and 20 deletions.
20 changes: 11 additions & 9 deletions assets/css/_custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
margin-top: 0;
}

& > img {
&>img {
margin: auto;
opacity: .75;
}
Expand All @@ -76,6 +76,7 @@
margin-top: .5rem;
}
}

.options .dropdown-item {
color: var(--white-50);
transition: color 200ms ease;
Expand Down Expand Up @@ -114,7 +115,7 @@
display: none;
}

& + .dropdown-menu {
&+.dropdown-menu {
padding: 0;
border-radius: 4px;
background-color: var(--background);
Expand Down Expand Up @@ -230,7 +231,7 @@
grid-column-gap: 3rem;
grid-row-gap: 2rem;

& > div:first-child {
&>div:first-child {
grid-column: span 2;
}

Expand All @@ -257,16 +258,16 @@
}

html {
.btn-group > form:not(:first-child) .btn {
.btn-group>form:not(:first-child) .btn {
margin-left: -1px;
}

.btn-group > form:not(:last-child) .btn {
.btn-group>form:not(:last-child) .btn {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}

.btn-group > form:not(:first-child) .btn {
.btn-group>form:not(:first-child) .btn {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
Expand All @@ -285,7 +286,7 @@ html {
align-items: center;
margin-bottom: 1.5rem;

& + h1 {
&+h1 {
margin-top: -1.5rem;
}

Expand All @@ -296,7 +297,7 @@ html {
@media(max-width: 860px) {
margin-bottom: 1rem;

& + h1 {
&+h1 {
margin-top: 0;
}
}
Expand Down Expand Up @@ -337,9 +338,10 @@ html {

.device-header-group {
display: flex;

.btn {
margin-left: 1%;
height: fit-content;
min-width: min-content;
}
}
}
89 changes: 89 additions & 0 deletions assets/css/_metrics.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
.metrics-section {
background: var(--backgroundLight);
padding: 1.5rem;
border-radius: 4px;
margin-bottom: 2rem;
}


.metrics-active {
background-color: rgb(68, 66, 66);
}

.btn.btn-outline-light.metrics-active:hover {
background-color: rgb(68, 66, 66);
}

.metrics-btn-group .btn.btn-outline-light:focus {
box-shadow: none;
}

.metrics-text {
margin-top: 2rem;
margin-bottom: 2rem;
}


// Contex Plots

/* Styling for tick line */
.exc-tick {
stroke: rgb(236, 235, 235);
}

.exc-tick line {
stroke: rgb(236, 235, 235);
}

/* Styling for tick text */
.exc-tick text {
fill: rgb(236, 235, 235);
stroke: none;
}

/* Styling for axis line */
.exc-domain {
stroke: rgb(207, 207, 207);
}

/* Styling for grid line */
.exc-grid {
stroke: lightgrey;
}

/* Styling for outline of colours in legend */
.exc-legend {
stroke: black;
}

/* Styling for text of colours in legend */
.exc-legend text {
fill: grey;
font-size: 0.8rem;
stroke: none;
}

/* Styling for title & subtitle of any plot */
.exc-title {
fill: darkslategray;
font-size: 2.3rem;
stroke: none;
}

.exc-subtitle {
fill: darkgrey;
font-size: 1.0rem;
stroke: none;
}

/* Styling for label printed inside a bar on a barchart */
.exc-barlabel-in {
fill: white;
font-size: 0.7rem;
}

/* Styling for label printed outside of a bar (e.g. if bar is too small) */
.exc-barlabel-out {
fill: grey;
font-size: 0.7rem;
}
3 changes: 2 additions & 1 deletion assets/css/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ $fa-font-path: '~@fortawesome/fontawesome-free/webfonts';
@import 'modal';
@import 'import';
@import '~bootstrap/scss/bootstrap';
@import 'metrics';

html {
margin: 0;
Expand Down Expand Up @@ -237,4 +238,4 @@ html body {

.device-health .callout.danger {
color: orangered;
}
}
14 changes: 12 additions & 2 deletions lib/nerves_hub/devices.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1139,8 +1139,18 @@ defmodule NervesHub.Devices do
end
end

def get_all_health(device_id) do
from(DeviceHealth, where: [device_id: ^device_id])
def get_device_health(device_id) do
DeviceHealth
|> where(device_id: ^device_id)
|> order_by(asc: :inserted_at)
|> Repo.all()
end

def get_device_health(device_id, unit, amount) do
DeviceHealth
|> where(device_id: ^device_id)
|> where([d], d.inserted_at > ago(^amount, ^unit))
|> order_by(asc: :inserted_at)
|> Repo.all()
end

Expand Down
102 changes: 102 additions & 0 deletions lib/nerves_hub_web/components/device_health/health_header.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
defmodule NervesHubWeb.Components.HealthHeader do
use NervesHubWeb, :component

attr(:org, :any)
attr(:product, :any)
attr(:device, :any)
attr(:status, :any)
attr(:latest_health, :any)
attr(:health_check_timer, :any, default: nil)

def render(assigns) do
~H"""
<div class="action-row">
<div>
<h1 class="ff-m mt-2 mb-1">Device Health</h1>
<p class="help-text large">Device identifier: <%= @device.identifier %></p>
</div>
<div>
<button
class="btn btn-outline-light btn-action"
aria-label={if @health_check_timer, do: "Disable Auto Refresh", else: "Enable Auto Refresh"}
type="button"
phx-click="toggle-health-check-auto-refresh"
>
<span :if={@health_check_timer} class="action-text">Disable Auto Refresh</span>
<span :if={!@health_check_timer} class="action-text">Enable Auto Refresh</span>
</button>
</div>
</div>
<div class="device-meta-grid">
<div>
<div class="help-text">Status</div>
<p class="flex-row align-items-center tt-c">
<span><%= @status %></span>
<span class="ml-1">
<%= if @status in ["offline"] do %>
<img src="/images/icons/cross.svg" alt="offline" class="table-icon" />
<% else %>
<img src="/images/icons/check.svg" alt="online" class="table-icon" />
<% end %>
</span>
</p>
</div>
<div>
<div class="help-text mb-1 tooltip-label help-tooltip">
<span>Last connected</span>
<span class="tooltip-info"></span>
<span class="tooltip-text" id="connection-establisted-at-tooltip" phx-hook="LocalTime">
<%= @device.connection_established_at %>
</span>
</div>
<p>
<span :if={[email protected]_established_at}>Never</span>
<time
:if={@device.connection_established_at}
id="connection-establisted-at"
phx-hook="UpdatingTimeAgo"
datetime={String.replace(DateTime.to_string(DateTime.truncate(@device.connection_established_at, :second)), " ", "T")}
>
<%= Timex.from_now(@device.connection_established_at) %>
</time>
</p>
</div>
<div>
<div class="help-text mb-1 tooltip-label help-tooltip">
<span>Last reported</span>
<span :if={@latest_health} class="tooltip-info"></span>
<span :if={@latest_health} class="tooltip-text" id="last-reported-at-tooltip" phx-hook="LocalTime">
<%= @latest_health.inserted_at %>
</span>
</div>
<p>
<span :if={!@latest_health}>Never</span>
<time :if={@latest_health} id="last-reported-at" phx-hook="UpdatingTimeAgo" datetime={String.replace(DateTime.to_string(DateTime.truncate(@latest_health.inserted_at, :second)), " ", "T")}>
<%= Timex.from_now(@latest_health.inserted_at) %>
</time>
</p>
</div>
<div>
<div class="help-text mb-1">Version</div>
<%= if is_nil(@device.firmware_metadata) do %>
<p>Unknown</p>
<% else %>
<.link navigate={~p"/org/#{@org.name}/#{@product.name}/firmware/#{@device.firmware_metadata.uuid}"} class="badge ff-m mt-0">
<%= @device.firmware_metadata.version %> (<%= String.slice(@device.firmware_metadata.uuid, 0..7) %>)
</.link>
<% end %>
</div>
<div>
<div class="help-text mb-1">Platform</div>
<%= if is_nil(@device.firmware_metadata.platform) do %>
<p>Unknown</p>
<% else %>
<p class="badge ff-m mt-0">
<%= @device.firmware_metadata.platform %>
</p>
<% end %>
</div>
</div>
"""
end
end
22 changes: 22 additions & 0 deletions lib/nerves_hub_web/components/device_health/health_section.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule NervesHubWeb.Components.HealthSection do
use NervesHubWeb, :component

attr(:title, :string)
attr(:svg, :any)
attr(:memory_size, :any, default: nil)
attr(:memory_usage, :any, default: nil)

def render(assigns) do
~H"""
<div class="metrics-section">
<div class="help-text mb-1">
<%= @title %>
<div :if={@memory_size}>Currently using <%= @memory_usage %>% of <%= @memory_size %> MB.</div>
</div>
<div>
<%= @svg %>
</div>
</div>
"""
end
end
Loading

0 comments on commit df29583

Please sign in to comment.