Coverage for utilities/templatetags/tabs.py: 23%
31 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django import template
2from django.urls.exceptions import NoReverseMatch
3from django.utils.module_loading import import_string
5from netbox.registry import registry
6from utilities.views import get_action_url
8__all__ = (
9 'model_view_tabs',
10)
12register = template.Library()
15#
16# Object detail view tabs
17#
19@register.inclusion_tag('tabs/model_view_tabs.html', takes_context=True)
20def model_view_tabs(context, instance):
21 app_label = instance._meta.app_label
22 model_name = instance._meta.model_name
23 user = context['request'].user
24 tabs = []
26 # Retrieve registered views for this model
27 try:
28 views = registry['views'][app_label][model_name]
29 except KeyError:
30 # No views have been registered for this model
31 views = []
33 # Compile a list of tabs to be displayed in the UI
34 for config in views:
35 view = import_string(config['view']) if type(config['view']) is str else config['view']
36 if tab := getattr(view, 'tab', None):
37 if tab.permission and not user.has_perm(tab.permission):
38 continue
40 if attrs := tab.render(instance):
41 active_tab = context.get('tab')
42 try:
43 url = get_action_url(instance, action=config['name'], kwargs={'pk': instance.pk})
44 except NoReverseMatch:
45 # No URL has been registered for this view; skip
46 continue
47 tabs.append({
48 'name': config['name'],
49 'url': url,
50 'label': attrs['label'],
51 'badge': attrs['badge'],
52 'weight': attrs['weight'],
53 'is_active': active_tab and active_tab == tab,
54 })
56 # Order tabs by weight
57 tabs = sorted(tabs, key=lambda x: x['weight'])
59 return {
60 'tabs': tabs,
61 }