diff --git a/lib/towerops_web/live/site_live/show.ex b/lib/towerops_web/live/site_live/show.ex index c5d8b0a9..aefcefcb 100644 --- a/lib/towerops_web/live/site_live/show.ex +++ b/lib/towerops_web/live/site_live/show.ex @@ -180,9 +180,12 @@ defmodule ToweropsWeb.SiteLive.Show do defp change_size_label(size) when size < 500, do: "Medium" defp change_size_label(_), do: "Large" - defp change_size_color(size) when size < 100, do: "badge-ghost" - defp change_size_color(size) when size < 500, do: "badge-warning" - defp change_size_color(_), do: "badge-error" + defp change_size_color(size) when size < 100, do: "bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300" + + defp change_size_color(size) when size < 500, + do: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400" + + defp change_size_color(_), do: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400" defp insight_urgency_class("critical"), do: "text-red-600 dark:text-red-400" defp insight_urgency_class("warning"), do: "text-yellow-600 dark:text-yellow-400" diff --git a/lib/towerops_web/live/site_live/show.html.heex b/lib/towerops_web/live/site_live/show.html.heex index fd237121..1c7c1b05 100644 --- a/lib/towerops_web/live/site_live/show.html.heex +++ b/lib/towerops_web/live/site_live/show.html.heex @@ -35,77 +35,93 @@ <% end %> - <.header> - {@page_title} - <:subtitle>{@site.location} - <:actions> - <%= if @device != [] do %> - <.button - type="button" - phx-click="force_rediscover_all" - data-confirm={ - t("This will trigger SNMP discovery for all devices at this site. Continue?") - } - > - <.icon name="hero-magnifying-glass" class="h-4 w-4" /> Force Rediscover All - - <% end %> - <.button navigate={~p"/sites/#{@site.id}/edit"}> - <.icon name="hero-pencil" class="h-4 w-4" /> Edit + <%= if @device != [] do %> +
+ <.button + type="button" + phx-click="force_rediscover_all" + class="btn-sm" + data-confirm={ + t("This will trigger SNMP discovery for all devices at this site. Continue?") + } + > + <.icon name="hero-magnifying-glass" class="h-4 w-4" /> {t("Force Rediscover All")} - - +
+ <% end %> + + <%!-- Quick Actions --%> +
+ <.button navigate={~p"/devices/new?site_id=#{@site.id}"} variant="primary" class="btn-sm"> + <.icon name="hero-plus" class="h-4 w-4" /> {t("Add Device")} + + <%= if @site.latitude && @site.longitude do %> + <.button + navigate={~p"/sites-map?lat=#{@site.latitude}&lng=#{@site.longitude}&zoom=15"} + class="btn-sm" + > + <.icon name="hero-map" class="h-4 w-4" /> {t("View on Map")} + + <% end %> + <.button navigate={~p"/sites/#{@site.id}/edit"} class="btn-sm"> + <.icon name="hero-pencil" class="h-4 w-4" /> {t("Edit Site")} + +
<%!-- Summary Stat Cards --%>
<%!-- Subscribers --%> -
-
-
- <.icon name="hero-users" class="h-4 w-4" /> Subscribers -
-

- {format_number(@site_summary.subscribers || 0)} -

+
+
+ <.icon name="hero-users" class="h-4 w-4" /> {t("Subscribers")}
+

+ {format_number(@site_summary.subscribers || 0)} +

<%!-- MRR --%> -
-
-
- <.icon name="hero-currency-dollar" class="h-4 w-4" /> Monthly Revenue -
-

- {format_mrr(@site_summary.mrr)} -

+
+
+ <.icon name="hero-currency-dollar" class="h-4 w-4" /> {t("Monthly Revenue")}
+

+ {format_mrr(@site_summary.mrr)} +

<%!-- Device Count --%> -
-
-
- <.icon name="hero-server" class="h-4 w-4" /> Devices -
-

- {format_number(@site_summary.device_count)} - <%= if @site_summary.devices_down > 0 do %> - - ({@site_summary.devices_down} down) - - <% end %> -

+
+
+ <.icon name="hero-server" class="h-4 w-4" /> {t("Devices")}
+

+ {format_number(@site_summary.device_count)} + <%= if @site_summary.devices_down > 0 do %> + + ({@site_summary.devices_down} {t("down")}) + + <% end %> +

<%!-- Active Alerts --%> -
-
-
- <.icon name="hero-bell-alert" class="h-4 w-4" /> Active Alerts -
-

- {length(@active_alerts)} -

+
0, + do: "border-red-200 dark:border-red-900/50", + else: "border-gray-200 dark:border-white/10" + ) + ]}> +
+ <.icon name="hero-bell-alert" class="h-4 w-4" /> {t("Active Alerts")}
+

0, + do: "text-red-600 dark:text-red-400", + else: "text-gray-900 dark:text-white" + ) + ]}> + {length(@active_alerts)} +

@@ -145,9 +161,11 @@ <%!-- Left Column --%>
<%!-- Site Details --%> -
-
-

{t("Site Details")}

+
+
+

+ {t("Site Details")} +

<%= if @site.parent_site do %>
@@ -193,12 +211,14 @@
<%!-- Active Alerts Panel --%> -
-
-

+
+
+

<.icon name="hero-bell-alert" class="h-5 w-5" /> Active Alerts <%= if @active_alerts != [] do %> - {length(@active_alerts)} + + {length(@active_alerts)} + <% end %>

<%= if @active_alerts == [] do %> @@ -210,7 +230,7 @@
<.icon name={insight_urgency_icon(alert_severity(alert.alert_type))} @@ -232,9 +252,9 @@
<%!-- Recent Config Changes Panel --%> -
-
-

+
+
+

<.icon name="hero-document-text" class="h-5 w-5" /> Recent Config Changes

<%= if @config_changes == [] do %> @@ -245,7 +265,7 @@

@@ -268,10 +288,10 @@ <%!-- Right Column --%>

<%!-- Device Health Grid --%> -
-
+
+
-

+

<.icon name="hero-server" class="h-5 w-5" /> Device Health

<.button @@ -283,7 +303,7 @@
<%= if @device == [] do %> -
+
<.icon name="hero-server" class="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" @@ -301,23 +321,49 @@
<% else %> -
- <.link - :for={eq <- @device} - navigate={~p"/devices/#{eq.id}"} - class="flex items-center gap-3 rounded-lg border border-base-300 p-3 hover:bg-base-200 transition-colors cursor-pointer" - > - -
-

- {eq.name} -

-

{eq.ip_address}

-
- - {format_response_time(@response_times[eq.id])} - - +
+ + + + + + + + + + + + + + + +
{t("Device")}{t("IP Address")}{t("Latency")}
+
+ + + {eq.name} + +
+
+ {eq.ip_address} + "text-gray-400" + ms when ms < 50 -> "text-green-600 dark:text-green-400" + ms when ms < 200 -> "text-yellow-600 dark:text-yellow-400" + _ -> "text-red-600 dark:text-red-400" + end + ]}> + {format_response_time(@response_times[eq.id])} +
<% end %>
@@ -325,15 +371,15 @@ <%!-- Insights Panel --%> <%= if @insights != [] do %> -
-
-

+
+
+

<.icon name="hero-light-bulb" class="h-5 w-5" /> Preseem Insights

<.icon name={insight_urgency_icon(insight.urgency)} @@ -358,22 +404,30 @@ <%!-- Latency Chart --%> <%= if @latency_chart_data do %>
-
-
-

- <.icon name="hero-chart-bar" class="h-5 w-5" /> Site Latency — Last 24 Hours +
+
+

+ <.icon name="hero-chart-bar" class="h-4 w-4" /> {t("Site Latency — Last 24 Hours")}

-
-
- +
+
+
+
+
+
+
+ {t("Loading chart...")} +
+
diff --git a/lib/towerops_web/live/user_settings_live.html.heex b/lib/towerops_web/live/user_settings_live.html.heex index 201c5f4c..167d9ee3 100644 --- a/lib/towerops_web/live/user_settings_live.html.heex +++ b/lib/towerops_web/live/user_settings_live.html.heex @@ -11,95 +11,108 @@

-
- -
+
@@ -777,27 +790,38 @@ <%= for session <- @browser_sessions do %> <% is_current = current_session?(session, get_current_token_id(assigns)) %>
  • -
    -
    -

    - {format_browser_info(session)} -

    - <%= if is_current do %> - - {t("Current Session")} - +
    +
    + <%= if String.contains?(String.downcase(session.user_agent || ""), ["mobile", "android", "iphone", "ipad"]) do %> + <.icon name="hero-device-phone-mobile" class="h-6 w-6 text-gray-400" /> + <% else %> + <.icon name="hero-computer-desktop" class="h-6 w-6 text-gray-400" /> <% end %>
    -
    -
    - <.icon name="hero-map-pin" class="h-3 w-3" /> - {format_location(session)} - - {session.ip_address} +
    +
    +

    + {format_browser_info(session)} +

    + <%= if is_current do %> + + {t("Current Session")} + + <% end %>
    -
    - <.icon name="hero-clock" class="h-3 w-3" /> - Last active {format_relative_time(session.last_activity_at)} +
    +
    + <.icon name="hero-map-pin" class="h-3 w-3" /> + {format_location(session)} + + {session.ip_address} +
    +
    + <.icon name="hero-clock" class="h-3 w-3" /> + + Last active {format_relative_time(session.last_activity_at)} + +
    @@ -1572,12 +1596,35 @@ > {t("Scan QR Code")}
  • -
    -

    - {t( - "Scan this QR code with your authenticator app (Google Authenticator, Authy, 1Password, etc.)." - )} -

    +
    +
    +
    + + 1 + +

    + {t( + "Install an authenticator app (Google Authenticator, Authy, 1Password, etc.)" + )} +

    +
    +
    + + 2 + +

    + {t("Scan the QR code below with your authenticator app")} +

    +
    +
    + + 3 + +

    + {t("Enter the 6-digit code from your app to verify setup")} +

    +
    +