mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-14 04:19:36 -06:00
Introduce SimpleLayout
This commit is contained in:
parent
59899d0d9a
commit
d5cec3723e
@ -21,7 +21,8 @@ from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
|
|||||||
from netbox.object_actions import *
|
from netbox.object_actions import *
|
||||||
from netbox.ui import actions, layout
|
from netbox.ui import actions, layout
|
||||||
from netbox.ui.panels import (
|
from netbox.ui.panels import (
|
||||||
CommentsPanel, NestedGroupObjectPanel, ObjectsTablePanel, PluginContentPanel, RelatedObjectsPanel, TemplatePanel,
|
CommentsPanel, NestedGroupObjectPanel, ObjectsTablePanel, OrganizationalObjectPanel, RelatedObjectsPanel,
|
||||||
|
TemplatePanel,
|
||||||
)
|
)
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
@ -228,33 +229,26 @@ class RegionListView(generic.ObjectListView):
|
|||||||
@register_model_view(Region)
|
@register_model_view(Region)
|
||||||
class RegionView(GetRelatedModelsMixin, generic.ObjectView):
|
class RegionView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Region.objects.all()
|
queryset = Region.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
NestedGroupObjectPanel(),
|
||||||
NestedGroupObjectPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ObjectsTablePanel(
|
||||||
|
model='dcim.Region',
|
||||||
|
title=_('Child Regions'),
|
||||||
|
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
layout.Column(
|
]
|
||||||
RelatedObjectsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.Region',
|
|
||||||
title=_('Child Regions'),
|
|
||||||
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -367,33 +361,26 @@ class SiteGroupListView(generic.ObjectListView):
|
|||||||
@register_model_view(SiteGroup)
|
@register_model_view(SiteGroup)
|
||||||
class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
class SiteGroupView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = SiteGroup.objects.all()
|
queryset = SiteGroup.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
NestedGroupObjectPanel(),
|
||||||
NestedGroupObjectPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ObjectsTablePanel(
|
||||||
|
model='dcim.SiteGroup',
|
||||||
|
title=_('Child Groups'),
|
||||||
|
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
layout.Column(
|
]
|
||||||
RelatedObjectsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.SiteGroup',
|
|
||||||
title=_('Child Groups'),
|
|
||||||
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject('dcim.Region', url_params={'parent': lambda ctx: ctx['object'].pk}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -524,45 +511,38 @@ class SiteListView(generic.ObjectListView):
|
|||||||
@register_model_view(Site)
|
@register_model_view(Site)
|
||||||
class SiteView(GetRelatedModelsMixin, generic.ObjectView):
|
class SiteView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Site.objects.prefetch_related('tenant__group')
|
queryset = Site.objects.prefetch_related('tenant__group')
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.SitePanel(),
|
||||||
panels.SitePanel(),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
ImageAttachmentsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ObjectsTablePanel(
|
||||||
|
model='dcim.Location',
|
||||||
|
filters={'site_id': lambda ctx: ctx['object'].pk},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject('dcim.Location', url_params={'site': lambda ctx: ctx['object'].pk}),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
layout.Column(
|
ObjectsTablePanel(
|
||||||
RelatedObjectsPanel(),
|
model='dcim.Device',
|
||||||
ImageAttachmentsPanel(),
|
title=_('Non-Racked Devices'),
|
||||||
PluginContentPanel('right_page'),
|
filters={
|
||||||
|
'site_id': lambda ctx: ctx['object'].pk,
|
||||||
|
'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
||||||
|
'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
||||||
|
},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject('dcim.Device', url_params={'site': lambda ctx: ctx['object'].pk}),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
]
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.Location',
|
|
||||||
filters={'site_id': lambda ctx: ctx['object'].pk},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject('dcim.Location', url_params={'site': lambda ctx: ctx['object'].pk}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.Device',
|
|
||||||
title=_('Non-Racked Devices'),
|
|
||||||
filters={
|
|
||||||
'site_id': lambda ctx: ctx['object'].pk,
|
|
||||||
'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
|
||||||
'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
|
||||||
},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject('dcim.Device', url_params={'site': lambda ctx: ctx['object'].pk}),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -664,58 +644,51 @@ class LocationListView(generic.ObjectListView):
|
|||||||
@register_model_view(Location)
|
@register_model_view(Location)
|
||||||
class LocationView(GetRelatedModelsMixin, generic.ObjectView):
|
class LocationView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Location.objects.all()
|
queryset = Location.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.LocationPanel(),
|
||||||
panels.LocationPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
|
RelatedObjectsPanel(),
|
||||||
|
ImageAttachmentsPanel(),
|
||||||
|
],
|
||||||
|
bottom_panels=[
|
||||||
|
ObjectsTablePanel(
|
||||||
|
model='dcim.Location',
|
||||||
|
title=_('Child Locations'),
|
||||||
|
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'dcim.Location',
|
||||||
|
url_params={
|
||||||
|
'site': lambda ctx: ctx['object'].site_id,
|
||||||
|
'parent': lambda ctx: ctx['object'].pk,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
layout.Column(
|
ObjectsTablePanel(
|
||||||
RelatedObjectsPanel(),
|
model='dcim.Device',
|
||||||
ImageAttachmentsPanel(),
|
title=_('Non-Racked Devices'),
|
||||||
PluginContentPanel('right_page'),
|
filters={
|
||||||
|
'location_id': lambda ctx: ctx['object'].pk,
|
||||||
|
'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
||||||
|
'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
||||||
|
},
|
||||||
|
actions=[
|
||||||
|
actions.AddObject(
|
||||||
|
'dcim.Device',
|
||||||
|
url_params={
|
||||||
|
'site': lambda ctx: ctx['object'].site_id,
|
||||||
|
'parent': lambda ctx: ctx['object'].pk,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
]
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.Location',
|
|
||||||
title=_('Child Locations'),
|
|
||||||
filters={'parent_id': lambda ctx: ctx['object'].pk},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject(
|
|
||||||
'dcim.Location',
|
|
||||||
url_params={
|
|
||||||
'site': lambda ctx: ctx['object'].site_id,
|
|
||||||
'parent': lambda ctx: ctx['object'].pk,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
ObjectsTablePanel(
|
|
||||||
model='dcim.Device',
|
|
||||||
title=_('Non-Racked Devices'),
|
|
||||||
filters={
|
|
||||||
'location_id': lambda ctx: ctx['object'].pk,
|
|
||||||
'rack_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
|
||||||
'parent_bay_id': settings.FILTERS_NULL_CHOICE_VALUE,
|
|
||||||
},
|
|
||||||
actions=[
|
|
||||||
actions.AddObject(
|
|
||||||
'dcim.Device',
|
|
||||||
url_params={
|
|
||||||
'site': lambda ctx: ctx['object'].site_id,
|
|
||||||
'parent': lambda ctx: ctx['object'].pk,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -817,24 +790,15 @@ class RackRoleListView(generic.ObjectListView):
|
|||||||
@register_model_view(RackRole)
|
@register_model_view(RackRole)
|
||||||
class RackRoleView(GetRelatedModelsMixin, generic.ObjectView):
|
class RackRoleView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = RackRole.objects.all()
|
queryset = RackRole.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.RackRolePanel(),
|
||||||
panels.RackRolePanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
),
|
RelatedObjectsPanel(),
|
||||||
layout.Column(
|
CustomFieldsPanel(),
|
||||||
RelatedObjectsPanel(),
|
],
|
||||||
CustomFieldsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -903,28 +867,19 @@ class RackTypeListView(generic.ObjectListView):
|
|||||||
@register_model_view(RackType)
|
@register_model_view(RackType)
|
||||||
class RackTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
class RackTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = RackType.objects.all()
|
queryset = RackType.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.RackTypePanel(),
|
||||||
panels.RackTypePanel(),
|
panels.RackDimensionsPanel(title=_('Dimensions')),
|
||||||
panels.RackDimensionsPanel(title=_('Dimensions')),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
),
|
panels.RackNumberingPanel(title=_('Numbering')),
|
||||||
layout.Column(
|
panels.RackWeightPanel(title=_('Weight'), exclude=['total_weight']),
|
||||||
panels.RackNumberingPanel(title=_('Numbering')),
|
CustomFieldsPanel(),
|
||||||
panels.RackWeightPanel(title=_('Weight'), exclude=['total_weight']),
|
RelatedObjectsPanel(),
|
||||||
CustomFieldsPanel(),
|
],
|
||||||
RelatedObjectsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -1043,30 +998,21 @@ class RackElevationListView(generic.ObjectListView):
|
|||||||
@register_model_view(Rack)
|
@register_model_view(Rack)
|
||||||
class RackView(GetRelatedModelsMixin, generic.ObjectView):
|
class RackView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
|
queryset = Rack.objects.prefetch_related('site__region', 'tenant__group', 'location', 'role')
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.RackPanel(),
|
||||||
panels.RackPanel(),
|
panels.RackDimensionsPanel(title=_('Dimensions')),
|
||||||
panels.RackDimensionsPanel(title=_('Dimensions')),
|
panels.RackNumberingPanel(title=_('Numbering')),
|
||||||
panels.RackNumberingPanel(title=_('Numbering')),
|
panels.RackWeightPanel(title=_('Weight')),
|
||||||
panels.RackWeightPanel(title=_('Weight')),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
ImageAttachmentsPanel(),
|
||||||
ImageAttachmentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
),
|
TemplatePanel('dcim/panels/rack_elevations.html'),
|
||||||
layout.Column(
|
RelatedObjectsPanel(),
|
||||||
TemplatePanel('dcim/panels/rack_elevations.html'),
|
],
|
||||||
RelatedObjectsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
@ -1199,27 +1145,18 @@ class RackReservationListView(generic.ObjectListView):
|
|||||||
@register_model_view(RackReservation)
|
@register_model_view(RackReservation)
|
||||||
class RackReservationView(generic.ObjectView):
|
class RackReservationView(generic.ObjectView):
|
||||||
queryset = RackReservation.objects.all()
|
queryset = RackReservation.objects.all()
|
||||||
layout = layout.Layout(
|
layout = layout.SimpleLayout(
|
||||||
layout.Row(
|
left_panels=[
|
||||||
layout.Column(
|
panels.RackPanel(accessor='rack', only=['region', 'site', 'location']),
|
||||||
panels.RackPanel(title=_('Rack'), accessor='rack', only=['region', 'site', 'location']),
|
CustomFieldsPanel(),
|
||||||
CustomFieldsPanel(),
|
TagsPanel(),
|
||||||
TagsPanel(),
|
CommentsPanel(),
|
||||||
CommentsPanel(),
|
ImageAttachmentsPanel(),
|
||||||
ImageAttachmentsPanel(),
|
],
|
||||||
PluginContentPanel('left_page'),
|
right_panels=[
|
||||||
),
|
TemplatePanel('dcim/panels/rack_elevations.html'),
|
||||||
layout.Column(
|
RelatedObjectsPanel(),
|
||||||
TemplatePanel('dcim/panels/rack_elevations.html'),
|
],
|
||||||
RelatedObjectsPanel(),
|
|
||||||
PluginContentPanel('right_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
layout.Row(
|
|
||||||
layout.Column(
|
|
||||||
PluginContentPanel('full_width_page'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -1294,6 +1231,10 @@ class ManufacturerListView(generic.ObjectListView):
|
|||||||
@register_model_view(Manufacturer)
|
@register_model_view(Manufacturer)
|
||||||
class ManufacturerView(GetRelatedModelsMixin, generic.ObjectView):
|
class ManufacturerView(GetRelatedModelsMixin, generic.ObjectView):
|
||||||
queryset = Manufacturer.objects.all()
|
queryset = Manufacturer.objects.all()
|
||||||
|
layout = layout.SimpleLayout(
|
||||||
|
left_panels=[OrganizationalObjectPanel(), TagsPanel()],
|
||||||
|
right_panels=[RelatedObjectsPanel(), CustomFieldsPanel()],
|
||||||
|
)
|
||||||
|
|
||||||
def get_extra_context(self, request, instance):
|
def get_extra_context(self, request, instance):
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
from netbox.ui.panels import Panel
|
from netbox.ui.panels import Panel, PluginContentPanel
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Column',
|
'Column',
|
||||||
'Layout',
|
'Layout',
|
||||||
'Row',
|
'Row',
|
||||||
|
'SimpleLayout',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Base classes
|
||||||
|
#
|
||||||
|
|
||||||
class Layout:
|
class Layout:
|
||||||
|
|
||||||
def __init__(self, *rows):
|
def __init__(self, *rows):
|
||||||
@ -32,3 +37,27 @@ class Column:
|
|||||||
if not isinstance(panel, Panel):
|
if not isinstance(panel, Panel):
|
||||||
raise TypeError(f"Panel {i} must be an instance of a Panel, not {type(panel)}.")
|
raise TypeError(f"Panel {i} must be an instance of a Panel, not {type(panel)}.")
|
||||||
self.panels = panels
|
self.panels = panels
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Standard layouts
|
||||||
|
#
|
||||||
|
|
||||||
|
class SimpleLayout(Layout):
|
||||||
|
"""
|
||||||
|
A layout with one row of two columns and a second row with one column. Includes registered plugin content.
|
||||||
|
"""
|
||||||
|
def __init__(self, left_panels=None, right_panels=None, bottom_panels=None):
|
||||||
|
left_panels = left_panels or []
|
||||||
|
right_panels = right_panels or []
|
||||||
|
bottom_panels = bottom_panels or []
|
||||||
|
rows = [
|
||||||
|
Row(
|
||||||
|
Column(*left_panels, PluginContentPanel('left_page')),
|
||||||
|
Column(*right_panels, PluginContentPanel('right_page')),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
Column(*bottom_panels, PluginContentPanel('full_width_page'))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
super().__init__(*rows)
|
||||||
|
|||||||
@ -149,6 +149,7 @@ class ObjectPanel(Panel, metaclass=ObjectPanelMeta):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
**super().get_context(context),
|
**super().get_context(context),
|
||||||
|
'title': self.title or title(obj._meta.verbose_name),
|
||||||
'attrs': [
|
'attrs': [
|
||||||
{
|
{
|
||||||
'label': attr.label or title(name),
|
'label': attr.label or title(name),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user