Переглянути джерело

#9416: cleanup & widget improvements

jeremystretch 2 роки тому
батько
коміт
e176c7d906

+ 67 - 5
netbox/extras/constants.py

@@ -19,6 +19,19 @@ WEBHOOK_EVENT_TYPES = {
 
 # Dashboard
 DEFAULT_DASHBOARD = [
+    {
+        'widget': 'extras.ObjectCountsWidget',
+        'width': 4,
+        'height': 2,
+        'title': 'Organization',
+        'config': {
+            'models': [
+                'dcim.site',
+                'tenancy.tenant',
+                'tenancy.contact',
+            ]
+        }
+    },
     {
         'widget': 'extras.ObjectCountsWidget',
         'width': 4,
@@ -26,12 +39,53 @@ DEFAULT_DASHBOARD = [
         'title': 'IPAM',
         'config': {
             'models': [
+                'ipam.vrf',
                 'ipam.aggregate',
                 'ipam.prefix',
+                'ipam.iprange',
                 'ipam.ipaddress',
+                'ipam.vlan',
+            ]
+        }
+    },
+    {
+        'widget': 'extras.NoteWidget',
+        'width': 4,
+        'height': 2,
+        'title': 'Welcome!',
+        'color': 'green',
+        'config': {
+            'content': (
+                'This is your personal dashboard. Feel free to customize it by rearranging, resizing, or removing '
+                'widgets. You can also add new widgets using the "add widget" button below. Any changes affect only '
+                '_your_ dashboard, so feel free to experiment!'
+            )
+        }
+    },
+    {
+        'widget': 'extras.ObjectCountsWidget',
+        'width': 4,
+        'height': 2,
+        'title': 'Circuits',
+        'config': {
+            'models': [
+                'circuits.provider',
+                'circuits.circuit',
+                'circuits.providernetwork',
             ]
         }
     },
+    {
+        'widget': 'extras.RSSFeedWidget',
+        'width': 4,
+        'height': 4,
+        'title': 'NetBox News',
+        'config': {
+            'feed_url': 'http://netbox.dev/rss/',
+            'max_entries': 10,
+            'cache_timeout': 14400,
+        }
+    },
     {
         'widget': 'extras.ObjectCountsWidget',
         'width': 4,
@@ -41,25 +95,33 @@ DEFAULT_DASHBOARD = [
             'models': [
                 'dcim.site',
                 'dcim.rack',
+                'dcim.devicetype',
                 'dcim.device',
-            ]
+                'dcim.cable',
+            ],
         }
     },
     {
-        'widget': 'extras.NoteWidget',
+        'widget': 'extras.ObjectCountsWidget',
         'width': 4,
-        'height': 3,
+        'height': 2,
+        'title': 'Virtualization',
         'config': {
-            'content': 'Welcome to **NetBox**!'
+            'models': [
+                'virtualization.cluster',
+                'virtualization.virtualmachine',
+            ]
         }
     },
     {
         'widget': 'extras.ObjectListWidget',
         'width': 12,
-        'height': 6,
+        'height': 5,
         'title': 'Change Log',
+        'color': 'blue',
         'config': {
             'model': 'extras.objectchange',
+            'page_size': 25,
         }
     },
 ]

+ 3 - 1
netbox/extras/dashboard/forms.py

@@ -1,5 +1,6 @@
 from django import forms
 from django.urls import reverse_lazy
+from django.utils.translation import gettext as _
 
 from netbox.registry import registry
 from utilities.forms import BootstrapMixin, add_blank_choice
@@ -33,6 +34,7 @@ class DashboardWidgetAddForm(DashboardWidgetForm):
                 'hx-get': reverse_lazy('extras:dashboardwidget_add'),
                 'hx-target': '#widget_add_form',
             }
-        )
+        ),
+        label=_('Widget type')
     )
     field_order = ('widget_class', 'title', 'color')

+ 2 - 4
netbox/extras/dashboard/utils.py

@@ -54,10 +54,7 @@ def get_dashboard(user):
 
 def get_default_dashboard():
     from extras.models import Dashboard
-    dashboard = Dashboard(
-        layout=[],
-        config={}
-    )
+    dashboard = Dashboard()
     for widget in DEFAULT_DASHBOARD:
         id = str(uuid.uuid4())
         dashboard.layout.append({
@@ -70,6 +67,7 @@ def get_default_dashboard():
         dashboard.config[id] = {
             'class': widget['widget'],
             'title': widget.get('title'),
+            'color': widget.get('color'),
             'config': widget.get('config', {}),
         }
 

+ 13 - 0
netbox/extras/dashboard/widgets.py

@@ -7,6 +7,7 @@ from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.core.cache import cache
 from django.template.loader import render_to_string
+from django.urls import NoReverseMatch, reverse
 from django.utils.translation import gettext as _
 
 from utilities.forms import BootstrapMixin
@@ -126,14 +127,26 @@ class ObjectListWidget(DashboardWidget):
         model = forms.ChoiceField(
             choices=get_content_type_labels
         )
+        page_size = forms.IntegerField(
+            required=False,
+            min_value=1,
+            max_value=100,
+            help_text=_('The default number of objects to display')
+        )
 
     def render(self, request):
         app_label, model_name = self.config['model'].split('.')
         content_type = ContentType.objects.get_by_natural_key(app_label, model_name)
         viewname = get_viewname(content_type.model_class(), action='list')
+        try:
+            htmx_url = reverse(viewname)
+        except NoReverseMatch:
+            htmx_url = None
 
         return render_to_string(self.template_name, {
             'viewname': viewname,
+            'htmx_url': htmx_url,
+            'page_size': self.config.get('page_size'),
         })
 
 

+ 2 - 2
netbox/extras/migrations/0087_dashboard.py

@@ -17,8 +17,8 @@ class Migration(migrations.Migration):
             name='Dashboard',
             fields=[
                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
-                ('layout', models.JSONField()),
-                ('config', models.JSONField()),
+                ('layout', models.JSONField(default=list)),
+                ('config', models.JSONField(default=dict)),
                 ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='dashboard', to=settings.AUTH_USER_MODEL)),
             ],
         ),

+ 6 - 2
netbox/extras/models/dashboard.py

@@ -14,8 +14,12 @@ class Dashboard(models.Model):
         on_delete=models.CASCADE,
         related_name='dashboard'
     )
-    layout = models.JSONField()
-    config = models.JSONField()
+    layout = models.JSONField(
+        default=list
+    )
+    config = models.JSONField(
+        default=dict
+    )
 
     class Meta:
         pass

+ 1 - 0
netbox/extras/views.py

@@ -727,6 +727,7 @@ class DashboardWidgetConfigView(LoginRequiredMixin, View):
         config_form = widget.ConfigForm(initial=widget.form_data.get('config'), prefix='config')
 
         return render(request, self.template_name, {
+            'widget_class': widget.__class__,
             'widget_form': widget_form,
             'config_form': config_form,
             'form_url': reverse('extras:dashboardwidget_config', kwargs={'id': id})

+ 2 - 1
netbox/templates/extras/dashboard/widget_config.html

@@ -3,10 +3,11 @@
 <form hx-post="{{ form_url }}">
   {% csrf_token %}
   <div class="modal-header">
-    <h5 class="modal-title">Widget Configuration</h5>
+    <h5 class="modal-title">{{ widget_class }} Configuration</h5>
     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
   </div>
   <div class="modal-body">
+    <p>{{ widget_class.description }}</p>
     {% block form %}
       {% render_form widget_form %}
       {% render_form config_form %}

+ 7 - 4
netbox/templates/extras/dashboard/widgets/objectlist.html

@@ -1,4 +1,7 @@
-<div class="htmx-container"
-  hx-get="{% url viewname %}"
-  hx-trigger="load"
-></div>
+{% if htmx_url %}
+  <div class="htmx-container" hx-get="{{ htmx_url }}{% if page_size %}?per_page={{ page_size }}{% endif %}" hx-trigger="load"></div>
+{% else %}
+  <div class="text-danger text-center">
+    <i class="mdi mdi-alert"></i> Unable to load content. Invalid view name: <span class="font-monospace">{{ viewname }}</span>
+  </div>
+{% endif %}

+ 1 - 1
netbox/templates/home.html

@@ -40,7 +40,7 @@
       <i class="mdi mdi-plus"></i> Add Widget
     </a>
     <button id="save_dashboard" class="btn btn-primary btn-sm" data-url="{% url 'extras-api:dashboard' %}">
-      <i class="mdi mdi-content-save-outline"></i> Save
+      <i class="mdi mdi-content-save-outline"></i> Save Layout
     </button>
   </div>
 {% endblock content-wrapper %}