|
| 1 | +# UI Components |
| 2 | + |
| 3 | +!!! note "New in NetBox v4.5" |
| 4 | + All UI components described here were introduced in NetBox v4.5. Be sure to set the minimum NetBox version to 4.5.0 for your plugin before incorporating any of these resources. |
| 5 | + |
| 6 | +!!! danger "Beta Feature" |
| 7 | + UI components are considered a beta feature, and are still under active development. Please be aware that the API for resources on this page is subject to change in future releases. |
| 8 | + |
| 9 | +To simply the process of designing your plugin's user interface, and to encourage a consistent look and feel throughout the entire application, NetBox provides a set of components that enable programmatic UI design. These make it possible to declare complex page layouts with little or no custom HTML. |
| 10 | + |
| 11 | +## Page Layout |
| 12 | + |
| 13 | +A layout defines the general arrangement of content on a page into rows and columns. The layout is defined under the [view](./views.md) and declares a set of rows, each of which may have one or more columns. Below is an example layout. |
| 14 | + |
| 15 | +``` |
| 16 | ++-------+-------+-------+ |
| 17 | +| Col 1 | Col 2 | Col 3 | |
| 18 | ++-------+-------+-------+ |
| 19 | +| Col 4 | |
| 20 | ++-----------+-----------+ |
| 21 | +| Col 5 | Col 6 | |
| 22 | ++-----------+-----------+ |
| 23 | +``` |
| 24 | + |
| 25 | +The above layout can be achieved with the following declaration under a view: |
| 26 | + |
| 27 | +```python |
| 28 | +from netbox.ui import layout |
| 29 | +from netbox.views import generic |
| 30 | + |
| 31 | +class MyView(generic.ObjectView): |
| 32 | + layout = layout.Layout( |
| 33 | + layout.Row( |
| 34 | + layout.Column(), |
| 35 | + layout.Column(), |
| 36 | + layout.Column(), |
| 37 | + ), |
| 38 | + layout.Row( |
| 39 | + layout.Column(), |
| 40 | + ), |
| 41 | + layout.Row( |
| 42 | + layout.Column(), |
| 43 | + layout.Column(), |
| 44 | + ), |
| 45 | + ) |
| 46 | +``` |
| 47 | + |
| 48 | +!!! note |
| 49 | + Currently, layouts are supported only for subclasses of [`generic.ObjectView`](./views.md#netbox.views.generic.ObjectView). |
| 50 | + |
| 51 | +::: netbox.ui.layout.Layout |
| 52 | + |
| 53 | +::: netbox.ui.layout.SimpleLayout |
| 54 | + |
| 55 | +::: netbox.ui.layout.Row |
| 56 | + |
| 57 | +::: netbox.ui.layout.Column |
| 58 | + |
| 59 | +## Panels |
| 60 | + |
| 61 | +Within each column, related blocks of content are arranged into panels. Each panel has a title and may have a set of associated actions, but the content within is otherwise arbitrary. |
| 62 | + |
| 63 | +Plugins can define their own panels by inheriting from the base class `netbox.ui.panels.Panel`. Override the `get_context()` method to pass additional context to your custom panel template. An example is provided below. |
| 64 | + |
| 65 | +```python |
| 66 | +from django.utils.translation import gettext_lazy as _ |
| 67 | +from netbox.ui.panels import Panel |
| 68 | + |
| 69 | +class RecentChangesPanel(Panel): |
| 70 | + template_name = 'my_plugin/panels/recent_changes.html' |
| 71 | + title = _('Recent Changes') |
| 72 | + |
| 73 | + def get_context(self, context): |
| 74 | + return { |
| 75 | + **super().get_context(context), |
| 76 | + 'changes': get_changes()[:10], |
| 77 | + } |
| 78 | +``` |
| 79 | + |
| 80 | +NetBox also includes a set of panels suite for specific uses, such as display object details or embedding a table of related objects. These are listed below. |
| 81 | + |
| 82 | +::: netbox.ui.panels.Panel |
| 83 | + |
| 84 | +::: netbox.ui.panels.ObjectPanel |
| 85 | + |
| 86 | +::: netbox.ui.panels.ObjectAttributesPanel |
| 87 | + |
| 88 | +#### Object Attributes |
| 89 | + |
| 90 | +The following classes are available to represent object attributes within an ObjectAttributesPanel. Additionally, plugins can subclass `netbox.ui.attrs.ObjectAttribute` to create custom classes. |
| 91 | + |
| 92 | +| Class | Description | |
| 93 | +|--------------------------------------|--------------------------------------------------| |
| 94 | +| `netbox.ui.attrs.AddressAttr` | A physical or mailing address. | |
| 95 | +| `netbox.ui.attrs.BooleanAttr` | A boolean value | |
| 96 | +| `netbox.ui.attrs.ColorAttr` | A color expressed in RGB | |
| 97 | +| `netbox.ui.attrs.ChoiceAttr` | A selection from a set of choices | |
| 98 | +| `netbox.ui.attrs.GPSCoordinatesAttr` | GPS coordinates (latitude and longitude) | |
| 99 | +| `netbox.ui.attrs.ImageAttr` | An attached image (displays the image) | |
| 100 | +| `netbox.ui.attrs.NestedObjectAttr` | A related nested object | |
| 101 | +| `netbox.ui.attrs.NumericAttr` | An integer or float value | |
| 102 | +| `netbox.ui.attrs.RelatedObjectAttr` | A related object | |
| 103 | +| `netbox.ui.attrs.TemplatedAttr` | Renders an attribute using a custom template | |
| 104 | +| `netbox.ui.attrs.TextAttr` | A string (text) value | |
| 105 | +| `netbox.ui.attrs.TimezoneAttr` | A timezone with annotated offset | |
| 106 | +| `netbox.ui.attrs.UtilizationAttr` | A numeric value expressed as a utilization graph | |
| 107 | + |
| 108 | +::: netbox.ui.panels.OrganizationalObjectPanel |
| 109 | + |
| 110 | +::: netbox.ui.panels.NestedGroupObjectPanel |
| 111 | + |
| 112 | +::: netbox.ui.panels.CommentsPanel |
| 113 | + |
| 114 | +::: netbox.ui.panels.JSONPanel |
| 115 | + |
| 116 | +::: netbox.ui.panels.RelatedObjectsPanel |
| 117 | + |
| 118 | +::: netbox.ui.panels.ObjectsTablePanel |
| 119 | + |
| 120 | +::: netbox.ui.panels.TemplatePanel |
| 121 | + |
| 122 | +::: netbox.ui.panels.PluginContentPanel |
| 123 | + |
| 124 | +## Panel Actions |
| 125 | + |
| 126 | +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. |
| 127 | + |
| 128 | +```python |
| 129 | +from django.utils.translation import gettext_lazy as _ |
| 130 | +from netbox.ui import actions, panels |
| 131 | + |
| 132 | +panels.ObjectsTablePanel( |
| 133 | + model='dcim.Region', |
| 134 | + title=_('Child Regions'), |
| 135 | + filters={'parent_id': lambda ctx: ctx['object'].pk}, |
| 136 | + actions=[ |
| 137 | + actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}), |
| 138 | + ], |
| 139 | +), |
| 140 | +``` |
| 141 | + |
| 142 | +::: netbox.ui.actions.PanelAction |
| 143 | + |
| 144 | +::: netbox.ui.actions.LinkAction |
| 145 | + |
| 146 | +::: netbox.ui.actions.AddObject |
| 147 | + |
| 148 | +::: netbox.ui.actions.CopyContent |
0 commit comments