defmodule PlausibleWeb.LayoutView do use PlausibleWeb, :view use Plausible alias Plausible.Teams alias PlausibleWeb.Components.Billing.Notice alias PlausibleWeb.Components.Layout require Plausible.Billing def plausible_url do PlausibleWeb.Endpoint.url() end def websocket_url() do PlausibleWeb.Endpoint.websocket_url() end defmodule JWT do use Joken.Config end def feedback_link(user) do token_params = %{ "id" => user.id, "email" => user.email, "name" => user.name, "imageUrl" => Plausible.Auth.User.profile_img_url(user) } case JWT.generate_and_sign(token_params) do {:ok, token, _claims} -> "https://feedback.plausible.io/sso/#{token}?returnUrl=https://feedback.plausible.io" _ -> "https://feedback.plausible.io" end end def home_dest(conn) do if conn.assigns[:current_user] do "/sites" else "/" end end def logo_path(filename) do if ee?() do Path.join("/images/ee/", filename) else Path.join("/images/ce/", filename) end end def site_settings_sidebar(conn) do regular_site? = Plausible.Sites.regular?(conn.assigns.site) [ %{key: "General", value: "general", icon: :rocket_launch}, if regular_site? do %{key: "People", value: "people", icon: :users} end, if regular_site? do %{key: "Visibility", value: "visibility", icon: :eye} end, %{key: "Goals", value: "goals", icon: :check_circle}, on_ee do if regular_site? do %{key: "Funnels", value: "funnels", icon: :funnel} end end, %{key: "Custom properties", value: "properties", icon: :tag}, if regular_site? do %{key: "Integrations", value: "integrations", icon: :puzzle_piece} end, if regular_site? do %{key: "Imports & exports", value: "imports-exports", icon: :arrow_down_tray} end, if regular_site? do %{ key: "Shields", icon: :shield_exclamation, value: [ %{key: "IP addresses", value: "shields/ip_addresses"}, %{key: "Countries", value: "shields/countries"}, %{key: "Pages", value: "shields/pages"}, %{key: "Hostnames", value: "shields/hostnames"} ] } end, %{key: "Email reports", value: "email-reports", icon: :envelope}, if regular_site? and conn.assigns[:site_role] in [:owner, :admin] do %{key: "Danger zone", value: "danger-zone", icon: :exclamation_triangle} end ] |> Enum.reject(&is_nil/1) end def account_settings_sidebar(assigns) do current_team = assigns.current_team current_team_role = assigns.current_team_role options = %{ "Account" => [ %{key: "Preferences", value: "preferences", icon: :cog_6_tooth}, %{key: "Security", value: "security", icon: :lock_closed}, if(ee?() and not Teams.setup?(current_team), do: %{key: "Subscription", value: "billing/subscription", icon: :subscription} ), if(not Teams.setup?(current_team), do: %{key: "API keys", value: "api-keys", icon: :api_keys} ), if(Plausible.Users.type(assigns.current_user) == :standard, do: %{key: "Danger zone", value: "danger-zone", icon: :exclamation_triangle} ) ] |> Enum.reject(&is_nil/1) } if Teams.setup?(current_team) do Map.put( options, "Team", [ %{key: "General", value: "team/general", icon: :adjustments_horizontal}, if(ee?() and current_team_role in Plausible.Billing.allowed_roles(), do: %{key: "Subscription", value: "billing/subscription", icon: :subscription} ), if(current_team_role in [:owner, :billing, :admin, :editor], do: %{key: "API keys", value: "api-keys", icon: :api_keys} ), if( ee?() and current_team_role == :owner and Plausible.Billing.Feature.SSO.check_availability(current_team) == :ok, do: %{ key: "Single Sign-On", icon: :cloud, value: [ %{key: "Configuration", value: "sso/general"}, %{key: "Sessions", value: "sso/sessions"} ] } ), if( ee?() and Plausible.Billing.Feature.SSO.check_availability(current_team) != :ok, do: %{ key: "Single Sign-On", value: "sso/info", icon: :cloud } ), if(current_team_role == :owner, do: %{key: "Danger zone", value: "team/delete", icon: :exclamation_triangle} ) ] |> Enum.reject(&is_nil/1) ) else options end end attr :conn, :map, required: true attr :teams, :list, required: true attr :my_team, :any, default: nil attr :current_team, :any, default: nil def team_switcher(assigns) do teams = assigns[:teams] if teams && length(teams) > 0 do current_team = assigns[:current_team] my_team = assigns[:my_team] current_included? = current_team && Enum.any?(teams, &(&1.id == current_team.id)) current_is_my? = current_team && my_team && current_team.id == my_team.id teams = if current_team && !current_included? && !current_is_my? do [current_team | teams] else teams end teams = if my_team do teams ++ [my_team] else teams ++ [%Teams.Team{identifier: "none", name: Teams.default_name()}] end selected_id = current_team && current_team.id {pinned_team, other_teams} = Enum.split_with(teams, &(&1.id == selected_id)) assigns = assigns |> assign(:pinned_team, List.first(pinned_team)) |> assign(:other_teams, other_teams) ~H""" <.dropdown_item>
Teams
<.dropdown_item :if={@pinned_team} href={Routes.site_path(@conn, :index, __team: @pinned_team.identifier)} >

{Teams.name(@pinned_team)}

<.dropdown_item :for={team <- @other_teams} href={Routes.site_path(@conn, :index, __team: team.identifier)} >

{Teams.name(team)}

""" else ~H"" end end def trial_notification(team) do case Teams.trial_days_left(team) do days when days > 1 -> "#{days} trial days left" days when days == 1 -> "Trial ends tomorrow" days when days == 0 -> "Trial ends today" end end @doc "http://blog.plataformatec.com.br/2018/05/nested-layouts-with-phoenix/" def render_layout(layout, assigns, do: content) do render(layout, Map.put(assigns, :inner_layout, content)) end def current_tab?(_, nil) do false end def current_tab?(path, tab) when is_binary(path) do String.ends_with?(path, tab) end def current_tab?(conn, tab) do full_path = Path.join(conn.path_info) one_up = conn.path_info |> Enum.drop(-1) |> Path.join() case conn.method do :get -> String.ends_with?(full_path, tab) _ -> String.ends_with?(full_path, tab) or String.ends_with?(one_up, tab) end end end