From c9073aca3c6ea9ea2ddb7e3a868231ec6b377510 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 1 Apr 2026 15:49:55 -0400 Subject: [PATCH] Misc cleanup --- docs/plugins/development/ui-components.md | 83 +++++++++++++++++------ netbox/netbox/ui/actions.py | 2 +- netbox/netbox/ui/layout.py | 2 +- netbox/netbox/ui/panels.py | 10 +-- 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/docs/plugins/development/ui-components.md b/docs/plugins/development/ui-components.md index a8fe2eff0..d388bf11a 100644 --- a/docs/plugins/development/ui-components.md +++ b/docs/plugins/development/ui-components.md @@ -85,26 +85,6 @@ NetBox also includes a set of panels suite for specific uses, such as display ob ::: netbox.ui.panels.ObjectAttributesPanel -#### Object Attributes - -The following classes are available to represent object attributes within an ObjectAttributesPanel. Additionally, plugins can subclass `netbox.ui.attrs.ObjectAttribute` to create custom classes. - -| Class | Description | -|--------------------------------------|--------------------------------------------------| -| `netbox.ui.attrs.AddressAttr` | A physical or mailing address. | -| `netbox.ui.attrs.BooleanAttr` | A boolean value | -| `netbox.ui.attrs.ColorAttr` | A color expressed in RGB | -| `netbox.ui.attrs.ChoiceAttr` | A selection from a set of choices | -| `netbox.ui.attrs.GPSCoordinatesAttr` | GPS coordinates (latitude and longitude) | -| `netbox.ui.attrs.ImageAttr` | An attached image (displays the image) | -| `netbox.ui.attrs.NestedObjectAttr` | A related nested object | -| `netbox.ui.attrs.NumericAttr` | An integer or float value | -| `netbox.ui.attrs.RelatedObjectAttr` | A related object | -| `netbox.ui.attrs.TemplatedAttr` | Renders an attribute using a custom template | -| `netbox.ui.attrs.TextAttr` | A string (text) value | -| `netbox.ui.attrs.TimezoneAttr` | A timezone with annotated offset | -| `netbox.ui.attrs.UtilizationAttr` | A numeric value expressed as a utilization graph | - ::: netbox.ui.panels.OrganizationalObjectPanel ::: netbox.ui.panels.NestedGroupObjectPanel @@ -119,9 +99,13 @@ The following classes are available to represent object attributes within an Obj ::: netbox.ui.panels.TemplatePanel +::: netbox.ui.panels.TextCodePanel + +::: netbox.ui.panels.ContextTablePanel + ::: netbox.ui.panels.PluginContentPanel -## Panel Actions +### Panel Actions Each panel may have actions associated with it. These render as links or buttons within the panel header, opposite the panel's title. For example, a common use case is to include an "Add" action on a panel which displays a list of objects. Below is an example of this. @@ -146,3 +130,60 @@ panels.ObjectsTablePanel( ::: netbox.ui.actions.AddObject ::: netbox.ui.actions.CopyContent + +## Object Attributes + +The following classes are available to represent object attributes within an ObjectAttributesPanel. Additionally, plugins can subclass `netbox.ui.attrs.ObjectAttribute` to create custom classes. + +| Class | Description | +|------------------------------------------|--------------------------------------------------| +| `netbox.ui.attrs.AddressAttr` | A physical or mailing address. | +| `netbox.ui.attrs.BooleanAttr` | A boolean value | +| `netbox.ui.attrs.ChoiceAttr` | A selection from a set of choices | +| `netbox.ui.attrs.ColorAttr` | A color expressed in RGB | +| `netbox.ui.attrs.DateTimeAttr` | A date or datetime value | +| `netbox.ui.attrs.GenericForeignKeyAttr` | A related object via a generic foreign key | +| `netbox.ui.attrs.GPSCoordinatesAttr` | GPS coordinates (latitude and longitude) | +| `netbox.ui.attrs.ImageAttr` | An attached image (displays the image) | +| `netbox.ui.attrs.NestedObjectAttr` | A related nested object (includes ancestors) | +| `netbox.ui.attrs.NumericAttr` | An integer or float value | +| `netbox.ui.attrs.RelatedObjectAttr` | A related object | +| `netbox.ui.attrs.RelatedObjectListAttr` | A list of related objects | +| `netbox.ui.attrs.TemplatedAttr` | Renders an attribute using a custom template | +| `netbox.ui.attrs.TextAttr` | A string (text) value | +| `netbox.ui.attrs.TimezoneAttr` | A timezone with annotated offset | +| `netbox.ui.attrs.UtilizationAttr` | A numeric value expressed as a utilization graph | + +::: netbox.ui.attrs.ObjectAttribute + +::: netbox.ui.attrs.AddressAttr + +::: netbox.ui.attrs.BooleanAttr + +::: netbox.ui.attrs.ChoiceAttr + +::: netbox.ui.attrs.ColorAttr + +::: netbox.ui.attrs.DateTimeAttr + +::: netbox.ui.attrs.GenericForeignKeyAttr + +::: netbox.ui.attrs.GPSCoordinatesAttr + +::: netbox.ui.attrs.ImageAttr + +::: netbox.ui.attrs.NestedObjectAttr + +::: netbox.ui.attrs.NumericAttr + +::: netbox.ui.attrs.RelatedObjectAttr + +::: netbox.ui.attrs.RelatedObjectListAttr + +::: netbox.ui.attrs.TemplatedAttr + +::: netbox.ui.attrs.TextAttr + +::: netbox.ui.attrs.TimezoneAttr + +::: netbox.ui.attrs.UtilizationAttr diff --git a/netbox/netbox/ui/actions.py b/netbox/netbox/ui/actions.py index 7579e7b93..791171ffc 100644 --- a/netbox/netbox/ui/actions.py +++ b/netbox/netbox/ui/actions.py @@ -59,7 +59,7 @@ class PanelAction: """ # Enforce permissions user = context['request'].user - if not user.has_perms(self.permissions): + if self.permissions and not user.has_perms(self.permissions): return '' return render_to_string(self.template_name, self.get_context(context)) diff --git a/netbox/netbox/ui/layout.py b/netbox/netbox/ui/layout.py index b59fd7b34..9ac58d697 100644 --- a/netbox/netbox/ui/layout.py +++ b/netbox/netbox/ui/layout.py @@ -62,7 +62,7 @@ class SimpleLayout(Layout): """ A layout with one row of two columns and a second row with one column. - Plugin content registered for `left_page`, `right_page`, or `full_width_path` is included automatically. Most object + Plugin content registered for `left_page`, `right_page`, or `full_width_page` is included automatically. Most object views in NetBox utilize this layout. ``` diff --git a/netbox/netbox/ui/panels.py b/netbox/netbox/ui/panels.py index f58e98449..295428aff 100644 --- a/netbox/netbox/ui/panels.py +++ b/netbox/netbox/ui/panels.py @@ -225,9 +225,10 @@ class CommentsPanel(ObjectPanel): self.field_name = field_name def get_context(self, context): + ctx = super().get_context(context) return { - **super().get_context(context), - 'comments': getattr(context['object'], self.field_name), + **ctx, + 'comments': getattr(ctx['object'], self.field_name), } @@ -249,9 +250,10 @@ class JSONPanel(ObjectPanel): self.actions.append(CopyContent(f'panel_{field_name}')) def get_context(self, context): + ctx = super().get_context(context) return { - **super().get_context(context), - 'data': getattr(context['object'], self.field_name), + **ctx, + 'data': getattr(ctx['object'], self.field_name), 'field_name': self.field_name, }