From 98732f05aa272f5fdf36a29110ae354bb173922d Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 23 Feb 2023 14:55:34 -0500 Subject: [PATCH] Implement view to add dashboard widgets --- netbox/extras/dashboard/forms.py | 20 +++++++ netbox/extras/urls.py | 1 + netbox/extras/views.py | 56 ++++++++++++++++++- .../extras/dashboard/widget_add.html | 19 +++++++ netbox/templates/home.html | 9 +++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 netbox/templates/extras/dashboard/widget_add.html diff --git a/netbox/extras/dashboard/forms.py b/netbox/extras/dashboard/forms.py index 04896cf80..9c09e6e7b 100644 --- a/netbox/extras/dashboard/forms.py +++ b/netbox/extras/dashboard/forms.py @@ -1,13 +1,33 @@ from django import forms +from django.urls import reverse_lazy +from netbox.registry import registry from utilities.forms import BootstrapMixin __all__ = ( + 'DashboardWidgetAddForm', 'DashboardWidgetForm', ) +def get_widget_choices(): + return registry['widgets'].items() + + class DashboardWidgetForm(BootstrapMixin, forms.Form): title = forms.CharField( required=False ) + + +class DashboardWidgetAddForm(DashboardWidgetForm): + widget_class = forms.ChoiceField( + choices=get_widget_choices, + widget=forms.Select( + attrs={ + 'hx-get': reverse_lazy('extras:dashboardwidget_add'), + 'hx-target': '#widget_add_form', + } + ) + ) + field_order = ('widget_class', 'title') diff --git a/netbox/extras/urls.py b/netbox/extras/urls.py index 6d15038c4..e127e164a 100644 --- a/netbox/extras/urls.py +++ b/netbox/extras/urls.py @@ -88,6 +88,7 @@ urlpatterns = [ path('changelog//', include(get_model_urls('extras', 'objectchange'))), # User dashboard + path('dashboard/widgets/add/', views.DashboardWidgetAddView.as_view(), name='dashboardwidget_add'), path('dashboard/widgets//configure/', views.DashboardWidgetConfigView.as_view(), name='dashboardwidget_config'), path('dashboard/widgets//delete/', views.DashboardWidgetDeleteView.as_view(), name='dashboardwidget_delete'), diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 5fb3ede5d..d303c7050 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -9,10 +9,11 @@ from django.views.generic import View from django_rq.queues import get_connection from rq import Worker -from extras.dashboard.forms import DashboardWidgetForm +from extras.dashboard.forms import DashboardWidgetAddForm, DashboardWidgetForm from extras.dashboard.utils import get_widget_class_and_config +from netbox.registry import registry from netbox.views import generic -from utilities.forms import ConfirmationForm +from utilities.forms import ConfirmationForm, get_field_value from utilities.htmx import is_htmx from utilities.utils import copy_safe_request, count_related, get_viewname, normalize_querydict, shallow_compare_dict from utilities.views import ContentTypePermissionRequiredMixin, register_model_view @@ -672,6 +673,57 @@ class JournalEntryBulkDeleteView(generic.BulkDeleteView): # Dashboard widgets # +class DashboardWidgetAddView(LoginRequiredMixin, View): + template_name = 'extras/dashboard/widget_add.html' + + def get(self, request): + initial = request.GET or { + 'widget_class': 'extras.NoteWidget', + } + widget_form = DashboardWidgetAddForm(initial=initial) + widget_name = get_field_value(widget_form, 'widget_class') + widget_class = registry['widgets'][widget_name] + config_form = widget_class.ConfigForm(prefix='config') + + if not is_htmx(request): + return redirect('home') + + return render(request, self.template_name, { + 'widget_form': widget_form, + 'config_form': config_form, + }) + + def post(self, request): + widget_form = DashboardWidgetAddForm(request.POST) + + if widget_form.is_valid(): + widget_class = registry['widgets'][widget_form.cleaned_data['widget_class']] + config_form = widget_class.ConfigForm(request.POST, prefix='config') + + if config_form.is_valid(): + data = widget_form.cleaned_data + class_name = data.pop('widget_class') + data['config'] = config_form.cleaned_data + widget = widget_class(**data) + data['class'] = class_name + request.user.config.set(f'dashboard.widgets.{widget.id}', data) + request.user.config.get(f'dashboard.layout').append({ + 'h': widget.height, + 'w': widget.width, + 'id': str(widget.id), + }) + request.user.config.save() + + response = HttpResponse() + response['HX-Redirect'] = reverse('home') + return response + + return render(request, self.template_name, { + 'widget_form': widget_form, + 'config_form': config_form, + }) + + class DashboardWidgetConfigView(LoginRequiredMixin, View): template_name = 'extras/dashboard/widget_config.html' diff --git a/netbox/templates/extras/dashboard/widget_add.html b/netbox/templates/extras/dashboard/widget_add.html new file mode 100644 index 000000000..86be86421 --- /dev/null +++ b/netbox/templates/extras/dashboard/widget_add.html @@ -0,0 +1,19 @@ +{% load form_helpers %} + +
+ {% csrf_token %} + + + +
diff --git a/netbox/templates/home.html b/netbox/templates/home.html index cd4761f87..08135ea4e 100644 --- a/netbox/templates/home.html +++ b/netbox/templates/home.html @@ -30,6 +30,15 @@ {% endfor %}