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:
|
||||
vc_members = []
|
||||
|
||||
services = Service.objects.restrict(request.user, 'view').filter(device=instance)
|
||||
|
||||
return {
|
||||
'services': services,
|
||||
'vc_members': vc_members,
|
||||
'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.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 {
|
||||
'parent_prefixes_table': parent_prefixes_table,
|
||||
'duplicate_ips_table': duplicate_ips_table,
|
||||
'related_ips_table': related_ips_table,
|
||||
'services': services,
|
||||
}
|
||||
|
||||
|
||||
|
@ -282,7 +282,20 @@
|
||||
</div>
|
||||
</div>
|
||||
{% 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/image_attachments.html' %}
|
||||
{% 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,11 +117,16 @@
|
||||
{% include 'inc/panel_table.html' with table=duplicate_ips_table heading='Duplicate IPs' panel_class='danger' %}
|
||||
{% endif %}
|
||||
{% 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 %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
{% plugin_full_width_page object %}
|
||||
|
@ -144,7 +144,20 @@
|
||||
</table>
|
||||
</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' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
|
@ -327,32 +327,7 @@ class VirtualMachineListView(generic.ObjectListView):
|
||||
|
||||
@register_model_view(VirtualMachine)
|
||||
class VirtualMachineView(generic.ObjectView):
|
||||
queryset = VirtualMachine.objects.prefetch_related('tenant__group')
|
||||
|
||||
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,
|
||||
}
|
||||
queryset = VirtualMachine.objects.all()
|
||||
|
||||
|
||||
@register_model_view(VirtualMachine, 'interfaces')
|
||||
|
Loading…
Reference in New Issue
Block a user