Merge branch 'develop' into 2365-show-available-toggle

This commit is contained in:
hSaria 2020-01-02 09:18:53 +00:00 committed by GitHub
commit 6a7af22dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 82 additions and 16 deletions

View File

@ -3,6 +3,9 @@
## Enhancements ## Enhancements
* [#2365](https://github.com/netbox-community/netbox/issues/2365) - Toggle for showing available prefixes/ip addresses * [#2365](https://github.com/netbox-community/netbox/issues/2365) - Toggle for showing available prefixes/ip addresses
* [#2892](https://github.com/netbox-community/netbox/issues/2892) - Extend admin UI to allow deleting old report results
* [#3062](https://github.com/netbox-community/netbox/issues/3062) - Add `assigned_to_interface` filter for IP addresses
* [#3461](https://github.com/netbox-community/netbox/issues/3461) - Fail gracefully on custom link rendering exception
* [#3705](https://github.com/netbox-community/netbox/issues/3705) - Provide request context when executing custom scripts * [#3705](https://github.com/netbox-community/netbox/issues/3705) - Provide request context when executing custom scripts
* [#3762](https://github.com/netbox-community/netbox/issues/3762) - Add date/time picker widgets * [#3762](https://github.com/netbox-community/netbox/issues/3762) - Add date/time picker widgets
* [#3788](https://github.com/netbox-community/netbox/issues/3788) - Enable partial search for inventory items * [#3788](https://github.com/netbox-community/netbox/issues/3788) - Enable partial search for inventory items

View File

@ -3,7 +3,10 @@ from django.contrib import admin
from netbox.admin import admin_site from netbox.admin import admin_site
from utilities.forms import LaxURLField from utilities.forms import LaxURLField
from .models import CustomField, CustomFieldChoice, CustomLink, Graph, ExportTemplate, TopologyMap, Webhook from .models import (
CustomField, CustomFieldChoice, CustomLink, Graph, ExportTemplate, ReportResult, TopologyMap, Webhook,
)
from .reports import get_report
def order_content_types(field): def order_content_types(field):
@ -166,6 +169,36 @@ class ExportTemplateAdmin(admin.ModelAdmin):
form = ExportTemplateForm form = ExportTemplateForm
#
# Reports
#
@admin.register(ReportResult, site=admin_site)
class ReportResultAdmin(admin.ModelAdmin):
list_display = [
'report', 'active', 'created', 'user', 'passing',
]
fields = [
'report', 'user', 'passing', 'data',
]
list_filter = [
'failed',
]
readonly_fields = fields
def has_add_permission(self, request):
return False
def active(self, obj):
module, report_name = obj.report.split('.')
return True if get_report(module, report_name) else False
active.boolean = True
def passing(self, obj):
return not obj.failed
passing.boolean = True
# #
# Topology maps # Topology maps
# #

View File

@ -915,6 +915,13 @@ class ReportResult(models.Model):
class Meta: class Meta:
ordering = ['report'] ordering = ['report']
def __str__(self):
return "{} {} at {}".format(
self.report,
"passed" if not self.failed else "failed",
self.created
)
# #
# Change logging # Change logging

View File

@ -46,12 +46,17 @@ def custom_links(obj):
# Add non-grouped links # Add non-grouped links
else: else:
text_rendered = render_jinja2(cl.text, context) try:
if text_rendered: text_rendered = render_jinja2(cl.text, context)
link_target = ' target="_blank"' if cl.new_window else '' if text_rendered:
template_code += LINK_BUTTON.format( link_rendered = render_jinja2(cl.url, context)
cl.url, link_target, cl.button_class, text_rendered link_target = ' target="_blank"' if cl.new_window else ''
) template_code += LINK_BUTTON.format(
link_rendered, link_target, cl.button_class, text_rendered
)
except Exception as e:
template_code += '<a class="btn btn-sm btn-default" disabled="disabled" title="{}">' \
'<i class="fa fa-warning"></i> {}</a>\n'.format(e, cl.name)
# Add grouped links to template # Add grouped links to template
for group, links in group_names.items(): for group, links in group_names.items():
@ -59,11 +64,17 @@ def custom_links(obj):
links_rendered = [] links_rendered = []
for cl in links: for cl in links:
text_rendered = render_jinja2(cl.text, context) try:
if text_rendered: text_rendered = render_jinja2(cl.text, context)
link_target = ' target="_blank"' if cl.new_window else '' if text_rendered:
link_target = ' target="_blank"' if cl.new_window else ''
links_rendered.append(
GROUP_LINK.format(cl.url, link_target, cl.text)
)
except Exception as e:
links_rendered.append( links_rendered.append(
GROUP_LINK.format(cl.url, link_target, cl.text) '<li><a disabled="disabled" title="{}"><span class="text-muted">'
'<i class="fa fa-warning"></i> {}</span></a></li>'.format(e, cl.name)
) )
if links_rendered: if links_rendered:
@ -71,7 +82,4 @@ def custom_links(obj):
links[0].button_class, group, ''.join(links_rendered) links[0].button_class, group, ''.join(links_rendered)
) )
# Render template return mark_safe(template_code)
rendered = render_jinja2(template_code, context)
return mark_safe(rendered)

View File

@ -309,6 +309,10 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
label='Interface (ID)', label='Interface (ID)',
) )
assigned_to_interface = django_filters.BooleanFilter(
method='_assigned_to_interface',
label='Is assigned to an interface',
)
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=IPADDRESS_STATUS_CHOICES, choices=IPADDRESS_STATUS_CHOICES,
null_value=None null_value=None
@ -366,6 +370,9 @@ class IPAddressFilter(TenancyFilterSet, CustomFieldFilterSet, CreatedUpdatedFilt
except Device.DoesNotExist: except Device.DoesNotExist:
return queryset.none() return queryset.none()
def _assigned_to_interface(self, queryset, name, value):
return queryset.exclude(interface__isnull=value)
class VLANGroupFilter(NameSlugSearchFilterSet): class VLANGroupFilter(NameSlugSearchFilterSet):
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(

View File

@ -938,7 +938,8 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm): class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
model = IPAddress model = IPAddress
field_order = [ field_order = [
'q', 'parent', 'family', 'mask_length', 'vrf_id', 'status', 'role', 'tenant_group', 'tenant', 'q', 'parent', 'family', 'mask_length', 'vrf_id', 'status', 'role', 'assigned_to_interface', 'tenant_group',
'tenant',
] ]
q = forms.CharField( q = forms.CharField(
required=False, required=False,
@ -984,6 +985,13 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
required=False, required=False,
widget=StaticSelect2Multiple() widget=StaticSelect2Multiple()
) )
assigned_to_interface = forms.NullBooleanField(
required=False,
label='Assigned to an interface',
widget=StaticSelect2(
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
# #