fix: device index uses device_role instead of nonexistent device_type, last_checked_at instead of last_seen_at; make TimescaleDB migrations conditional for dev/test

This commit is contained in:
Graham McIntire 2026-02-14 10:13:03 -06:00
parent 715a20dd09
commit c37ae76ceb
4 changed files with 41 additions and 9 deletions

View file

@ -418,9 +418,9 @@ defmodule ToweropsWeb.DeviceLive.Index do
end
defp device_row_title(device) do
{last_seen, _color} = last_seen_text(device.last_seen_at)
{last_seen, _color} = last_seen_text(device.last_checked_at)
snmp = if device.snmp_enabled, do: "SNMP: #{device.snmp_version || "v2c"}", else: "SNMP: off"
type_label = device.device_type |> to_string() |> String.capitalize()
type_label = (device.device_role || "unknown") |> to_string() |> String.capitalize()
"#{type_label} | Last Poll: #{last_seen} | #{snmp}"
end

View file

@ -392,7 +392,7 @@
title={health_dot_title(row.health)}
/>
<.icon
name={device_type_icon(row.device.device_type)}
name={device_type_icon(row.device.device_role)}
class="h-4 w-4 text-gray-400 dark:text-gray-500 flex-shrink-0"
/>
{row.device.name}
@ -444,7 +444,7 @@
if(@compact_mode, do: "py-1.5", else: "py-4")
]}
>
<% {text, color} = last_seen_text(row.device.last_seen_at) %>
<% {text, color} = last_seen_text(row.device.last_checked_at) %>
<span class={"text-xs font-medium #{color}"}>{text}</span>
</.link>
</td>

View file

@ -23,6 +23,23 @@ defmodule Towerops.Repo.Migrations.EnableTimescaledbOptimizations do
@disable_migration_lock true
def up do
# Skip TimescaleDB in test environment where it's not available
if timescaledb_available?() do
do_up()
else
# Log and skip - tables already exist from earlier migrations, just without hypertable optimization
repo().query!("SELECT 1")
end
end
defp timescaledb_available? do
case repo().query("SELECT 1 FROM pg_available_extensions WHERE name = 'timescaledb'") do
{:ok, %{num_rows: n}} when n > 0 -> true
_ -> false
end
end
defp do_up do
# Step 1: Enable TimescaleDB extension
execute("CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE")
@ -333,6 +350,12 @@ defmodule Towerops.Repo.Migrations.EnableTimescaledbOptimizations do
end
def down do
if timescaledb_available?() do
do_down()
end
end
defp do_down do
# Remove refresh policies
execute(
"SELECT remove_continuous_aggregate_policy('monitoring_checks_hourly', if_exists => true)"

View file

@ -24,17 +24,26 @@ defmodule Towerops.Repo.Migrations.AddCheckResultsHypertable do
"ALTER TABLE check_results DROP CONSTRAINT check_results_pkey"
)
# Convert to TimescaleDB hypertable
execute(
"SELECT create_hypertable('check_results', 'checked_at')",
"DROP TABLE check_results"
)
# Convert to TimescaleDB hypertable (skip if not available, e.g. in test/dev without TimescaleDB)
if timescaledb_available?() do
execute(
"SELECT create_hypertable('check_results', 'checked_at')",
"DROP TABLE check_results"
)
end
create index(:check_results, [:check_id, :checked_at])
create index(:check_results, [:organization_id, :status])
create index(:check_results, [:organization_id, :checked_at])
end
defp timescaledb_available? do
case repo().query("SELECT 1 FROM pg_available_extensions WHERE name = 'timescaledb'") do
{:ok, %{num_rows: n}} when n > 0 -> true
_ -> false
end
end
def down do
drop table(:check_results)
end