improve agent status display and fix two pre-existing test failures (#83)

- Wrap agent name + icon inside the offline amber badge so it's clear
  what is offline on the device detail page
- Add "Agent:" label before the agent indicator for all states
- Fix TimeSeriesTest deadlock: switch to async: false since check_results
  is a TimescaleDB hypertable and concurrent chunk creation deadlocks
- Fix unicode property test: String.length/1 counts grapheme clusters,
  not code points; combining chars can make a 2-codepoint string have
  only 1 grapheme, legitimately failing the min: 2 validation

Reviewed-on: graham/towerops-web#83
This commit is contained in:
Graham McIntire 2026-03-19 11:43:42 -05:00 committed by graham
parent 36cb080823
commit c18f034997
3 changed files with 35 additions and 24 deletions

View file

@ -67,29 +67,36 @@
/>
</span>
<span class="text-gray-300 dark:text-gray-600">·</span>
<%= if @agent_info.type == :cloud do %>
<span class="inline-flex items-center gap-1 text-blue-600 dark:text-blue-400">
<.icon name="hero-cloud" class="h-3 w-3" />
<%= if @agent_info.agent_token_id do %>
{t("Cloud")} ({@agent_info.name})
<% else %>
{t("Cloud")}
<% end %>
<span class="inline-flex items-center gap-1.5">
<span class="text-xs text-gray-400 dark:text-gray-500 font-medium">
{t("Agent:")}
</span>
<% else %>
<span class="inline-flex items-center gap-1 text-green-600 dark:text-green-400">
<.icon name="hero-server" class="h-3 w-3" />
{@agent_info.name}
</span>
<%= if @agent_info.is_offline do %>
<span
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-medium text-amber-700 bg-amber-100 dark:text-amber-400 dark:bg-amber-900/30 rounded"
title="Agent has not checked in for over 5 minutes."
>
<.icon name="hero-exclamation-triangle" class="h-3 w-3" /> Offline
<%= if @agent_info.type == :cloud do %>
<span class="inline-flex items-center gap-1 text-blue-600 dark:text-blue-400">
<.icon name="hero-cloud" class="h-3 w-3" />
<%= if @agent_info.agent_token_id do %>
{t("Cloud")} ({@agent_info.name})
<% else %>
{t("Cloud")}
<% end %>
</span>
<% else %>
<%= if @agent_info.is_offline do %>
<span
class="inline-flex items-center gap-1 px-1.5 py-0.5 font-medium text-amber-700 bg-amber-100 dark:text-amber-400 dark:bg-amber-900/30 rounded"
title="Agent has not checked in for over 5 minutes."
>
<.icon name="hero-exclamation-triangle" class="h-3 w-3" />
{@agent_info.name} · Offline
</span>
<% else %>
<span class="inline-flex items-center gap-1 text-green-600 dark:text-green-400">
<.icon name="hero-server" class="h-3 w-3" />
{@agent_info.name}
</span>
<% end %>
<% end %>
<% end %>
</span>
</div>
</div>
<div class="shrink-0 mt-0.5">

View file

@ -1,5 +1,5 @@
defmodule ToweropsWeb.GraphQL.Resolvers.TimeSeriesTest do
use ToweropsWeb.ConnCase, async: true
use ToweropsWeb.ConnCase, async: false
import Towerops.AccountsFixtures
import Towerops.DevicesFixtures

View file

@ -218,9 +218,13 @@ defmodule ToweropsWeb.Org.SettingsLiveTest do
property "unicode names within length bounds are accepted", %{organization: org} do
check all(name <- string(:printable, min_length: 2, max_length: 100), max_runs: 50) do
changeset = Organizations.change_organization(org, %{name: name})
# Should not have a name error (length is valid)
refute Keyword.has_key?(changeset.errors, :name)
# String.length/1 counts grapheme clusters, which may be fewer than code points
# when combining characters are present (e.g. a base char + combining mark = 1 grapheme).
# Only assert when the grapheme count satisfies the validation bounds.
if String.length(name) >= 2 and String.length(name) <= 100 do
changeset = Organizations.change_organization(org, %{name: name})
refute Keyword.has_key?(changeset.errors, :name)
end
end
end
end