feat(virtualization): Refactor VirtualMachine view to UI layout

Migrate the VirtualMachine detail view to SimpleLayout with standardized
panels for attributes, clusters, and resources. Modularize templates
to improve maintainability and reuse.

Fixes #21337
This commit is contained in:
Martin Hauser
2026-02-06 14:54:25 +01:00
committed by Jeremy Stretch
parent 584e0a9b8c
commit 5013297326
7 changed files with 122 additions and 199 deletions

View File

View File

@@ -0,0 +1,34 @@
from django.utils.translation import gettext_lazy as _
from netbox.ui import attrs, panels
class VirtualMachinePanel(panels.ObjectAttributesPanel):
name = attrs.TextAttr('name')
status = attrs.ChoiceAttr('status')
start_on_boot = attrs.ChoiceAttr('start_on_boot')
role = attrs.RelatedObjectAttr('role', linkify=True)
platform = attrs.NestedObjectAttr('platform', linkify=True, max_depth=3)
description = attrs.TextAttr('description')
serial = attrs.TextAttr('serial', label=_('Serial number'), style='font-monospace', copy_button=True)
tenant = attrs.RelatedObjectAttr('tenant', linkify=True, grouped_by='group')
config_template = attrs.RelatedObjectAttr('config_template', linkify=True)
primary_ip4 = attrs.TemplatedAttr(
'primary_ip4',
label=_('Primary IPv4'),
template_name='virtualization/virtualmachine/attrs/ipaddress.html',
)
primary_ip6 = attrs.TemplatedAttr(
'primary_ip6',
label=_('Primary IPv6'),
template_name='virtualization/virtualmachine/attrs/ipaddress.html',
)
class VirtualMachineClusterPanel(panels.ObjectAttributesPanel):
title = _('Cluster')
site = attrs.RelatedObjectAttr('site', linkify=True, grouped_by='group')
cluster = attrs.RelatedObjectAttr('cluster', linkify=True)
cluster_type = attrs.RelatedObjectAttr('cluster.type', linkify=True)
device = attrs.RelatedObjectAttr('device', linkify=True)

View File

@@ -10,12 +10,15 @@ from dcim.filtersets import DeviceFilterSet
from dcim.forms import DeviceFilterForm
from dcim.models import Device
from dcim.tables import DeviceTable
from extras.ui.panels import CustomFieldsPanel, ImageAttachmentsPanel, TagsPanel
from extras.views import ObjectConfigContextView, ObjectRenderConfigView
from ipam.models import IPAddress, VLANGroup
from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
from netbox.object_actions import (
AddObject, BulkDelete, BulkEdit, BulkExport, BulkImport, BulkRename, DeleteObject, EditObject,
)
from netbox.ui import actions, layout
from netbox.ui.panels import CommentsPanel, ObjectsTablePanel, TemplatePanel
from netbox.views import generic
from utilities.query import count_related
from utilities.query_functions import CollateAsChar
@@ -23,6 +26,7 @@ from utilities.views import GetRelatedModelsMixin, ViewTab, register_model_view
from . import filtersets, forms, tables
from .models import *
from .object_actions import BulkAddComponents
from .ui import panels
#
@@ -336,6 +340,7 @@ class ClusterAddDevicesView(generic.ObjectEditView):
# Virtual machines
#
@register_model_view(VirtualMachine, 'list', path='', detail=False)
class VirtualMachineListView(generic.ObjectListView):
queryset = VirtualMachine.objects.prefetch_related('primary_ip4', 'primary_ip6')
@@ -348,6 +353,44 @@ class VirtualMachineListView(generic.ObjectListView):
@register_model_view(VirtualMachine)
class VirtualMachineView(generic.ObjectView):
queryset = VirtualMachine.objects.all()
layout = layout.SimpleLayout(
left_panels=[
panels.VirtualMachinePanel(),
CustomFieldsPanel(),
TagsPanel(),
CommentsPanel(),
],
right_panels=[
panels.VirtualMachineClusterPanel(),
TemplatePanel('virtualization/panels/virtual_machine_resources.html'),
ObjectsTablePanel(
model='ipam.Service',
title=_('Application Services'),
filters={'virtual_machine_id': lambda ctx: ctx['object'].pk},
actions=[
actions.AddObject(
'ipam.Service',
url_params={
'parent_object_type': lambda ctx: ContentType.objects.get_for_model(ctx['object']).pk,
'parent': lambda ctx: ctx['object'].pk,
},
),
],
),
ImageAttachmentsPanel(),
],
bottom_panels=[
ObjectsTablePanel(
model='virtualization.VirtualDisk',
filters={'virtual_machine_id': lambda ctx: ctx['object'].pk},
actions=[
actions.AddObject(
'virtualization.VirtualDisk', url_params={'virtual_machine': lambda ctx: ctx['object'].pk}
),
],
),
],
)
@register_model_view(VirtualMachine, 'interfaces')