defmodule ToweropsWeb.Layouts do
@moduledoc """
This module holds layouts and related functionality
used by your application.
"""
use ToweropsWeb, :html
alias ToweropsWeb.Components.ConsentPrompt
alias ToweropsWeb.Components.CookieConsent
alias ToweropsWeb.Helpers.StatusHelpers
alias ToweropsWeb.Live.Components.GlobalSearchComponent
alias ToweropsWeb.TimeHelpers
# Embed all files in layouts/* within this module.
# The default root.html.heex file contains the HTML
# skeleton of your application, namely HTML headers
# and other static content.
embed_templates "layouts/*"
@doc """
Renders your app layout.
This function is typically invoked from every template,
and it often contains your application menu, sidebar,
or similar.
## Examples
Content
"""
attr :flash, :map, required: true, doc: "the map of flash messages"
attr :current_scope, :map,
default: nil,
doc: "the current [scope](https://hexdocs.pm/phoenix/scopes.html)"
attr :timezone, :string, default: "UTC", doc: "the user's timezone"
attr :requires_cookie_consent, :boolean,
default: false,
doc: "whether to show the cookie consent banner"
slot :inner_block, required: true
def app(assigns) do
assigns = Map.put_new(assigns, :requires_cookie_consent, false)
~H"""
<.flash_group flash={@flash} />
"""
end
@doc """
Renders the authenticated app layout with navigation.
Use this for pages that require organization context.
## Examples
Content
"""
attr :flash, :map, required: true, doc: "the map of flash messages"
attr :current_scope, :map,
default: nil,
doc: "the current scope (contains user, organization, timezone, and impersonation state)"
attr :active_page, :string,
default: nil,
doc: "the currently active page (dashboard, sites, device, or alerts)"
attr :unresolved_alert_count, :integer,
default: 0,
doc: "number of unresolved alerts for the current organization"
slot :inner_block, required: true
def authenticated(assigns) do
assigns = Map.put_new(assigns, :requires_cookie_consent, false)
# Extract organization and timezone from scope for template convenience
current_organization = assigns[:current_scope] && assigns.current_scope.organization
timezone = (assigns[:current_scope] && assigns.current_scope.timezone) || "UTC"
# Get policies needing consent from assigns (set in CheckPolicyConsent plug)
policies_needing_consent = Map.get(assigns, :policies_needing_consent, [])
# Check if this is the help page for banner display
always_show_banner = if Map.get(assigns, :active_page) == "help", do: "true", else: "false"
assigns =
assigns
|> Map.put(:current_organization, current_organization)
|> Map.put(:timezone, timezone)
|> Map.put(:policies_needing_consent, policies_needing_consent)
|> Map.put(:always_show_banner, always_show_banner)
~H"""
<%= if @current_scope && @current_scope.impersonating? do %>
We'd love to hear your feedback, suggestions, or help you with any questions. Please email us at
hi@towerops.net
for support, feature requests, or just to say hello!
<.flash_group flash={@flash} />
"""
end
@doc """
Renders the application footer with copyright notice and deploy timestamp.
"""
attr :timezone, :string, default: "UTC"
def footer(assigns) do
build_time = Towerops.Application.build_timestamp()
timezone = Map.get(assigns, :timezone, "UTC")
assigns =
assigns
|> assign(:build_time, build_time)
|> assign(:time_ago, TimeHelpers.format_time_ago(build_time))
|> assign(:formatted_time, TimeHelpers.format_iso8601(build_time, timezone))
~H"""
"""
end
@doc """
Returns the page title with status emoji prepended based on organization health.
"""
def status_title(assigns) do
page_title = assigns[:page_title] || "TowerOps"
organization = get_in(assigns, [:current_scope, Access.key(:organization)])
if organization do
StatusHelpers.title_with_status(page_title, organization)
else
page_title
end
end
end