diff --git a/lib/towerops_web/live/device_live/index.ex b/lib/towerops_web/live/device_live/index.ex index 25af6a28..d367940b 100644 --- a/lib/towerops_web/live/device_live/index.ex +++ b/lib/towerops_web/live/device_live/index.ex @@ -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 diff --git a/lib/towerops_web/live/device_live/index.html.heex b/lib/towerops_web/live/device_live/index.html.heex index afce062d..bd23ddbc 100644 --- a/lib/towerops_web/live/device_live/index.html.heex +++ b/lib/towerops_web/live/device_live/index.html.heex @@ -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) %> {text} diff --git a/priv/repo/migrations/20260122191230_enable_timescaledb_optimizations.exs b/priv/repo/migrations/20260122191230_enable_timescaledb_optimizations.exs index a1fa1bcd..26e7551a 100644 --- a/priv/repo/migrations/20260122191230_enable_timescaledb_optimizations.exs +++ b/priv/repo/migrations/20260122191230_enable_timescaledb_optimizations.exs @@ -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)" diff --git a/priv/repo/migrations/20260212185433_add_check_results_hypertable.exs b/priv/repo/migrations/20260212185433_add_check_results_hypertable.exs index f3494fc1..054df19a 100644 --- a/priv/repo/migrations/20260212185433_add_check_results_hypertable.exs +++ b/priv/repo/migrations/20260212185433_add_check_results_hypertable.exs @@ -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