diff --git a/lib/towerops/workers/firmware_version_fetcher_worker.ex b/lib/towerops/workers/firmware_version_fetcher_worker.ex index 52a0e9b1..b54cc084 100644 --- a/lib/towerops/workers/firmware_version_fetcher_worker.ex +++ b/lib/towerops/workers/firmware_version_fetcher_worker.ex @@ -84,6 +84,10 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorker do if version == "" or is_nil(version) do {:error, :invalid_data} else + # Extract clean version number from RSS title + # "RouterOS 7.21.2 [stable]" -> "7.21.2" + clean_version = extract_version_number(version) + # Parse RFC822 date release_date = parse_rfc822_date(pub_date_string) @@ -91,14 +95,15 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorker do %{ vendor: "mikrotik", product_line: "routeros", - version: version, + version: clean_version, release_date: release_date, download_url: download_url, changelog_url: @changelog_url, fetched_at: DateTime.utc_now(), metadata: %{ "rss_title" => channel_title, - "rss_description" => description + "rss_description" => description, + "raw_version" => version } }} end @@ -111,6 +116,20 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorker do {:error, :parse_error} end + # Extract clean version number from RSS title + # Examples: + # "RouterOS 7.21.2 [stable]" -> "7.21.2" + # "7.14.1" -> "7.14.1" + defp extract_version_number(version_string) do + # Match pattern: one or more digits, followed by dot, followed by digits + # This extracts semantic version numbers like "7.21.2" + case Regex.run(~r/\d+\.\d+(?:\.\d+)?/, version_string) do + [version] -> version + # Fallback to original if no match + _ -> version_string + end + end + # Parse RFC822 date format used in RSS feeds # Example: "Wed, 15 Jan 2025 12:00:00 +0000" defp parse_rfc822_date(date_string) when is_binary(date_string) and date_string != "" do diff --git a/lib/towerops_web/live/device_live/show.ex b/lib/towerops_web/live/device_live/show.ex index 84f53192..e8537e94 100644 --- a/lib/towerops_web/live/device_live/show.ex +++ b/lib/towerops_web/live/device_live/show.ex @@ -286,12 +286,27 @@ defmodule ToweropsWeb.DeviceLive.Show do end end - defp determine_vendor("MikroTik"), do: "mikrotik" - defp determine_vendor("Cisco"), do: "cisco" - defp determine_vendor("Ubiquiti"), do: "ubiquiti" + defp determine_vendor(manufacturer) when is_binary(manufacturer) do + manufacturer_lower = String.downcase(manufacturer) + + cond do + String.contains?(manufacturer_lower, "mikrotik") -> "mikrotik" + String.contains?(manufacturer_lower, "cisco") -> "cisco" + String.contains?(manufacturer_lower, "ubiquiti") -> "ubiquiti" + true -> nil + end + end + defp determine_vendor(_), do: nil - defp determine_product_line("MikroTik"), do: "routeros" + defp determine_product_line(manufacturer) when is_binary(manufacturer) do + manufacturer_lower = String.downcase(manufacturer) + + if String.contains?(manufacturer_lower, "mikrotik") do + "routeros" + end + end + defp determine_product_line(_), do: nil defp firmware_update_available?(nil, _), do: false @@ -301,7 +316,29 @@ defmodule ToweropsWeb.DeviceLive.Show do current = snmp_device.firmware_version available = available_firmware.version - current && available && VersionComparator.newer?(current, available) + # Extract clean version numbers for comparison + # "RouterOS 7.20.6 (Level 6)" -> "7.20.6" + # "7.21.2" -> "7.21.2" + current_clean = extract_version_number(current) + available_clean = extract_version_number(available) + + current_clean && available_clean && VersionComparator.newer?(current_clean, available_clean) + end + + # Extract semantic version number from version string + # Examples: + # "RouterOS 7.20.6 (Level 6)" -> "7.20.6" + # "7.21.2" -> "7.21.2" + # "v7.14.1" -> "7.14.1" + defp extract_version_number(nil), do: nil + defp extract_version_number(""), do: nil + + defp extract_version_number(version_string) when is_binary(version_string) do + # Match semantic version pattern: X.Y or X.Y.Z + case Regex.run(~r/\d+\.\d+(?:\.\d+)?/, version_string) do + [version] -> version + _ -> nil + end end defp format_date(nil), do: "" diff --git a/lib/towerops_web/live/device_live/show.html.heex b/lib/towerops_web/live/device_live/show.html.heex index 6b20a4eb..00972421 100644 --- a/lib/towerops_web/live/device_live/show.html.heex +++ b/lib/towerops_web/live/device_live/show.html.heex @@ -205,57 +205,6 @@
<%= case @active_tab do %> <% "overview" -> %> - - <%= if firmware_update_available?(@snmp_device, @available_firmware) do %> -
-
-
- <.icon name="hero-arrow-up-circle" class="h-5 w-5 text-blue-400" /> -
-
-

- Firmware Update Available -

-
-

- Current version: - {@snmp_device.firmware_version} -
Latest version: - {@available_firmware.version} - <%= if @available_firmware.release_date do %> - - (released {format_date(@available_firmware.release_date)}) - - <% end %> -

-
- -
-
-
- <% end %> -
@@ -293,16 +242,83 @@
Operating System
- {cond do - @snmp_device.manufacturer && @snmp_device.firmware_version -> - "#{@snmp_device.manufacturer} #{@snmp_device.firmware_version}" +
+ + {cond do + @snmp_device.manufacturer && @snmp_device.firmware_version -> + "#{@snmp_device.manufacturer} #{@snmp_device.firmware_version}" - @snmp_device.manufacturer -> - @snmp_device.manufacturer + @snmp_device.manufacturer -> + @snmp_device.manufacturer - true -> - @snmp_device.sys_descr || "N/A" - end} + true -> + @snmp_device.sys_descr || "N/A" + end} + + <%= if firmware_update_available?(@snmp_device, @available_firmware) do %> +
+ <.icon + name="hero-arrow-up-circle" + class="h-5 w-5 text-blue-500 cursor-help dark:text-blue-400" + /> + +
+ + +
+ <% end %> +
@@ -790,7 +806,7 @@
- <%= if sensor.latest_reading do %> + <%= if sensor.latest_reading && sensor.latest_reading.value do %> {trunc(sensor.latest_reading.value)} <%= if sensor.sensor_unit && sensor.sensor_unit != "" do %> {sensor.sensor_unit} @@ -826,7 +842,7 @@
- <%= if sensor.latest_reading do %> + <%= if sensor.latest_reading && sensor.latest_reading.value do %> <%= if sensor.sensor_type in ["clients", "ccq", "utilization"] do %> {trunc(sensor.latest_reading.value)} <% else %>