Define a default dashboard

This commit is contained in:
jeremystretch 2023-02-20 17:19:05 -05:00
parent 029d22e495
commit 0bfd986f08
6 changed files with 123 additions and 28 deletions

View File

@ -5,4 +5,4 @@ class ExtrasConfig(AppConfig):
name = "extras" name = "extras"
def ready(self): def ready(self):
from . import lookups, search, signals from . import dashboard, lookups, search, signals

View File

@ -1,2 +1,47 @@
# Webhook content types # Webhook content types
HTTP_CONTENT_TYPE_JSON = 'application/json' HTTP_CONTENT_TYPE_JSON = 'application/json'
# Dashboard
DEFAULT_DASHBOARD = [
{
'widget': 'extras.ObjectCountsWidget',
'width': 4,
'height': 3,
'config': {
'title': 'IPAM',
'models': [
'ipam.Aggregate',
'ipam.Prefix',
'ipam.IPRange',
'ipam.IPAddress',
]
}
},
{
'widget': 'extras.ObjectCountsWidget',
'width': 4,
'height': 3,
'config': {
'title': 'DCIM',
'models': [
'dcim.Site',
'dcim.Rack',
'dcim.Device',
'dcim.Cable',
]
}
},
{
'widget': 'extras.StaticContentWidget',
'width': 4,
'height': 3,
'config': {
'content': 'Welcome to NetBox!'
}
},
{
'widget': 'extras.ChangeLogWidget',
'width': 12,
'height': 6,
},
]

View File

@ -0,0 +1,2 @@
from .utils import *
from .widgets import *

View File

@ -0,0 +1,66 @@
import uuid
from netbox.registry import registry
from extras.constants import DEFAULT_DASHBOARD
__all__ = (
'get_dashboard',
'register_widget',
)
def register_widget(cls):
"""
Decorator for registering a DashboardWidget class.
"""
app_label = cls.__module__.split('.', maxsplit=1)[0]
label = f'{app_label}.{cls.__name__}'
registry['widgets'][label] = cls
return cls
def get_dashboard(user):
"""
Return the dashboard layout for a given User.
"""
if not user.is_anonymous and user.config.get('dashboard'):
config = user.config.get('dashboard')
else:
config = get_default_dashboard_config()
print(config)
if not user.is_anonymous:
user.config.set('dashboard', config, commit=True)
widgets = []
for grid_item in config['layout']:
widget_id = grid_item['id']
widget_config = config['widgets'][widget_id]
widget_class = registry['widgets'].get(widget_config.pop('class'))
widget = widget_class(id=widget_id, **widget_config)
widget.set_layout(grid_item)
widgets.append(widget)
return widgets
def get_default_dashboard_config():
config = {
'layout': [],
'widgets': {},
}
for widget in DEFAULT_DASHBOARD:
id = str(uuid.uuid4())
config['layout'].append({
'id': id,
'w': widget['width'],
'h': widget['height'],
'x': widget.get('x'),
'y': widget.get('y'),
})
config['widgets'][id] = {
'class': widget['widget'],
'config': widget.get('config', {}),
}
return config

View File

@ -4,28 +4,16 @@ from django.contrib.contenttypes.models import ContentType
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from netbox.registry import registry from .utils import register_widget
__all__ = ( __all__ = (
'ChangeLogWidget', 'ChangeLogWidget',
'DashboardWidget', 'DashboardWidget',
'ObjectCountsWidget', 'ObjectCountsWidget',
'StaticContentWidget', 'StaticContentWidget',
'register_widget',
) )
def register_widget(cls):
"""
Decorator for registering a DashboardWidget class.
"""
label = f'{cls.__module__}.{cls.__name__}'
registry['widgets'][label] = cls
return cls
class DashboardWidget: class DashboardWidget:
width = 4 width = 4
height = 3 height = 3
@ -41,6 +29,12 @@ class DashboardWidget:
self.height = height self.height = height
self.x, self.y = x, y self.x, self.y = x, y
def set_layout(self, grid_item):
self.width = grid_item['w']
self.height = grid_item['h']
self.x = grid_item.get('x')
self.y = grid_item.get('y')
def render(self, request): def render(self, request):
raise NotImplementedError("DashboardWidget subclasses must define a render() method.") raise NotImplementedError("DashboardWidget subclasses must define a render() method.")

View File

@ -9,7 +9,7 @@ from django.views.generic import View
from django_tables2 import RequestConfig from django_tables2 import RequestConfig
from packaging import version from packaging import version
from extras import dashboard from extras.dashboard.utils import get_dashboard
from netbox.forms import SearchForm from netbox.forms import SearchForm
from netbox.registry import registry from netbox.registry import registry
from netbox.search import LookupTypes from netbox.search import LookupTypes
@ -34,19 +34,7 @@ class HomeView(View):
return redirect('login') return redirect('login')
# Build custom dashboard from user's config # Build custom dashboard from user's config
widgets = [] widgets = get_dashboard(request.user)
for grid_item in request.user.config.get('dashboard.layout'):
config = request.user.config.get(f"dashboard.widgets.{grid_item['id']}")
widget_class = registry['widgets'].get(config.pop('class'))
widget = widget_class(
id=grid_item.get('id'),
width=grid_item['w'],
height=grid_item['h'],
x=grid_item['x'],
y=grid_item['y'],
**config
)
widgets.append(widget)
# Check whether a new release is available. (Only for staff/superusers.) # Check whether a new release is available. (Only for staff/superusers.)
new_release = None new_release = None