Packages

phoenix_kit

1.7.219
1.7.220 1.7.219 1.7.218 1.7.217 1.7.216 1.7.215 1.7.214 1.7.213 1.7.212 1.7.211 1.7.210 1.7.209 1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit dashboard admin_tabs.ex
Raw

lib/phoenix_kit/dashboard/admin_tabs.ex

defmodule PhoenixKit.Dashboard.AdminTabs do
@moduledoc """
Default admin navigation tabs for PhoenixKit.
Defines all admin sidebar navigation items as Tab structs.
These are registered in the Dashboard Registry during initialization
and can be customized by parent applications via config.
"""
use Gettext, backend: PhoenixKitWeb.Gettext
require Logger
alias PhoenixKit.Dashboard.{Group, Tab}
alias PhoenixKit.ModuleRegistry
alias PhoenixKit.Users.Auth.Scope
# Builder helper to reduce repetition across admin subtab definitions.
# All admin tabs share level: :admin; subtabs share parent and permission.
defp admin_subtab(id, label, icon, path, priority, parent, permission, opts \\ []) do
%Tab{
id: id,
label: label,
icon: icon,
path: path,
priority: priority,
level: :admin,
permission: permission,
parent: parent,
match: Keyword.get(opts, :match, :prefix),
gettext_backend: PhoenixKitWeb.Gettext
}
end
@doc """
Returns all default admin tabs.
"""
@spec default_tabs() :: [Tab.t()]
def default_tabs do
core_tabs() ++ module_tabs() ++ settings_tabs()
end
@doc """
Returns the default admin tab groups.
"""
@spec default_groups() :: [Group.t()]
def default_groups do
[
%Group{id: :admin_main, label: nil, priority: 100},
%Group{id: :admin_modules, label: nil, priority: 500},
%Group{id: :admin_system, label: nil, priority: 900}
]
end
@doc """
Returns core admin tabs (always present, gated only by permission).
"""
@spec core_tabs() :: [Tab.t()]
def core_tabs do
tabs = [
# Dashboard
%Tab{
id: :admin_dashboard,
label: gettext_noop("Dashboard"),
icon: "hero-home",
path: "",
priority: 100,
level: :admin,
permission: "dashboard",
match: :exact,
group: :admin_main,
gettext_backend: PhoenixKitWeb.Gettext
},
# Users parent
%Tab{
id: :admin_users,
label: gettext_noop("Users"),
icon: "hero-users",
path: "users",
priority: 200,
level: :admin,
permission: "users",
match: :prefix,
group: :admin_main,
subtab_display: :when_active,
highlight_with_subtabs: false,
gettext_backend: PhoenixKitWeb.Gettext
},
# Users subtabs
admin_subtab(
:admin_users_manage,
gettext_noop("Users"),
"hero-users",
"users",
210,
:admin_users,
"users",
# :exact only matched the list itself (/admin/users) — viewing or
# editing a single user (/admin/users/view|edit/:id) fell through
# to no subtab match, so the parent :admin_users tab (which DOES
# prefix-match those routes) highlighted as a whole section
# instead of this specific "Users" subtab staying lit. Match the
# list + its own detail/edit/new routes, but not sibling subtabs
# (roles, permissions, live_sessions, sessions) which have their
# own path already covered by their own :prefix match.
match: {:regex, ~r{^/admin/users(/(new|edit|view)(/.*)?)?$}}
),
admin_subtab(
:admin_users_live_sessions,
gettext_noop("Live Sessions"),
"hero-eye",
"users/live_sessions",
220,
:admin_users,
"users"
),
admin_subtab(
:admin_users_sessions,
gettext_noop("Sessions"),
"hero-computer-desktop",
"users/sessions",
230,
:admin_users,
"users"
),
admin_subtab(
:admin_users_roles,
gettext_noop("Roles"),
"hero-shield-check",
"users/roles",
240,
:admin_users,
"users"
),
admin_subtab(
:admin_users_permissions,
gettext_noop("Permissions"),
"hero-key",
"users/permissions",
250,
:admin_users,
"users"
),
# Activity
%Tab{
id: :admin_activity,
label: gettext_noop("Activity"),
icon: "hero-bell-alert",
path: "activity",
priority: 250,
level: :admin,
permission: "dashboard",
match: :prefix,
group: :admin_main,
gettext_backend: PhoenixKitWeb.Gettext
},
# Media
%Tab{
id: :admin_media,
label: gettext_noop("Media"),
icon: "hero-photo",
path: "media",
priority: 300,
level: :admin,
permission: "media",
match: :prefix,
group: :admin_main,
gettext_backend: PhoenixKitWeb.Gettext
}
]
Enum.map(tabs, &Tab.resolve_path(&1, :admin))
end
@doc """
Returns feature module admin tabs (collected from ModuleRegistry).
"""
@spec module_tabs() :: [Tab.t()]
def module_tabs do
ModuleRegistry.all_admin_tabs() ++
[
# Modules management page (core admin, not a feature module)
Tab.resolve_path(
%Tab{
id: :admin_modules_page,
label: gettext_noop("Modules"),
icon: "hero-puzzle-piece",
path: "modules",
priority: 630,
level: :admin,
permission: "modules",
match: :exact,
group: :admin_modules,
gettext_backend: PhoenixKitWeb.Gettext
},
:admin
)
]
end
@doc """
Returns settings admin tabs.
Core settings (General, Organization, Users, Media) are hardcoded here.
Feature module settings subtabs are collected from the ModuleRegistry.
"""
@spec settings_tabs() :: [Tab.t()]
def settings_tabs do
core_settings_tabs() ++ ModuleRegistry.all_settings_tabs()
end
defp core_settings_tabs do
# Settings parent lives in admin context (it's a top-level sidebar item)
settings_parent =
Tab.resolve_path(
%Tab{
id: :admin_settings,
label: gettext_noop("Settings"),
icon: "hero-cog-6-tooth",
path: "settings",
priority: 910,
level: :admin,
match: :exact,
group: :admin_system,
subtab_display: :when_active,
highlight_with_subtabs: false,
visible: &__MODULE__.settings_visible?/1,
gettext_backend: PhoenixKitWeb.Gettext
},
:admin
)
# Settings subtabs live in settings context (paths under /admin/settings/)
subtabs = [
admin_subtab(
:admin_settings_general,
gettext_noop("General"),
"hero-cog-6-tooth",
"",
911,
:admin_settings,
"settings",
match: :exact
),
admin_subtab(
:admin_settings_authorization,
gettext_noop("Authorization"),
"hero-lock-closed",
"authorization",
912,
:admin_settings,
"settings"
),
admin_subtab(
:admin_settings_organization,
gettext_noop("Organization"),
"hero-building-office",
"organization",
913,
:admin_settings,
"settings"
),
admin_subtab(
:admin_settings_users,
gettext_noop("Users"),
"hero-users",
"users",
914,
:admin_settings,
"settings"
),
admin_subtab(
:admin_settings_email_sending,
gettext_noop("Email Sending"),
"hero-envelope",
"email-sending",
916,
:admin_settings,
"settings"
),
admin_subtab(
:admin_settings_send_profiles,
gettext_noop("Send Profiles"),
"hero-adjustments-horizontal",
"email-sending/profiles",
917,
:admin_settings_email_sending,
"settings"
),
# Integrations — a Settings sub-section grouping "My Integrations"
# (personal, "integrations" key) and "Website Integrations" (system,
# "integrations_system" key). Shown if the user holds EITHER key; the
# parent link redirects to the first sub-subtab they can actually reach
# (so a system-only user lands on Website, not the personal index).
%Tab{
id: :admin_integrations,
label: gettext_noop("Integrations"),
icon: "hero-link",
path: "integrations",
priority: 920,
level: :admin,
parent: :admin_settings,
match: :prefix,
subtab_display: :when_active,
highlight_with_subtabs: false,
redirect_to_first_subtab: true,
visible: &__MODULE__.integrations_visible?/1,
gettext_backend: PhoenixKitWeb.Gettext
},
admin_subtab(
:admin_integrations_mine,
gettext_noop("My Integrations"),
"hero-user",
"integrations",
921,
:admin_integrations,
"integrations",
# Active on the personal pages (/integrations, /new, /:uuid) but not on
# the "/integrations/website*" pages owned by the Website sub-subtab.
match: {:regex, ~r{^/admin/settings/integrations(?!/website)}}
),
admin_subtab(
:admin_integrations_website,
gettext_noop("Website Integrations"),
"hero-globe-alt",
"integrations/website",
922,
:admin_integrations,
"integrations_system"
),
%Tab{
id: :admin_settings_media,
label: gettext_noop("Media"),
icon: "hero-photo",
path: "media",
priority: 933,
level: :admin,
permission: "media",
match: :prefix,
parent: :admin_settings,
subtab_display: :when_active,
highlight_with_subtabs: false,
gettext_backend: PhoenixKitWeb.Gettext
},
admin_subtab(
:admin_settings_media_dimensions,
gettext_noop("Dimensions"),
"hero-arrows-pointing-out",
"media/dimensions",
934,
:admin_settings_media,
"media"
),
admin_subtab(
:admin_settings_media_health,
gettext_noop("Health"),
"hero-heart",
"media/health",
935,
:admin_settings_media,
"media"
)
]
[settings_parent | Enum.map(subtabs, &Tab.resolve_path(&1, :settings))]
end
@doc """
Visibility function for the Settings parent tab.
Returns true if user has "settings" permission or any sub-module permission.
"""
@spec settings_visible?(map()) :: boolean()
def settings_visible?(scope) do
# Settings visible if user has core "settings" permission, "media",
# either integrations key (the Settings › Integrations sub-section), or
# any module permission that provides settings tabs.
Scope.has_module_access?(scope, "settings") or
Scope.has_module_access?(scope, "media") or
integrations_visible?(scope) or
Enum.any?(settings_tab_permissions(), &Scope.has_module_access?(scope, &1))
rescue
error ->
Logger.warning("[AdminTabs] settings_visible?/1 failed: #{Exception.message(error)}")
false
end
@doc """
Whether the unified Integrations section is visible — the user holds the
personal `integrations` key OR the website-wide `integrations_system` key.
Each subtab is then gated by its own key.
"""
@spec integrations_visible?(map()) :: boolean()
def integrations_visible?(scope) do
Scope.has_module_access?(scope, "integrations") or
Scope.has_module_access?(scope, "integrations_system")
rescue
error ->
Logger.warning("[AdminTabs] integrations_visible?/1 failed: #{Exception.message(error)}")
false
end
# Returns permission keys from modules that actually provide settings tabs
defp settings_tab_permissions do
ModuleRegistry.all_settings_tabs()
|> Enum.map(& &1.permission)
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
end
end