mirror of
https://github.com/netbox-community/netbox.git
synced 2025-12-23 05:42:17 -06:00
Merge branch 'develop' into feature
This commit is contained in:
@@ -163,7 +163,7 @@ class ProviderNetworkView(generic.ObjectView):
|
||||
related_models = (
|
||||
(
|
||||
Circuit.objects.restrict(request.user, 'view').filter(terminations__provider_network=instance),
|
||||
'providernetwork_id',
|
||||
'provider_network_id',
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -836,6 +836,7 @@ class InterfaceTypeChoices(ChoiceSet):
|
||||
TYPE_200GE_CFP2 = '200gbase-x-cfp2'
|
||||
TYPE_200GE_QSFP56 = '200gbase-x-qsfp56'
|
||||
TYPE_200GE_QSFP_DD = '200gbase-x-qsfpdd'
|
||||
TYPE_400GE_CFP2 = '400gbase-x-cfp2'
|
||||
TYPE_400GE_QSFP_DD = '400gbase-x-qsfpdd'
|
||||
TYPE_400GE_OSFP = '400gbase-x-osfp'
|
||||
TYPE_400GE_CDFP = '400gbase-x-cdfp'
|
||||
@@ -978,6 +979,7 @@ class InterfaceTypeChoices(ChoiceSet):
|
||||
(TYPE_100GE_CFP, 'CFP (100GE)'),
|
||||
(TYPE_100GE_CFP2, 'CFP2 (100GE)'),
|
||||
(TYPE_200GE_CFP2, 'CFP2 (200GE)'),
|
||||
(TYPE_400GE_CFP2, 'CFP2 (400GE)'),
|
||||
(TYPE_100GE_CFP4, 'CFP4 (100GE)'),
|
||||
(TYPE_100GE_CXP, 'CXP (100GE)'),
|
||||
(TYPE_100GE_CPAK, 'Cisco CPAK (100GE)'),
|
||||
|
||||
@@ -1098,6 +1098,9 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
||||
queryset=VirtualDeviceContext.objects.all(),
|
||||
required=False,
|
||||
label=_('Virtual device contexts'),
|
||||
initial_params={
|
||||
'interfaces': '$parent',
|
||||
},
|
||||
query_params={
|
||||
'device_id': '$device',
|
||||
}
|
||||
|
||||
@@ -591,7 +591,12 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
||||
}
|
||||
)
|
||||
mgmt_only = columns.BooleanColumn(
|
||||
verbose_name=_('Management Only'),
|
||||
verbose_name=_('Management Only')
|
||||
)
|
||||
speed_formatted = columns.TemplateColumn(
|
||||
template_code='{% load helpers %}{{ value|humanize_speed }}',
|
||||
accessor=Accessor('speed'),
|
||||
verbose_name=_('Speed')
|
||||
)
|
||||
wireless_link = tables.Column(
|
||||
verbose_name=_('Wireless link'),
|
||||
@@ -618,7 +623,7 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
||||
model = models.Interface
|
||||
fields = (
|
||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu',
|
||||
'speed', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
|
||||
'speed', 'speed_formatted', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
|
||||
'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected', 'cable',
|
||||
'cable_color', 'wireless_link', 'wireless_lans', 'link_peer', 'connection', 'tags', 'vdcs', 'vrf', 'l2vpn',
|
||||
'ip_addresses', 'fhrp_groups', 'untagged_vlan', 'tagged_vlans', 'created', 'last_updated',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import traceback
|
||||
from collections import defaultdict
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
@@ -45,6 +46,15 @@ CABLE_TERMINATION_TYPES = {
|
||||
|
||||
|
||||
class DeviceComponentsView(generic.ObjectChildrenView):
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete', 'bulk_rename', 'bulk_disconnect')
|
||||
action_perms = defaultdict(set, **{
|
||||
'add': {'add'},
|
||||
'import': {'add'},
|
||||
'bulk_edit': {'change'},
|
||||
'bulk_delete': {'delete'},
|
||||
'bulk_rename': {'change'},
|
||||
'bulk_disconnect': {'change'},
|
||||
})
|
||||
queryset = Device.objects.all()
|
||||
|
||||
def get_children(self, request, parent):
|
||||
@@ -1997,6 +2007,7 @@ class DeviceModuleBaysView(DeviceComponentsView):
|
||||
table = tables.DeviceModuleBayTable
|
||||
filterset = filtersets.ModuleBayFilterSet
|
||||
template_name = 'dcim/device/modulebays.html'
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete', 'bulk_rename')
|
||||
tab = ViewTab(
|
||||
label=_('Module Bays'),
|
||||
badge=lambda obj: obj.module_bay_count,
|
||||
@@ -2012,6 +2023,7 @@ class DeviceDeviceBaysView(DeviceComponentsView):
|
||||
table = tables.DeviceDeviceBayTable
|
||||
filterset = filtersets.DeviceBayFilterSet
|
||||
template_name = 'dcim/device/devicebays.html'
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete', 'bulk_rename')
|
||||
tab = ViewTab(
|
||||
label=_('Device Bays'),
|
||||
badge=lambda obj: obj.device_bay_count,
|
||||
@@ -2023,6 +2035,7 @@ class DeviceDeviceBaysView(DeviceComponentsView):
|
||||
|
||||
@register_model_view(Device, 'inventory')
|
||||
class DeviceInventoryView(DeviceComponentsView):
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete', 'bulk_rename')
|
||||
child_model = InventoryItem
|
||||
table = tables.DeviceInventoryItemTable
|
||||
filterset = filtersets.InventoryItemFilterSet
|
||||
|
||||
@@ -316,7 +316,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
|
||||
text = clean_html(text, allowed_schemes)
|
||||
|
||||
# Sanitize link
|
||||
link = urllib.parse.quote(link, safe='/:?&=%+[]@#,')
|
||||
link = urllib.parse.quote(link, safe='/:?&=%+[]@#,;')
|
||||
|
||||
# Verify link scheme is allowed
|
||||
result = urllib.parse.urlparse(link)
|
||||
|
||||
@@ -2,7 +2,6 @@ import collections
|
||||
from importlib import import_module
|
||||
|
||||
from django.apps import AppConfig
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.module_loading import import_string
|
||||
from packaging import version
|
||||
@@ -146,23 +145,3 @@ class PluginConfig(AppConfig):
|
||||
for setting, value in cls.default_settings.items():
|
||||
if setting not in user_config:
|
||||
user_config[setting] = value
|
||||
|
||||
|
||||
#
|
||||
# Utilities
|
||||
#
|
||||
|
||||
def get_plugin_config(plugin_name, parameter, default=None):
|
||||
"""
|
||||
Return the value of the specified plugin configuration parameter.
|
||||
|
||||
Args:
|
||||
plugin_name: The name of the plugin
|
||||
parameter: The name of the configuration parameter
|
||||
default: The value to return if the parameter is not defined (default: None)
|
||||
"""
|
||||
try:
|
||||
plugin_config = settings.PLUGINS_CONFIG[plugin_name]
|
||||
return plugin_config.get(parameter, default)
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured(f"Plugin {plugin_name} is not registered.")
|
||||
|
||||
37
netbox/extras/plugins/utils.py
Normal file
37
netbox/extras/plugins/utils.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
__all__ = (
|
||||
'get_installed_plugins',
|
||||
'get_plugin_config',
|
||||
)
|
||||
|
||||
|
||||
def get_installed_plugins():
|
||||
"""
|
||||
Return a dictionary mapping the names of installed plugins to their versions.
|
||||
"""
|
||||
plugins = {}
|
||||
for plugin_name in settings.PLUGINS:
|
||||
plugin_name = plugin_name.rsplit('.', 1)[-1]
|
||||
plugin_config = apps.get_app_config(plugin_name)
|
||||
plugins[plugin_name] = getattr(plugin_config, 'version', None)
|
||||
|
||||
return dict(sorted(plugins.items()))
|
||||
|
||||
|
||||
def get_plugin_config(plugin_name, parameter, default=None):
|
||||
"""
|
||||
Return the value of the specified plugin configuration parameter.
|
||||
|
||||
Args:
|
||||
plugin_name: The name of the plugin
|
||||
parameter: The name of the configuration parameter
|
||||
default: The value to return if the parameter is not defined (default: None)
|
||||
"""
|
||||
try:
|
||||
plugin_config = settings.PLUGINS_CONFIG[plugin_name]
|
||||
return plugin_config.get(parameter, default)
|
||||
except KeyError:
|
||||
raise ImproperlyConfigured(f"Plugin {plugin_name} is not registered.")
|
||||
@@ -214,20 +214,18 @@ class Report(object):
|
||||
self.active_test = method_name
|
||||
test_method = getattr(self, method_name)
|
||||
test_method()
|
||||
job.data = self._results
|
||||
if self.failed:
|
||||
self.logger.warning("Report failed")
|
||||
job.status = JobStatusChoices.STATUS_FAILED
|
||||
job.terminate(status=JobStatusChoices.STATUS_FAILED)
|
||||
else:
|
||||
self.logger.info("Report completed successfully")
|
||||
job.status = JobStatusChoices.STATUS_COMPLETED
|
||||
job.terminate()
|
||||
except Exception as e:
|
||||
stacktrace = traceback.format_exc()
|
||||
self.log_failure(None, f"An exception occurred: {type(e).__name__}: {e} <pre>{stacktrace}</pre>")
|
||||
logger.error(f"Exception raised during report execution: {e}")
|
||||
job.terminate(status=JobStatusChoices.STATUS_ERRORED)
|
||||
finally:
|
||||
job.data = self._results
|
||||
job.terminate()
|
||||
|
||||
# Perform any post-run tasks
|
||||
self.post_run()
|
||||
|
||||
@@ -5,8 +5,9 @@ from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import Client, TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from extras.plugins import PluginMenu, get_plugin_config
|
||||
from extras.plugins import PluginMenu
|
||||
from extras.tests.dummy_plugin import config as dummy_config
|
||||
from extras.plugins.utils import get_plugin_config
|
||||
from netbox.graphql.schema import Query
|
||||
from netbox.registry import registry
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ class WebhookTest(APITestCase):
|
||||
def setUpTestData(cls):
|
||||
|
||||
site_ct = ContentType.objects.get_for_model(Site)
|
||||
DUMMY_URL = "http://localhost/"
|
||||
DUMMY_SECRET = "LOOKATMEIMASECRETSTRING"
|
||||
DUMMY_URL = 'http://localhost:9000/'
|
||||
DUMMY_SECRET = 'LOOKATMEIMASECRETSTRING'
|
||||
|
||||
webhooks = Webhook.objects.bulk_create((
|
||||
Webhook(name='Webhook 1', type_create=True, payload_url=DUMMY_URL, secret=DUMMY_SECRET, additional_headers='X-Foo: Bar'),
|
||||
@@ -259,7 +259,7 @@ class WebhookTest(APITestCase):
|
||||
name='Conditional Webhook',
|
||||
type_create=True,
|
||||
type_update=True,
|
||||
payload_url='http://localhost/',
|
||||
payload_url='http://localhost:9000/',
|
||||
conditions={
|
||||
'and': [
|
||||
{
|
||||
|
||||
@@ -591,6 +591,10 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||
method='_assigned_to_interface',
|
||||
label=_('Is assigned to an interface'),
|
||||
)
|
||||
assigned = django_filters.BooleanFilter(
|
||||
method='_assigned',
|
||||
label=_('Is assigned'),
|
||||
)
|
||||
status = django_filters.MultipleChoiceFilter(
|
||||
choices=IPAddressStatusChoices,
|
||||
null_value=None
|
||||
@@ -706,6 +710,18 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||
assigned_object_id__isnull=False
|
||||
)
|
||||
|
||||
def _assigned(self, queryset, name, value):
|
||||
if value:
|
||||
return queryset.exclude(
|
||||
assigned_object_type__isnull=True,
|
||||
assigned_object_id__isnull=True
|
||||
)
|
||||
else:
|
||||
return queryset.filter(
|
||||
assigned_object_type__isnull=True,
|
||||
assigned_object_id__isnull=True
|
||||
)
|
||||
|
||||
|
||||
class FHRPGroupFilterSet(NetBoxModelFilterSet):
|
||||
protocol = django_filters.MultipleChoiceFilter(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from django import forms
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Q
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.models import Device, Interface, Site
|
||||
@@ -10,7 +9,9 @@ from ipam.constants import *
|
||||
from ipam.models import *
|
||||
from netbox.forms import NetBoxModelImportForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms.fields import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, SlugField
|
||||
from utilities.forms.fields import (
|
||||
CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, SlugField
|
||||
)
|
||||
from virtualization.models import VirtualMachine, VMInterface
|
||||
|
||||
__all__ = (
|
||||
@@ -42,10 +43,25 @@ class VRFImportForm(NetBoxModelImportForm):
|
||||
to_field_name='name',
|
||||
help_text=_('Assigned tenant')
|
||||
)
|
||||
import_targets = CSVModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
help_text=_('Import route targets')
|
||||
)
|
||||
export_targets = CSVModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False,
|
||||
to_field_name='name',
|
||||
help_text=_('Export route targets')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = ('name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments', 'tags')
|
||||
fields = (
|
||||
'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'comments',
|
||||
'tags',
|
||||
)
|
||||
|
||||
|
||||
class RouteTargetImportForm(NetBoxModelImportForm):
|
||||
|
||||
@@ -992,6 +992,12 @@ class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
params = {'fhrpgroup_id': [fhrp_groups[0].pk, fhrp_groups[1].pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_assigned(self):
|
||||
params = {'assigned': 'true'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 8)
|
||||
params = {'assigned': 'false'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||
|
||||
def test_assigned_to_interface(self):
|
||||
params = {'assigned_to_interface': 'true'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
||||
|
||||
@@ -216,7 +216,7 @@ class ASNRangeASNsView(generic.ObjectChildrenView):
|
||||
child_model = ASN
|
||||
table = tables.ASNTable
|
||||
filterset = filtersets.ASNFilterSet
|
||||
template_name = 'ipam/asnrange/asns.html'
|
||||
template_name = 'generic/object_children.html'
|
||||
tab = ViewTab(
|
||||
label=_('ASNs'),
|
||||
badge=lambda x: x.get_child_asns().count(),
|
||||
@@ -816,7 +816,6 @@ class IPAddressAssignView(generic.ObjectView):
|
||||
table = None
|
||||
|
||||
if form.is_valid():
|
||||
|
||||
addresses = self.queryset.prefetch_related('vrf', 'tenant')
|
||||
# Limit to 100 results
|
||||
addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
|
||||
@@ -866,7 +865,7 @@ class IPAddressRelatedIPsView(generic.ObjectChildrenView):
|
||||
child_model = IPAddress
|
||||
table = tables.IPAddressTable
|
||||
filterset = filtersets.IPAddressFilterSet
|
||||
template_name = 'ipam/ipaddress/ip_addresses.html'
|
||||
template_name = 'generic/object_children.html'
|
||||
tab = ViewTab(
|
||||
label=_('Related IPs'),
|
||||
badge=lambda x: x.get_related_ips().count(),
|
||||
@@ -963,7 +962,6 @@ class FHRPGroupView(generic.ObjectView):
|
||||
queryset = FHRPGroup.objects.all()
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
|
||||
# Get assigned interfaces
|
||||
members_table = tables.FHRPGroupAssignmentTable(
|
||||
data=FHRPGroupAssignment.objects.restrict(request.user, 'view').filter(group=instance),
|
||||
@@ -1077,7 +1075,7 @@ class VLANInterfacesView(generic.ObjectChildrenView):
|
||||
child_model = Interface
|
||||
table = tables.VLANDevicesTable
|
||||
filterset = InterfaceFilterSet
|
||||
template_name = 'ipam/vlan/interfaces.html'
|
||||
template_name = 'generic/object_children.html'
|
||||
tab = ViewTab(
|
||||
label=_('Device Interfaces'),
|
||||
badge=lambda x: x.get_interfaces().count(),
|
||||
@@ -1095,7 +1093,7 @@ class VLANVMInterfacesView(generic.ObjectChildrenView):
|
||||
child_model = VMInterface
|
||||
table = tables.VLANVirtualMachinesTable
|
||||
filterset = VMInterfaceFilterSet
|
||||
template_name = 'ipam/vlan/vminterfaces.html'
|
||||
template_name = 'generic/object_children.html'
|
||||
tab = ViewTab(
|
||||
label=_('VM Interfaces'),
|
||||
badge=lambda x: x.get_vminterfaces().count(),
|
||||
|
||||
@@ -11,6 +11,7 @@ from rest_framework.reverse import reverse
|
||||
from rest_framework.views import APIView
|
||||
from rq.worker import Worker
|
||||
|
||||
from extras.plugins.utils import get_installed_plugins
|
||||
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
|
||||
|
||||
|
||||
@@ -61,19 +62,11 @@ class StatusView(APIView):
|
||||
installed_apps[app_config.name] = version
|
||||
installed_apps = {k: v for k, v in sorted(installed_apps.items())}
|
||||
|
||||
# Gather installed plugins
|
||||
plugins = {}
|
||||
for plugin_name in settings.PLUGINS:
|
||||
plugin_name = plugin_name.rsplit('.', 1)[-1]
|
||||
plugin_config = apps.get_app_config(plugin_name)
|
||||
plugins[plugin_name] = getattr(plugin_config, 'version', None)
|
||||
plugins = {k: v for k, v in sorted(plugins.items())}
|
||||
|
||||
return Response({
|
||||
'django-version': DJANGO_VERSION,
|
||||
'installed-apps': installed_apps,
|
||||
'netbox-version': settings.VERSION,
|
||||
'plugins': plugins,
|
||||
'plugins': get_installed_plugins(),
|
||||
'python-version': platform.python_version(),
|
||||
'rq-workers-running': Worker.count(get_connection('default')),
|
||||
})
|
||||
|
||||
@@ -88,7 +88,10 @@ class NetBoxModelImportForm(CSVModelForm, NetBoxModelForm):
|
||||
|
||||
def _get_custom_fields(self, content_type):
|
||||
return CustomField.objects.filter(content_types=content_type).filter(
|
||||
ui_visibility=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE
|
||||
ui_visibility__in=[
|
||||
CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE,
|
||||
CustomFieldVisibilityChoices.VISIBILITY_HIDDEN_IFUNSET,
|
||||
]
|
||||
)
|
||||
|
||||
def _get_form_field(self, customfield):
|
||||
|
||||
@@ -491,6 +491,19 @@ class SyncedDataMixin(models.Model):
|
||||
|
||||
return ret
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
from core.models import AutoSyncRecord
|
||||
|
||||
# Delete AutoSyncRecord
|
||||
content_type = ContentType.objects.get_for_model(self)
|
||||
AutoSyncRecord.objects.filter(
|
||||
datafile=self.data_file,
|
||||
object_type=content_type,
|
||||
object_id=self.pk
|
||||
).delete()
|
||||
|
||||
return super().delete(*args, **kwargs)
|
||||
|
||||
def resolve_data_file(self):
|
||||
"""
|
||||
Determine the designated DataFile object identified by its parent DataSource and its path. Returns None if
|
||||
|
||||
@@ -474,8 +474,6 @@ LOGIN_REDIRECT_URL = f'/{BASE_PATH}'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
|
||||
TEST_RUNNER = "django_rich.test.RichRunner"
|
||||
|
||||
# Exclude potentially sensitive models from wildcard view exemption. These may still be exempted
|
||||
# by specifying the model individually in the EXEMPT_VIEW_PERMISSIONS configuration parameter.
|
||||
EXEMPT_EXCLUDE_MODELS = (
|
||||
|
||||
@@ -54,7 +54,7 @@ class BaseTable(tables.Table):
|
||||
# 3. Meta.fields
|
||||
selected_columns = None
|
||||
if user is not None and not isinstance(user, AnonymousUser):
|
||||
selected_columns = user.config.get(f"tables.{self.__class__.__name__}.columns")
|
||||
selected_columns = user.config.get(f"tables.{self.name}.columns")
|
||||
if not selected_columns:
|
||||
selected_columns = getattr(self.Meta, 'default_columns', self.Meta.fields)
|
||||
|
||||
@@ -113,6 +113,10 @@ class BaseTable(tables.Table):
|
||||
columns.append((name, column.verbose_name))
|
||||
return columns
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.__class__.__name__
|
||||
|
||||
@property
|
||||
def available_columns(self):
|
||||
return self._get_columns(visible=False)
|
||||
@@ -138,17 +142,16 @@ class BaseTable(tables.Table):
|
||||
"""
|
||||
# Save ordering preference
|
||||
if request.user.is_authenticated:
|
||||
table_name = self.__class__.__name__
|
||||
if self.prefixed_order_by_field in request.GET:
|
||||
if request.GET[self.prefixed_order_by_field]:
|
||||
# If an ordering has been specified as a query parameter, save it as the
|
||||
# user's preferred ordering for this table.
|
||||
ordering = request.GET.getlist(self.prefixed_order_by_field)
|
||||
request.user.config.set(f'tables.{table_name}.ordering', ordering, commit=True)
|
||||
request.user.config.set(f'tables.{self.name}.ordering', ordering, commit=True)
|
||||
else:
|
||||
# If the ordering has been set to none (empty), clear any existing preference.
|
||||
request.user.config.clear(f'tables.{table_name}.ordering', commit=True)
|
||||
elif ordering := request.user.config.get(f'tables.{table_name}.ordering'):
|
||||
request.user.config.clear(f'tables.{self.name}.ordering', commit=True)
|
||||
elif ordering := request.user.config.get(f'tables.{self.name}.ordering'):
|
||||
# If no ordering has been specified, set the preferred ordering (if any).
|
||||
self.order_by = ordering
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ from django.views.defaults import ERROR_500_TEMPLATE_NAME, page_not_found
|
||||
from django.views.generic import View
|
||||
from sentry_sdk import capture_message
|
||||
|
||||
from extras.plugins.utils import get_installed_plugins
|
||||
|
||||
__all__ = (
|
||||
'handler_404',
|
||||
'handler_500',
|
||||
@@ -53,4 +55,5 @@ def handler_500(request, template_name=ERROR_500_TEMPLATE_NAME):
|
||||
'exception': str(type_),
|
||||
'netbox_version': settings.VERSION,
|
||||
'python_version': platform.python_version(),
|
||||
'plugins': get_installed_plugins(),
|
||||
}))
|
||||
|
||||
@@ -143,9 +143,12 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
|
||||
return render(request, self.get_template_name(), {
|
||||
'object': instance,
|
||||
'child_model': self.child_model,
|
||||
'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html',
|
||||
'table': table,
|
||||
'table_config': f'{table.name}_config',
|
||||
'actions': actions,
|
||||
'tab': self.tab,
|
||||
'return_url': request.get_full_path(),
|
||||
**self.get_extra_context(request, instance),
|
||||
})
|
||||
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
{{ error }}
|
||||
|
||||
{% trans "Python version" %}: {{ python_version }}
|
||||
{% trans "NetBox version" %}: {{ netbox_version }}</pre>
|
||||
{% trans "NetBox version" %}: {{ netbox_version }}
|
||||
{% trans "Plugins" %}: {% for plugin, version in plugins.items %}
|
||||
{{ plugin }}: {{ version }}{% empty %}{% trans "None installed" %}{% endfor %}
|
||||
</pre>
|
||||
<p>
|
||||
{% trans "If further assistance is required, please post to the" %} <a href="https://github.com/netbox-community/netbox/discussions">{% trans "NetBox discussion forum" %}</a> {% trans "on GitHub" %}.
|
||||
</p>
|
||||
|
||||
15
netbox/templates/dcim/device/components_base.html
Normal file
15
netbox/templates/dcim/device/components_base.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block bulk_edit_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_rename_view=child_model|validated_viewname:"bulk_rename" %}
|
||||
{% if 'bulk_rename' in actions and bulk_rename_view %}
|
||||
<button type="submit" name="_rename"
|
||||
formaction="{% url bulk_rename_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> Rename
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_edit_controls %}
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsolePortTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:consoleport_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleports' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:consoleport_bulk_rename' %}?return_url={% url 'dcim:device_consoleports' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:consoleport_bulk_delete' %}?return_url={% url 'dcim:device_consoleports' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:consoleport_bulk_disconnect' %}?return_url={% url 'dcim:device_consoleports' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_consoleport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:consoleport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleports' pk=object.pk %}" class="btn btn-sm btn-primary">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Console Port" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_consoleport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:consoleport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleports' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Console Ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceConsoleServerPortTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:consoleserverport_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:consoleserverport_bulk_rename' %}?return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:consoleserverport_bulk_delete' %}?return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:consoleserverport_bulk_disconnect' %}?return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_consoleserverport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:consoleserverport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Console Server Ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_consoleserverport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:consoleserverport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_consoleserverports' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Console Server Ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
@@ -1,51 +1,14 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceDeviceBayTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:devicebay_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_devicebays' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:devicebay_bulk_rename' %}?return_url={% url 'dcim:device_devicebays' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:devicebay_bulk_delete' %}?return_url={% url 'dcim:device_devicebays' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.dcim.add_devicebay %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_devicebay %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:devicebay_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_devicebays' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Device Bays" %}
|
||||
</a>
|
||||
<a href="{% url 'dcim:devicebay_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_devicebays' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Device Bays" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceFrontPortTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:frontport_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_frontports' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:frontport_bulk_rename' %}?return_url={% url 'dcim:device_frontports' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:frontport_bulk_delete' %}?return_url={% url 'dcim:device_frontports' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:frontport_bulk_disconnect' %}?return_url={% url 'dcim:device_frontports' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_frontport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:frontport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_frontports' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add front ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_frontport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:frontport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_frontports' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Front Ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,67 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'dcim/device/inc/interface_table_controls.html' with table_modal="DeviceInterfaceTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit"
|
||||
formaction="{% url 'dcim:interface_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename"
|
||||
formaction="{% url 'dcim:interface_bulk_rename' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete"
|
||||
formaction="{% url 'dcim:interface_bulk_delete' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url 'dcim:interface_bulk_disconnect' %}?return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_interface %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:interface_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Interfaces" %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:interface_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_interfaces' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Interfaces" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,51 +1,14 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceInventoryItemTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:inventoryitem_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_inventory' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:inventoryitem_bulk_rename' %}?return_url={% url 'dcim:device_inventory' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:inventoryitem_bulk_delete' %}?return_url={% url 'dcim:device_inventory' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.dcim.add_inventoryitem %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_inventoryitem %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:inventoryitem_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_inventory' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Inventory Item" %}
|
||||
</a>
|
||||
<a href="{% url 'dcim:inventoryitem_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_inventory' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Inventory Item" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,47 +1,14 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceModuleBayTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:modulebay_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_modulebays' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:modulebay_bulk_rename' %}?return_url={% url 'dcim:device_modulebays' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:modulebay_bulk_delete' %}?return_url={% url 'dcim:device_modulebays' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.dcim.add_modulebay %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_modulebay %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:modulebay_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_modulebays' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Module Bays" %}
|
||||
</a>
|
||||
<a href="{% url 'dcim:modulebay_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_modulebays' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Module Bays" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% table_config_form table %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerOutletTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:poweroutlet_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:poweroutlet_bulk_rename' %}?return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:poweroutlet_bulk_delete' %}?return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:poweroutlet_bulk_disconnect' %}?return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_poweroutlet %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:poweroutlet_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Power Outlets" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_poweroutlet %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:poweroutlet_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_poweroutlets' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Power Outlets" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DevicePowerPortTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:powerport_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_powerports' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:powerport_bulk_rename' %}?return_url={% url 'dcim:device_powerports' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'dcim:powerport_bulk_delete' %}?return_url={% url 'dcim:device_powerports' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:powerport_bulk_disconnect' %}?return_url={% url 'dcim:device_powerports' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_powerport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:powerport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_powerports' pk=object.pk %}" class="btn btn-sm btn-primary">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Power Port" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_powerport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:powerport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_powerports' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Power Port" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
|
||||
@@ -1,58 +1,28 @@
|
||||
{% extends 'dcim/device/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load static %}
|
||||
{% extends 'dcim/device/components_base.html' %}
|
||||
{% load helpers %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceRearPortTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:rearport_bulk_edit' %}?device={{ object.pk }}&return_url={% url 'dcim:device_rearports' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% with bulk_disconnect_view=child_model|validated_viewname:"bulk_disconnect" %}
|
||||
{% if 'bulk_disconnect' in actions and bulk_disconnect_view %}
|
||||
<button type="submit" name="_disconnect"
|
||||
formaction="{% url bulk_disconnect_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'dcim:rearport_bulk_rename' %}?return_url={% url 'dcim:device_rearports' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group" role="group">
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:rearport_bulk_delete' %}?return_url={% url 'dcim:device_rearports' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_disconnect" formaction="{% url 'dcim:rearport_bulk_disconnect' %}?return_url={% url 'dcim:device_rearports' pk=object.pk %}" class="btn btn-outline-danger btn-sm">
|
||||
<span class="mdi mdi-ethernet-cable-off" aria-hidden="true"></span> {% trans "Disconnect" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if perms.dcim.add_rearport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:rearport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_rearports' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add rear ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_extra_controls %}
|
||||
{{ block.super }}
|
||||
{% if perms.dcim.add_rearport %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:rearport_add' %}?device={{ object.pk }}&return_url={% url 'dcim:device_rearports' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Rear Ports" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock bulk_extra_controls %}
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends 'dcim/rack/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
|
||||
{% block extra_controls %}
|
||||
{% if perms.dcim.add_device %}
|
||||
@@ -10,42 +9,4 @@
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit"
|
||||
formaction="{% url 'dcim:device_bulk_edit' %}?return_url={% url 'dcim:rack_nonracked_devices' pk=object.pk %}"
|
||||
class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit"
|
||||
formaction="{% url 'dcim:device_bulk_delete' %}?return_url={% url 'dcim:rack_nonracked_devices' pk=object.pk %}"
|
||||
class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,44 +1,13 @@
|
||||
{% extends 'dcim/rack/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="RackReservationTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'dcim:rackreservation_bulk_edit' %}?return_url={% url 'dcim:rack_reservations' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" formaction="{% url 'dcim:rackreservation_bulk_delete' %}?return_url={% url 'dcim:rack_reservations' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if perms.dcim.add_rackreservation %}
|
||||
{% block extra_controls %}
|
||||
{% if perms.dcim.add_rackreservation %}
|
||||
<div class="bulk-button-group">
|
||||
<a href="{% url 'dcim:rackreservation_add' %}?rack={{ object.pk }}&return_url={% url 'dcim:rack_reservations' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add reservation" %}
|
||||
</a>
|
||||
<a href="{% url 'dcim:rackreservation_add' %}?rack={{ object.pk }}&return_url={% url 'dcim:rack_reservations' pk=object.pk %}"
|
||||
class="btn btn-primary btn-sm">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add reservation" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endif %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
57
netbox/templates/generic/object_children.html
Normal file
57
netbox/templates/generic/object_children.html
Normal file
@@ -0,0 +1,57 @@
|
||||
{% extends base_template %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal=table_config %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="noprint bulk-buttons">
|
||||
{% block bulk_controls %}
|
||||
<div class="bulk-button-group">
|
||||
<div class="btn-group" role="group">
|
||||
{# Bulk edit buttons #}
|
||||
{% block bulk_edit_controls %}
|
||||
{% with bulk_edit_view=child_model|validated_viewname:"bulk_edit" %}
|
||||
{% if 'bulk_edit' in actions and bulk_edit_view %}
|
||||
<button type="submit" name="_edit"
|
||||
formaction="{% url bulk_edit_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_edit_controls %}
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
{# Bulk delete buttons #}
|
||||
{% block bulk_delete_controls %}
|
||||
{% with bulk_delete_view=child_model|validated_viewname:"bulk_delete" %}
|
||||
{% if 'bulk_delete' in actions and bulk_delete_view %}
|
||||
<button type="submit"
|
||||
formaction="{% url bulk_delete_view %}?return_url={{ return_url }}"
|
||||
class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="bulk-button-group">
|
||||
{# Other bulk action buttons #}
|
||||
{% block bulk_extra_controls %}{% endblock %}
|
||||
</div>
|
||||
{% endblock bulk_controls %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends 'ipam/aggregate/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_controls %}
|
||||
@@ -10,38 +9,4 @@
|
||||
</a>
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:prefix_bulk_edit' %}?return_url={% url 'ipam:aggregate_prefixes' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:prefix_bulk_delete' %}?return_url={% url 'ipam:aggregate_prefixes' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
{% extends 'ipam/asnrange/base.html' %}
|
||||
{% load helpers %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="ASNTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:asn_bulk_edit' %}?return_url={% url 'ipam:asnrange_asns' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:asn_bulk_delete' %}?return_url={% url 'ipam:asnrange_asns' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,19 +0,0 @@
|
||||
{% extends 'ipam/ipaddress/base.html' %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,45 +1,10 @@
|
||||
{% extends 'ipam/iprange/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_controls %}
|
||||
{% if perms.ipam.add_ipaddress and active_tab == 'ip-addresses' and object.first_available_ip %}
|
||||
{% if perms.ipam.add_ipaddress and object.first_available_ip %}
|
||||
<a href="{% url 'ipam:ipaddress_add' %}?address={{ object.first_available_ip }}&vrf={{ object.vrf.pk }}&tenant_group={{ object.tenant.group.pk }}&tenant={{ object.tenant.pk }}" class="btn btn-sm btn-primary">
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add IP Address" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:ipaddress_bulk_edit' %}?return_url={% url 'ipam:iprange_ipaddresses' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:ipaddress_bulk_delete' %}?return_url={% url 'ipam:iprange_ipaddresses' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends 'ipam/prefix/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_controls %}
|
||||
@@ -8,38 +7,4 @@
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add IP Address" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="IPAddressTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:ipaddress_bulk_edit' %}?return_url={% url 'ipam:prefix_ipaddresses' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:ipaddress_bulk_delete' %}?return_url={% url 'ipam:prefix_ipaddresses' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends 'ipam/prefix/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_controls %}
|
||||
@@ -8,38 +7,4 @@
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add IP Range" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="IPRangeTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:iprange_bulk_edit' %}?return_url={% url 'ipam:prefix_ipranges' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:iprange_bulk_delete' %}?return_url={% url 'ipam:prefix_ipranges' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% extends 'ipam/prefix/base.html' %}
|
||||
{% load helpers %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block extra_controls %}
|
||||
@@ -9,39 +8,4 @@
|
||||
<i class="mdi mdi-plus-thick" aria-hidden="true"></i> {% trans "Add Prefix" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="PrefixTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'ipam:prefix_bulk_edit' %}?return_url={% url 'ipam:prefix_prefixes' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'ipam:prefix_bulk_delete' %}?return_url={% url 'ipam:prefix_prefixes' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endblock extra_controls %}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
{% extends 'ipam/vlan/base.html' %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="VLANDevicesTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,20 +0,0 @@
|
||||
{% extends 'ipam/vlan/base.html' %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="VLANVirtualMachinesTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends base_template %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load helpers %}
|
||||
{% load i18n %}
|
||||
|
||||
@@ -11,20 +11,3 @@
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="ContactAssignmentTable_config" %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
|
||||
@@ -1,31 +1,13 @@
|
||||
{% extends 'virtualization/cluster/base.html' %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="DeviceTable_config" %}
|
||||
|
||||
<form action="{% url 'virtualization:cluster_remove_devices' pk=object.pk %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if perms.virtualization.change_cluster %}
|
||||
<button type="submit" name="_remove" class="btn btn-danger btn-sm">
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> {% trans "Remove Devices" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% block bulk_delete_controls %}
|
||||
{{ block.super }}
|
||||
{% if 'bulk_remove_devices' in actions %}
|
||||
<button type="submit" name="_remove"
|
||||
formaction="{% url 'virtualization:cluster_remove_devices' pk=object.pk %}?return_url={{ return_url }}"
|
||||
class="btn btn-danger btn-sm">
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> {% trans "Remove Selected" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endblock bulk_delete_controls %}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
{% extends 'virtualization/cluster/base.html' %}
|
||||
{% load helpers %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="noprint bulk-buttons">
|
||||
<div class="bulk-button-group">
|
||||
{% if 'bulk_edit' in actions %}
|
||||
<button type="submit" name="_edit" formaction="{% url 'virtualization:virtualmachine_bulk_edit' %}?return_url={% url 'virtualization:cluster_virtualmachines' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> {% trans "Edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if 'bulk_delete' in actions %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'virtualization:virtualmachine_bulk_delete' %}?return_url={% url 'virtualization:cluster_virtualmachines' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> {% trans "Delete" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
@@ -1,48 +1,14 @@
|
||||
{% extends 'virtualization/virtualmachine/base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% extends 'generic/object_children.html' %}
|
||||
{% load helpers %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% include 'inc/table_controls_htmx.html' with table_modal="VirtualMachineVMInterfaceTable_config" %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="card">
|
||||
<div class="card-body htmx-container table-responsive" id="object_list">
|
||||
{% include 'htmx/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="noprint">
|
||||
{% if perms.virtualization.change_vminterface %}
|
||||
<div class="btn-group" role="group">
|
||||
<button type="submit" name="_edit" formaction="{% url 'virtualization:vminterface_bulk_edit' %}?virtual_machine={{ object.pk }}&return_url={% url 'virtualization:virtualmachine_interfaces' pk=object.pk %}" class="btn btn-warning btn-sm">
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> {% trans "Edit" %}
|
||||
</button>
|
||||
<button type="submit" name="_rename" formaction="{% url 'virtualization:vminterface_bulk_rename' %}?return_url={% url 'virtualization:virtualmachine_interfaces' pk=object.pk %}" class="btn btn-outline-warning btn-sm">
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> {% trans "Rename" %}
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if perms.virtualization.delete_vminterface %}
|
||||
<button type="submit" name="_delete" formaction="{% url 'virtualization:vminterface_bulk_delete' %}?return_url={% url 'virtualization:virtualmachine_interfaces' pk=object.pk %}" class="btn btn-danger btn-sm">
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> {% trans "Delete" %}
|
||||
{% block bulk_edit_controls %}
|
||||
{{ block.super }}
|
||||
{% if 'bulk_rename' in actions %}
|
||||
<button type="submit" name="_rename"
|
||||
formaction="{% url 'virtualization:vminterface_bulk_rename' %}?return_url={{ return_url }}"
|
||||
class="btn btn-outline-warning btn-sm">
|
||||
<i class="mdi mdi-pencil-outline" aria-hidden="true"></i> {% trans "Rename" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if perms.virtualization.add_vminterface %}
|
||||
<div class="float-end">
|
||||
<a href="{% url 'virtualization:vminterface_add' %}?virtual_machine={{ object.pk }}&return_url={% url 'virtualization:virtualmachine_interfaces' pk=object.pk %}" class="btn btn-primary btn-sm">
|
||||
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% trans "Add interfaces" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endblock content %}
|
||||
|
||||
{% block modals %}
|
||||
{{ block.super }}
|
||||
{% table_config_form table %}
|
||||
{% endblock modals %}
|
||||
{% endif %}
|
||||
{% endblock bulk_edit_controls %}
|
||||
|
||||
@@ -41,11 +41,6 @@ class ObjectContactsView(generic.ObjectChildrenView):
|
||||
|
||||
return table
|
||||
|
||||
def get_extra_context(self, request, instance):
|
||||
return {
|
||||
'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html',
|
||||
}
|
||||
|
||||
#
|
||||
# Tenant groups
|
||||
#
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from collections import defaultdict
|
||||
|
||||
from django.contrib import messages
|
||||
from django.db import transaction
|
||||
from django.db.models import Prefetch, Sum
|
||||
@@ -175,7 +177,7 @@ class ClusterVirtualMachinesView(generic.ObjectChildrenView):
|
||||
child_model = VirtualMachine
|
||||
table = tables.VirtualMachineTable
|
||||
filterset = filtersets.VirtualMachineFilterSet
|
||||
template_name = 'virtualization/cluster/virtual_machines.html'
|
||||
template_name = 'generic/object_children.html'
|
||||
tab = ViewTab(
|
||||
label=_('Virtual Machines'),
|
||||
badge=lambda obj: obj.virtual_machines.count(),
|
||||
@@ -194,6 +196,13 @@ class ClusterDevicesView(generic.ObjectChildrenView):
|
||||
table = DeviceTable
|
||||
filterset = DeviceFilterSet
|
||||
template_name = 'virtualization/cluster/devices.html'
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_remove_devices')
|
||||
action_perms = defaultdict(set, **{
|
||||
'add': {'add'},
|
||||
'import': {'add'},
|
||||
'bulk_edit': {'change'},
|
||||
'bulk_remove_devices': {'change'},
|
||||
})
|
||||
tab = ViewTab(
|
||||
label=_('Devices'),
|
||||
badge=lambda obj: obj.devices.count(),
|
||||
@@ -353,6 +362,14 @@ class VirtualMachineInterfacesView(generic.ObjectChildrenView):
|
||||
permission='virtualization.view_vminterface',
|
||||
weight=500
|
||||
)
|
||||
actions = ('add', 'import', 'export', 'bulk_edit', 'bulk_delete', 'bulk_rename')
|
||||
action_perms = defaultdict(set, **{
|
||||
'add': {'add'},
|
||||
'import': {'add'},
|
||||
'bulk_edit': {'change'},
|
||||
'bulk_delete': {'delete'},
|
||||
'bulk_rename': {'change'},
|
||||
})
|
||||
|
||||
def get_children(self, request, parent):
|
||||
return parent.interfaces.restrict(request.user, 'view').prefetch_related(
|
||||
|
||||
Reference in New Issue
Block a user