Add color customization to dashboard widgets

This commit is contained in:
jeremystretch 2023-02-23 15:55:56 -05:00
parent e80428e5a1
commit e9e0738d5d
5 changed files with 28 additions and 20 deletions

View File

@ -2,7 +2,8 @@ from django import forms
from django.urls import reverse_lazy from django.urls import reverse_lazy
from netbox.registry import registry from netbox.registry import registry
from utilities.forms import BootstrapMixin from utilities.forms import BootstrapMixin, add_blank_choice
from utilities.choices import ButtonColorChoices
__all__ = ( __all__ = (
'DashboardWidgetAddForm', 'DashboardWidgetAddForm',
@ -18,6 +19,10 @@ class DashboardWidgetForm(BootstrapMixin, forms.Form):
title = forms.CharField( title = forms.CharField(
required=False required=False
) )
color = forms.ChoiceField(
choices=add_blank_choice(ButtonColorChoices),
required=False,
)
class DashboardWidgetAddForm(DashboardWidgetForm): class DashboardWidgetAddForm(DashboardWidgetForm):

View File

@ -3,7 +3,6 @@ import uuid
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType 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.safestring import mark_safe
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from utilities.forms import BootstrapMixin from utilities.forms import BootstrapMixin
@ -27,7 +26,7 @@ def get_content_type_labels():
class DashboardWidget: class DashboardWidget:
title = None default_title = None
description = None description = None
width = 4 width = 4
height = 3 height = 3
@ -35,11 +34,11 @@ class DashboardWidget:
class ConfigForm(forms.Form): class ConfigForm(forms.Form):
pass pass
def __init__(self, id=None, title=None, config=None, width=None, height=None, x=None, y=None): def __init__(self, id=None, title=None, color=None, config=None, width=None, height=None, x=None, y=None):
self.id = id or uuid.uuid4() self.id = id or uuid.uuid4()
self.config = config or {} self.config = config or {}
if title: self.title = title or self.default_title
self.title = title self.color = color
if width: if width:
self.width = width self.width = width
if height: if height:
@ -56,7 +55,7 @@ class DashboardWidget:
self.y = grid_item.get('y') 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(f"{self.__class__} must define a render() method.")
@property @property
def name(self): def name(self):
@ -66,11 +65,6 @@ class DashboardWidget:
@register_widget @register_widget
class NoteWidget(DashboardWidget): class NoteWidget(DashboardWidget):
description = _('Display some arbitrary custom content. Markdown is supported.') description = _('Display some arbitrary custom content. Markdown is supported.')
default_content = """
<div class="d-flex justify-content-center align-items-center" style="height: 100%">
<div class="text-center text-muted">Empty</div>
</div>
"""
class ConfigForm(BootstrapMixin, forms.Form): class ConfigForm(BootstrapMixin, forms.Form):
content = forms.CharField( content = forms.CharField(
@ -78,14 +72,12 @@ class NoteWidget(DashboardWidget):
) )
def render(self, request): def render(self, request):
if content := self.config.get('content'): return render_markdown(self.config.get('content'))
return render_markdown(content)
return mark_safe(self.default_content)
@register_widget @register_widget
class ObjectCountsWidget(DashboardWidget): class ObjectCountsWidget(DashboardWidget):
title = _('Objects') default_title = _('Objects')
description = _('Display a set of NetBox models and the number of objects created for each type.') description = _('Display a set of NetBox models and the number of objects created for each type.')
template_name = 'extras/dashboard/widgets/objectcounts.html' template_name = 'extras/dashboard/widgets/objectcounts.html'
@ -109,10 +101,11 @@ class ObjectCountsWidget(DashboardWidget):
@register_widget @register_widget
class ChangeLogWidget(DashboardWidget): class ChangeLogWidget(DashboardWidget):
title = _('Change Log') default_title = _('Change Log')
description = _('Display the most recent records from the global change log.')
template_name = 'extras/dashboard/widgets/changelog.html'
width = 12 width = 12
height = 4 height = 4
template_name = 'extras/dashboard/widgets/changelog.html'
def render(self, request): def render(self, request):
return render_to_string(self.template_name, {}) return render_to_string(self.template_name, {})

View File

@ -689,6 +689,7 @@ class DashboardWidgetAddView(LoginRequiredMixin, View):
return redirect('home') return redirect('home')
return render(request, self.template_name, { return render(request, self.template_name, {
'widget_class': widget_class,
'widget_form': widget_form, 'widget_form': widget_form,
'config_form': config_form, 'config_form': config_form,
}) })
@ -719,6 +720,7 @@ class DashboardWidgetAddView(LoginRequiredMixin, View):
return response return response
return render(request, self.template_name, { return render(request, self.template_name, {
'widget_class': widget_class,
'widget_form': widget_form, 'widget_form': widget_form,
'config_form': config_form, 'config_form': config_form,
}) })

View File

@ -9,7 +9,7 @@
gs-id="{{ widget.id }}" gs-id="{{ widget.id }}"
> >
<div class="card grid-stack-item-content"> <div class="card grid-stack-item-content">
<div class="card-header text-center text-light bg-secondary p-1"> <div class="card-header text-center text-light bg-{% if widget.color %}{{ widget.color }}{% else %}secondary{% endif %} p-1">
<div class="float-start ps-1"> <div class="float-start ps-1">
<a href="#" <a href="#"
hx-get="{% url 'extras:dashboardwidget_config' id=widget.id %}" hx-get="{% url 'extras:dashboardwidget_config' id=widget.id %}"

View File

@ -7,7 +7,15 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
{% block form %} {% block form %}
{% render_form widget_form %} {% render_field widget_form.widget_class %}
<div class="row mb-3">
<label class="col-sm-3 col-form-label text-lg-end">Description</label>
<div class="col">
<div class="form-control-plaintext">{{ widget_class.description|placeholder }}</div>
</div>
</div>
{% render_field widget_form.color %}
{% render_field widget_form.title %}
{% render_form config_form %} {% render_form config_form %}
{% endblock form %} {% endblock form %}
</div> </div>