diff --git a/docs/configuration.md b/docs/configuration.md index eb281bf4..2a274fb6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -38,7 +38,7 @@ JAZZMIN_SETTINGS = { "copyright": "Acme Library Ltd", # List of model admins to search from the search bar, search bar omitted if excluded - # If you want to use a single search field you dont need to use a list, you can use a simple string + # If you want to use a single search field you dont need to use a list, you can use a simple string "search_model": ["auth.User", "auth.Group"], # Field name on user model that contains avatar ImageField/URLField/Charfield or a callable that receives the user @@ -93,11 +93,12 @@ JAZZMIN_SETTINGS = { # List of apps (and/or models) to base side menu ordering off of (does not need to contain all apps/models) "order_with_respect_to": ["auth", "books", "books.author", "books.book"], - # Custom links to append to app groups, keyed on app name + # Custom links to append to app groups + # use the lower case app label to add links to that app, or use a new name to create a new group "custom_links": { "books": [{ - "name": "Make Messages", - "url": "make_messages", + "name": "Make Messages", + "url": "make_messages", "icon": "fas fa-comments", "permissions": ["books.view_book"] }] @@ -210,23 +211,32 @@ Currently, custom links (See below) cannot be ordered ### Side menu custom links -Custom links can be added using `custom_links`, this is a dictionary of links, keyed on the app they will live under. +Custom links can be added using `custom_links`, this is a dictionary of links, keyed on the (lower case) app they will +live under, OR to make a new menu group, use an app label that is not one of your installed apps + Example: ```python "custom_links": { "books": [{ # Any Name you like - "name": "Make Messages", - + "name": "Make Messages", + # url name e.g `admin:index`, relative urls e.g `/admin/index` or absolute urls e.g `https://domain.com/admin/index` - "url": "make_messages", - + "url": "make_messages", + # any font-awesome icon, see list here https://fontawesome.com/icons?d=gallery&m=free&v=5.0.0,5.0.1,5.0.10,5.0.11,5.0.12,5.0.13,5.0.2,5.0.3,5.0.4,5.0.5,5.0.6,5.0.7,5.0.8,5.0.9,5.1.0,5.1.1,5.2.0,5.3.0,5.3.1,5.4.0,5.4.1,5.4.2,5.13.0,5.12.0,5.11.2,5.11.1,5.10.0,5.9.0,5.8.2,5.8.1,5.7.2,5.7.1,5.7.0,5.6.3,5.5.0,5.4.2 (optional) - "icon": "fas fa-comments", - + "icon": "fas fa-comments", + # a list of permissions the user must have to see this link (optional) - "permissions": ["books.view_book"] + "permissions": ["books.view_book"] + }], + # Add/Or a new group (name must not conflict with an installed app) + "custom_group": [{ + "name": "Custom Link", + "url": "custom_link", + "icon": "fas fa-comments", + "permissions": ["books.view_book"] }] }, ``` diff --git a/jazzmin/settings.py b/jazzmin/settings.py index bf57f336..a98d8286 100644 --- a/jazzmin/settings.py +++ b/jazzmin/settings.py @@ -57,7 +57,8 @@ "hide_models": [], # List of apps to base side menu ordering off of "order_with_respect_to": [], - # Custom links to append to side menu app groups, keyed on app name + # Custom links to append to side menu app groups, keyed on lower case app label + # or makes a new group if the given app label doesnt exist in installed apps "custom_links": {}, # Custom icons for side menu apps/models See the link below # https://fontawesome.com/icons?d=gallery&m=free&v=5.0.0,5.0.1,5.0.10,5.0.11,5.0.12,5.0.13,5.0.2,5.0.3,5.0.4,5.0.5,5.0.6,5.0.7,5.0.8,5.0.9,5.1.0, diff --git a/jazzmin/templatetags/jazzmin.py b/jazzmin/templatetags/jazzmin.py index 7f24dfc2..78bbedca 100644 --- a/jazzmin/templatetags/jazzmin.py +++ b/jazzmin/templatetags/jazzmin.py @@ -31,6 +31,7 @@ from ..utils import ( get_admin_url, get_filter_id, + get_installed_apps, has_fieldsets_check, make_menu, order_with_respect_to, @@ -56,8 +57,17 @@ def get_side_menu(context: Context, using: str = "available_apps") -> List[Dict] ordering = options.get("order_with_respect_to", []) ordering = [x.lower() for x in ordering] + installed_apps = get_installed_apps() + available_apps: list[dict[str, Any]] = copy.deepcopy(context.get(using, [])) + menu = [] - available_apps = copy.deepcopy(context.get(using, [])) + + # Add any arbitrary groups that are not in available_apps + for app_label in options.get("custom_links", {}): + if app_label.lower() not in installed_apps: + available_apps.append( + {"name": app_label, "app_label": app_label, "app_url": "#", "has_module_perms": True, "models": []} + ) custom_links = { app_name: make_menu(user, links, options, allow_appmenus=False) diff --git a/jazzmin/utils.py b/jazzmin/utils.py index c1fe8099..ede4ff8b 100644 --- a/jazzmin/utils.py +++ b/jazzmin/utils.py @@ -237,3 +237,7 @@ def decorator(func: Callable): return func return decorator + + +def get_installed_apps() -> list[str]: + return [app_config.label for app_config in apps.get_app_configs()] diff --git a/pyproject.toml b/pyproject.toml index 0b4d6441..e4a9c597 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,7 +91,7 @@ known-first-party = ["jazzmin"] known-local-folder = ["tests"] [tool.ruff.lint.mccabe] -max-complexity = 10 +max-complexity = 11 [tool.coverage.run] omit = ["*/__init__.py", ".tox", ".mypy_cache", ".reports", ".git"] diff --git a/tests/test_app/library/settings.py b/tests/test_app/library/settings.py index 6f4897fb..389ba2cc 100644 --- a/tests/test_app/library/settings.py +++ b/tests/test_app/library/settings.py @@ -171,7 +171,8 @@ "hide_models": [], # List of apps to base side menu (app or model) ordering off of "order_with_respect_to": ["Make Messages", "auth", "books", "books.author", "books.book", "loans"], - # Custom links to append to app groups, keyed on app name + # Custom links to append to app groups, keyed on (lower case) app label + # or use a name not in installed apps for a new group "custom_links": { "loans": [ { diff --git a/tests/utils.py b/tests/utils.py index a4521103..fec6f34b 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -8,7 +8,7 @@ def parse_sidemenu(response): """ - Convert the side menu to a dict keyed on app name, containing a list of links + Convert the side menu to a dict keyed on app label, containing a list of links """ menu = defaultdict(list) current_app = "Global"