mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-23 17:08:41 -06:00
Use embedded table to show assigned services under object view
This commit is contained in:
parent
8f7c100e22
commit
0f6995e92a
@ -1807,10 +1807,7 @@ class DeviceView(generic.ObjectView):
|
|||||||
else:
|
else:
|
||||||
vc_members = []
|
vc_members = []
|
||||||
|
|
||||||
services = Service.objects.restrict(request.user, 'view').filter(device=instance)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'services': services,
|
|
||||||
'vc_members': vc_members,
|
'vc_members': vc_members,
|
||||||
'svg_extra': f'highlight=id:{instance.pk}'
|
'svg_extra': f'highlight=id:{instance.pk}'
|
||||||
}
|
}
|
||||||
|
@ -716,28 +716,10 @@ class IPAddressView(generic.ObjectView):
|
|||||||
related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
|
related_ips_table = tables.IPAddressTable(related_ips, orderable=False)
|
||||||
related_ips_table.configure(request)
|
related_ips_table.configure(request)
|
||||||
|
|
||||||
# Find services belonging to the IP
|
|
||||||
service_filter = Q(ipaddresses=instance)
|
|
||||||
|
|
||||||
# Find services listening on all IPs on the assigned device/vm
|
|
||||||
try:
|
|
||||||
if instance.assigned_object and instance.assigned_object.parent_object:
|
|
||||||
parent_object = instance.assigned_object.parent_object
|
|
||||||
|
|
||||||
if isinstance(parent_object, VirtualMachine):
|
|
||||||
service_filter |= (Q(virtual_machine=parent_object) & Q(ipaddresses=None))
|
|
||||||
elif isinstance(parent_object, Device):
|
|
||||||
service_filter |= (Q(device=parent_object) & Q(ipaddresses=None))
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
services = Service.objects.restrict(request.user, 'view').filter(service_filter)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'parent_prefixes_table': parent_prefixes_table,
|
'parent_prefixes_table': parent_prefixes_table,
|
||||||
'duplicate_ips_table': duplicate_ips_table,
|
'duplicate_ips_table': duplicate_ips_table,
|
||||||
'related_ips_table': related_ips_table,
|
'related_ips_table': related_ips_table,
|
||||||
'services': services,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,7 +282,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include 'inc/panels/services.html' %}
|
<div class="card">
|
||||||
|
<h5 class="card-header">Services</h5>
|
||||||
|
<div class="card-body htmx-container table-responsive"
|
||||||
|
hx-get="{% url 'ipam:service_list' %}?device_id={{ object.pk }}"
|
||||||
|
hx-trigger="load"
|
||||||
|
></div>
|
||||||
|
{% if perms.ipam.add_service %}
|
||||||
|
<div class="card-footer text-end noprint">
|
||||||
|
<a href="{% url 'ipam:service_add' %}?device={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||||
|
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add a service
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% include 'inc/panels/contacts.html' %}
|
{% include 'inc/panels/contacts.html' %}
|
||||||
{% include 'inc/panels/image_attachments.html' %}
|
{% include 'inc/panels/image_attachments.html' %}
|
||||||
{% if object.rack and object.position %}
|
{% if object.rack and object.position %}
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
<div class="card">
|
|
||||||
<h5 class="card-header">Services</h5>
|
|
||||||
<div class="card-body">
|
|
||||||
{% if services %}
|
|
||||||
<table class="table table-hover">
|
|
||||||
{% for service in services %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ service|linkify:"name" }}</td>
|
|
||||||
<td>{{ service.get_protocol_display }}</td>
|
|
||||||
<td>{{ service.port_list }}</td>
|
|
||||||
<td>
|
|
||||||
{% for ip in service.ipaddresses.all %}
|
|
||||||
<a href="{{ ip.get_absolute_url }}">{{ ip.address.ip }}</a><br />
|
|
||||||
{% empty %}
|
|
||||||
<span class="text-muted">All IPs</span>
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
<td>{{ service.description }}</td>
|
|
||||||
<td class="text-end noprint">
|
|
||||||
<a href="{% url 'ipam:service_changelog' pk=service.pk %}" class="btn btn-sm btn-outline-secondary" title="Change Log">
|
|
||||||
<i class="mdi mdi-history"></i>
|
|
||||||
</a>
|
|
||||||
{% if perms.ipam.change_service %}
|
|
||||||
<a href="{% url 'ipam:service_edit' pk=service.pk %}?return_url={{ service.parent.get_absolute_url }}" class="btn btn-warning btn-sm" title="Edit Service">
|
|
||||||
<i class="mdi mdi-pencil"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if perms.ipam.delete_service %}
|
|
||||||
<a href="{% url 'ipam:service_delete' pk=service.pk %}?return_url={{ service.parent.get_absolute_url }}" class="btn btn-danger btn-sm">
|
|
||||||
<i class="mdi mdi-trash-can-outline" title="Delete Service"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<div class="text-muted">None</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% if perms.ipam.add_service %}
|
|
||||||
{% with object|meta:"model_name" as object_type %}
|
|
||||||
<div class="card-footer text-end noprint">
|
|
||||||
<a href="{% url 'ipam:service_add' %}{% if object_type == "device" %}?device={{ object.pk }}{% elif object_type == "virtualmachine" %}?virtual_machine={{ object.pk }}{% endif %}" class="btn btn-sm btn-primary">
|
|
||||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add Service
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
@ -117,14 +117,19 @@
|
|||||||
{% include 'inc/panel_table.html' with table=duplicate_ips_table heading='Duplicate IPs' panel_class='danger' %}
|
{% include 'inc/panel_table.html' with table=duplicate_ips_table heading='Duplicate IPs' panel_class='danger' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% include 'inc/panel_table.html' with table=related_ips_table heading='Related IPs' %}
|
{% include 'inc/panel_table.html' with table=related_ips_table heading='Related IPs' %}
|
||||||
{% include 'inc/panels/services.html' %}
|
<div class="card">
|
||||||
|
<h5 class="card-header">Services</h5>
|
||||||
|
<div class="card-body htmx-container table-responsive"
|
||||||
|
hx-get="{% url 'ipam:service_list' %}?ipaddress_id={{ object.pk }}"
|
||||||
|
hx-trigger="load"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
{% plugin_right_page object %}
|
{% plugin_right_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-12">
|
<div class="col col-md-12">
|
||||||
{% plugin_full_width_page object %}
|
{% plugin_full_width_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -144,7 +144,20 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'inc/panels/services.html' %}
|
<div class="card">
|
||||||
|
<h5 class="card-header">Services</h5>
|
||||||
|
<div class="card-body htmx-container table-responsive"
|
||||||
|
hx-get="{% url 'ipam:service_list' %}?virtual_machine_id={{ object.pk }}"
|
||||||
|
hx-trigger="load"
|
||||||
|
></div>
|
||||||
|
{% if perms.ipam.add_service %}
|
||||||
|
<div class="card-footer text-end noprint">
|
||||||
|
<a href="{% url 'ipam:service_add' %}?virtual_machine={{ object.pk }}" class="btn btn-sm btn-primary">
|
||||||
|
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add a service
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
{% include 'inc/panels/contacts.html' %}
|
{% include 'inc/panels/contacts.html' %}
|
||||||
{% plugin_right_page object %}
|
{% plugin_right_page object %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -327,32 +327,7 @@ class VirtualMachineListView(generic.ObjectListView):
|
|||||||
|
|
||||||
@register_model_view(VirtualMachine)
|
@register_model_view(VirtualMachine)
|
||||||
class VirtualMachineView(generic.ObjectView):
|
class VirtualMachineView(generic.ObjectView):
|
||||||
queryset = VirtualMachine.objects.prefetch_related('tenant__group')
|
queryset = VirtualMachine.objects.all()
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
|
||||||
# Interfaces
|
|
||||||
vminterfaces = VMInterface.objects.restrict(request.user, 'view').filter(
|
|
||||||
virtual_machine=instance
|
|
||||||
).prefetch_related(
|
|
||||||
Prefetch('ip_addresses', queryset=IPAddress.objects.restrict(request.user))
|
|
||||||
)
|
|
||||||
vminterface_table = tables.VirtualMachineVMInterfaceTable(vminterfaces, user=request.user, orderable=False)
|
|
||||||
if request.user.has_perm('virtualization.change_vminterface') or \
|
|
||||||
request.user.has_perm('virtualization.delete_vminterface'):
|
|
||||||
vminterface_table.columns.show('pk')
|
|
||||||
|
|
||||||
# Services
|
|
||||||
services = Service.objects.restrict(request.user, 'view').filter(
|
|
||||||
virtual_machine=instance
|
|
||||||
).prefetch_related(
|
|
||||||
Prefetch('ipaddresses', queryset=IPAddress.objects.restrict(request.user)),
|
|
||||||
'virtual_machine'
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'vminterface_table': vminterface_table,
|
|
||||||
'services': services,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@register_model_view(VirtualMachine, 'interfaces')
|
@register_model_view(VirtualMachine, 'interfaces')
|
||||||
|
Loading…
Reference in New Issue
Block a user