mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 09:16:10 -06:00
Merge branch 'develop' into 10201-cable-terminations2
This commit is contained in:
commit
4bee634d7c
@ -63,6 +63,7 @@ Redis is configured using a configuration setting similar to `DATABASE` and thes
|
||||
|
||||
* `HOST` - Name or IP address of the Redis server (use `localhost` if running locally)
|
||||
* `PORT` - TCP port of the Redis service; leave blank for default port (6379)
|
||||
* `USERNAME` - Redis username (if set)
|
||||
* `PASSWORD` - Redis password (if set)
|
||||
* `DATABASE` - Numeric database ID
|
||||
* `SSL` - Use SSL connection to Redis
|
||||
@ -75,6 +76,7 @@ REDIS = {
|
||||
'tasks': {
|
||||
'HOST': 'redis.example.com',
|
||||
'PORT': 1234,
|
||||
'USERNAME': 'netbox'
|
||||
'PASSWORD': 'foobar',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
@ -82,6 +84,7 @@ REDIS = {
|
||||
'caching': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
'USERNAME': ''
|
||||
'PASSWORD': '',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
|
@ -7,15 +7,19 @@
|
||||
* [#9285](https://github.com/netbox-community/netbox/issues/9285) - Enable specifying assigned component during bulk import of inventory items
|
||||
* [#10700](https://github.com/netbox-community/netbox/issues/10700) - Match device name when using modules quick search
|
||||
* [#11121](https://github.com/netbox-community/netbox/issues/11121) - Add VM resource totals to cluster view
|
||||
* [#11156](https://github.com/netbox-community/netbox/issues/11156) - Enable selecting assigned component when editing inventory item in UI
|
||||
* [#11223](https://github.com/netbox-community/netbox/issues/11223) - `reindex` management command should accept app label without model name
|
||||
* [#11244](https://github.com/netbox-community/netbox/issues/11244) - Add controls for saved filters to rack elevations list
|
||||
* [#11248](https://github.com/netbox-community/netbox/issues/11248) - Fix database migration when plugin with search indexer is enabled
|
||||
* [#11259](https://github.com/netbox-community/netbox/issues/11259) - Add support for Redis username configuration
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* [#11280](https://github.com/netbox-community/netbox/issues/11280) - Fix errant newlines when exporting interfaces with multiple IP addresses assigned
|
||||
* [#11290](https://github.com/netbox-community/netbox/issues/11290) - Correct reporting of scheduled job duration
|
||||
* [#11232](https://github.com/netbox-community/netbox/issues/11232) - Enable partial & regular expression matching for non-string types in global search
|
||||
* [#11342](https://github.com/netbox-community/netbox/issues/11342) - Correct cable trace URL under "connection" tab for device components
|
||||
* [#11345](https://github.com/netbox-community/netbox/issues/11345) - Fix form validation for bulk import of modules
|
||||
|
||||
---
|
||||
|
||||
|
@ -56,8 +56,8 @@ class ModuleCommonForm(forms.Form):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
replicate_components = self.cleaned_data.get("replicate_components")
|
||||
adopt_components = self.cleaned_data.get("adopt_components")
|
||||
replicate_components = self.cleaned_data.get('replicate_components')
|
||||
adopt_components = self.cleaned_data.get('adopt_components')
|
||||
device = self.cleaned_data.get('device')
|
||||
module_type = self.cleaned_data.get('module_type')
|
||||
module_bay = self.cleaned_data.get('module_bay')
|
||||
@ -65,8 +65,9 @@ class ModuleCommonForm(forms.Form):
|
||||
if adopt_components:
|
||||
self.instance._adopt_components = True
|
||||
|
||||
# Bail out if we are not installing a new module or if we are not replicating components
|
||||
if self.instance.pk or not replicate_components:
|
||||
# Bail out if we are not installing a new module or if we are not replicating components (or if
|
||||
# validation has already failed)
|
||||
if self.errors or self.instance.pk or not replicate_components:
|
||||
self.instance._disable_replication = True
|
||||
return
|
||||
|
||||
|
@ -1549,15 +1549,63 @@ class InventoryItemForm(DeviceComponentForm):
|
||||
queryset=Manufacturer.objects.all(),
|
||||
required=False
|
||||
)
|
||||
component_type = ContentTypeChoiceField(
|
||||
queryset=ContentType.objects.all(),
|
||||
limit_choices_to=MODULAR_COMPONENT_MODELS,
|
||||
|
||||
# Assigned component selectors
|
||||
consoleport = DynamicModelChoiceField(
|
||||
queryset=ConsolePort.objects.all(),
|
||||
required=False,
|
||||
widget=forms.HiddenInput
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Console port')
|
||||
)
|
||||
component_id = forms.IntegerField(
|
||||
consoleserverport = DynamicModelChoiceField(
|
||||
queryset=ConsoleServerPort.objects.all(),
|
||||
required=False,
|
||||
widget=forms.HiddenInput
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Console server port')
|
||||
)
|
||||
frontport = DynamicModelChoiceField(
|
||||
queryset=FrontPort.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Front port')
|
||||
)
|
||||
interface = DynamicModelChoiceField(
|
||||
queryset=Interface.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Interface')
|
||||
)
|
||||
poweroutlet = DynamicModelChoiceField(
|
||||
queryset=PowerOutlet.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Power outlet')
|
||||
)
|
||||
powerport = DynamicModelChoiceField(
|
||||
queryset=PowerPort.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Power port')
|
||||
)
|
||||
rearport = DynamicModelChoiceField(
|
||||
queryset=RearPort.objects.all(),
|
||||
required=False,
|
||||
query_params={
|
||||
'device_id': '$device'
|
||||
},
|
||||
label=_('Rear port')
|
||||
)
|
||||
|
||||
fieldsets = (
|
||||
@ -1565,22 +1613,61 @@ class InventoryItemForm(DeviceComponentForm):
|
||||
('Hardware', ('manufacturer', 'part_id', 'serial', 'asset_tag')),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = InventoryItem
|
||||
fields = [
|
||||
'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
|
||||
'description', 'tags',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
instance = kwargs.get('instance')
|
||||
initial = kwargs.get('initial', {}).copy()
|
||||
component_type = initial.get('component_type')
|
||||
component_id = initial.get('component_id')
|
||||
|
||||
# Used for picking the default active tab for component selection
|
||||
self.no_component = True
|
||||
|
||||
if instance:
|
||||
# When editing set the initial value for component selectin
|
||||
for component_model in ContentType.objects.filter(MODULAR_COMPONENT_MODELS):
|
||||
if type(instance.component) is component_model.model_class():
|
||||
initial[component_model.model] = instance.component
|
||||
self.no_component = False
|
||||
break
|
||||
elif component_type and component_id:
|
||||
# When adding the InventoryItem from a component page
|
||||
if content_type := ContentType.objects.filter(MODULAR_COMPONENT_MODELS).filter(pk=component_type).first():
|
||||
if component := content_type.model_class().objects.filter(pk=component_id).first():
|
||||
initial[content_type.model] = component
|
||||
self.no_component = False
|
||||
|
||||
kwargs['initial'] = initial
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Specifically allow editing the device of IntentoryItems
|
||||
if self.instance.pk:
|
||||
self.fields['device'].disabled = False
|
||||
|
||||
class Meta:
|
||||
model = InventoryItem
|
||||
fields = [
|
||||
'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
|
||||
'description', 'component_type', 'component_id', 'tags',
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
# Handle object assignment
|
||||
selected_objects = [
|
||||
field for field in (
|
||||
'consoleport', 'consoleserverport', 'frontport', 'interface', 'poweroutlet', 'powerport', 'rearport'
|
||||
) if self.cleaned_data[field]
|
||||
]
|
||||
if len(selected_objects) > 1:
|
||||
raise forms.ValidationError("An InventoryItem can only be assigned to a single component.")
|
||||
elif selected_objects:
|
||||
self.instance.component = self.cleaned_data[selected_objects[0]]
|
||||
else:
|
||||
self.instance.component = None
|
||||
|
||||
|
||||
#
|
||||
# Device component roles
|
||||
#
|
||||
|
||||
|
@ -1146,3 +1146,8 @@ class InventoryItem(MPTTModel, ComponentModel):
|
||||
# When moving an InventoryItem to another device, remove any associated component
|
||||
if self.component and self.component.device != self.device:
|
||||
self.component = None
|
||||
else:
|
||||
if self.component and self.component.device != self.device:
|
||||
raise ValidationError({
|
||||
"device": "Cannot assign inventory item to component on another device"
|
||||
})
|
||||
|
@ -961,7 +961,7 @@ class Module(PrimaryModel, ConfigContextModel):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
|
||||
if self.module_bay.device != self.device:
|
||||
if hasattr(self, "module_bay") and (self.module_bay.device != self.device):
|
||||
raise ValidationError(
|
||||
f"Module must be installed within a module bay belonging to the assigned device ({self.device})."
|
||||
)
|
||||
|
@ -2914,23 +2914,14 @@ class InventoryItemView(generic.ObjectView):
|
||||
class InventoryItemEditView(generic.ObjectEditView):
|
||||
queryset = InventoryItem.objects.all()
|
||||
form = forms.InventoryItemForm
|
||||
template_name = 'dcim/inventoryitem_edit.html'
|
||||
|
||||
|
||||
class InventoryItemCreateView(generic.ComponentCreateView):
|
||||
queryset = InventoryItem.objects.all()
|
||||
form = forms.InventoryItemCreateForm
|
||||
model_form = forms.InventoryItemForm
|
||||
|
||||
def alter_object(self, instance, request):
|
||||
# Set component (if any)
|
||||
component_type = request.GET.get('component_type')
|
||||
component_id = request.GET.get('component_id')
|
||||
|
||||
if component_type and component_id:
|
||||
content_type = get_object_or_404(ContentType, pk=component_type)
|
||||
instance.component = get_object_or_404(content_type.model_class(), pk=component_id)
|
||||
|
||||
return instance
|
||||
template_name = 'dcim/inventoryitem_edit.html'
|
||||
|
||||
|
||||
@register_model_view(InventoryItem, 'delete')
|
||||
|
@ -31,6 +31,7 @@ REDIS = {
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'USERNAME': '',
|
||||
'PASSWORD': '',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
@ -44,6 +45,7 @@ REDIS = {
|
||||
# Comment out `HOST` and `PORT` lines and uncomment the following if using Redis Sentinel
|
||||
# 'SENTINELS': [('mysentinel.redis.example.com', 6379)],
|
||||
# 'SENTINEL_SERVICE': 'netbox',
|
||||
'USERNAME': '',
|
||||
'PASSWORD': '',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
|
@ -22,6 +22,7 @@ REDIS = {
|
||||
'tasks': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
'USERNAME': '',
|
||||
'PASSWORD': '',
|
||||
'DATABASE': 0,
|
||||
'SSL': False,
|
||||
@ -29,6 +30,7 @@ REDIS = {
|
||||
'caching': {
|
||||
'HOST': 'localhost',
|
||||
'PORT': 6379,
|
||||
'USERNAME': '',
|
||||
'PASSWORD': '',
|
||||
'DATABASE': 1,
|
||||
'SSL': False,
|
||||
|
@ -230,6 +230,7 @@ TASKS_REDIS_USING_SENTINEL = all([
|
||||
])
|
||||
TASKS_REDIS_SENTINEL_SERVICE = TASKS_REDIS.get('SENTINEL_SERVICE', 'default')
|
||||
TASKS_REDIS_SENTINEL_TIMEOUT = TASKS_REDIS.get('SENTINEL_TIMEOUT', 10)
|
||||
TASKS_REDIS_USERNAME = TASKS_REDIS.get('USERNAME', '')
|
||||
TASKS_REDIS_PASSWORD = TASKS_REDIS.get('PASSWORD', '')
|
||||
TASKS_REDIS_DATABASE = TASKS_REDIS.get('DATABASE', 0)
|
||||
TASKS_REDIS_SSL = TASKS_REDIS.get('SSL', False)
|
||||
@ -243,6 +244,8 @@ if 'caching' not in REDIS:
|
||||
CACHING_REDIS_HOST = REDIS['caching'].get('HOST', 'localhost')
|
||||
CACHING_REDIS_PORT = REDIS['caching'].get('PORT', 6379)
|
||||
CACHING_REDIS_DATABASE = REDIS['caching'].get('DATABASE', 0)
|
||||
CACHING_REDIS_USERNAME = REDIS['caching'].get('USERNAME', '')
|
||||
CACHING_REDIS_USERNAME_HOST = '@'.join(filter(None, [CACHING_REDIS_USERNAME, CACHING_REDIS_HOST]))
|
||||
CACHING_REDIS_PASSWORD = REDIS['caching'].get('PASSWORD', '')
|
||||
CACHING_REDIS_SENTINELS = REDIS['caching'].get('SENTINELS', [])
|
||||
CACHING_REDIS_SENTINEL_SERVICE = REDIS['caching'].get('SENTINEL_SERVICE', 'default')
|
||||
@ -252,7 +255,7 @@ CACHING_REDIS_SKIP_TLS_VERIFY = REDIS['caching'].get('INSECURE_SKIP_TLS_VERIFY',
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django_redis.cache.RedisCache',
|
||||
'LOCATION': f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_HOST}:{CACHING_REDIS_PORT}/{CACHING_REDIS_DATABASE}',
|
||||
'LOCATION': f'{CACHING_REDIS_PROTO}://{CACHING_REDIS_USERNAME_HOST}:{CACHING_REDIS_PORT}/{CACHING_REDIS_DATABASE}',
|
||||
'OPTIONS': {
|
||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
||||
'PASSWORD': CACHING_REDIS_PASSWORD,
|
||||
@ -640,6 +643,7 @@ else:
|
||||
}
|
||||
RQ_PARAMS.update({
|
||||
'DB': TASKS_REDIS_DATABASE,
|
||||
'USERNAME': TASKS_REDIS_USERNAME,
|
||||
'PASSWORD': TASKS_REDIS_PASSWORD,
|
||||
'DEFAULT_TIMEOUT': RQ_DEFAULT_TIMEOUT,
|
||||
})
|
||||
|
@ -60,7 +60,7 @@
|
||||
{% if object.mark_connected %}
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:consoleport_trace' %}
|
||||
{% else %}
|
||||
<div class="text-muted">
|
||||
Not Connected
|
||||
|
@ -60,7 +60,7 @@
|
||||
{% if object.mark_connected %}
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:consoleserverport_trace' %}
|
||||
{% else %}
|
||||
<div class="text-muted">
|
||||
Not Connected
|
||||
|
@ -3,7 +3,7 @@
|
||||
<th scope="row">Cable</th>
|
||||
<td>
|
||||
{{ object.cable|linkify }}
|
||||
<a href="{% url 'dcim:interface_trace' pk=object.pk %}" class="btn btn-primary btn-sm lh-1" title="Trace">
|
||||
<a href="{% url trace_url pk=object.pk %}" class="btn btn-primary btn-sm lh-1" title="Trace">
|
||||
<i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
@ -145,7 +145,7 @@
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||
</div>
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:interface_trace' %}
|
||||
{% elif object.wireless_link %}
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
|
106
netbox/templates/dcim/inventoryitem_edit.html
Normal file
106
netbox/templates/dcim/inventoryitem_edit.html
Normal file
@ -0,0 +1,106 @@
|
||||
{% extends 'generic/object_edit.html' %}
|
||||
{% load static %}
|
||||
{% load form_helpers %}
|
||||
{% load helpers %}
|
||||
|
||||
{% block form %}
|
||||
<div class="field-group my-5">
|
||||
<div class="row mb-2">
|
||||
<h5 class="offset-sm-3">InventoryItem</h5>
|
||||
</div>
|
||||
{% render_field form.device %}
|
||||
{% render_field form.parent %}
|
||||
{% render_field form.name %}
|
||||
{% render_field form.label %}
|
||||
{% render_field form.role %}
|
||||
{% render_field form.description %}
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
|
||||
<div class="field-group my-5">
|
||||
<div class="row mb-2">
|
||||
<h5 class="offset-sm-3">Hardware</h5>
|
||||
</div>
|
||||
{% render_field form.manufacturer %}
|
||||
{% render_field form.part_id %}
|
||||
{% render_field form.serial %}
|
||||
{% render_field form.asset_tag %}
|
||||
</div>
|
||||
|
||||
<div class="field-group my-5">
|
||||
<div class="row mb-2">
|
||||
<h5 class="offset-sm-3">Component Assignment</h5>
|
||||
</div>
|
||||
<div class="row mb-2 offset-sm-3">
|
||||
<ul class="nav nav-pills" role="tablist">
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="consoleport_tab" data-bs-toggle="tab" aria-controls="consoleport" data-bs-target="#consoleport" class="nav-link {% if form.initial.consoleport or form.no_component %}active{% endif %}">
|
||||
Console Port
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="consoleserverport_tab" data-bs-toggle="tab" aria-controls="consoleserverport" data-bs-target="#consoleserverport" class="nav-link {% if form.initial.consoleserverport %}active{% endif %}">
|
||||
Console Server Port
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="frontport_tab" data-bs-toggle="tab" aria-controls="frontport" data-bs-target="#frontport" class="nav-link {% if form.initial.frontport %}active{% endif %}">
|
||||
Front Port
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="interface_tab" data-bs-toggle="tab" aria-controls="interface" data-bs-target="#interface" class="nav-link {% if form.initial.interface %}active{% endif %}">
|
||||
Interface
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="poweroutlet_tab" data-bs-toggle="tab" aria-controls="poweroutlet" data-bs-target="#poweroutlet" class="nav-link {% if form.initial.poweroutlet %}active{% endif %}">
|
||||
Power Outlet
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="powerport_tab" data-bs-toggle="tab" aria-controls="powerport" data-bs-target="#powerport" class="nav-link {% if form.initial.powerport %}active{% endif %}">
|
||||
Power Port
|
||||
</button>
|
||||
</li>
|
||||
<li role="presentation" class="nav-item">
|
||||
<button role="tab" type="button" id="rearport_tab" data-bs-toggle="tab" aria-controls="rearport" data-bs-target="#rearport" class="nav-link {% if form.initial.rearport %}active{% endif %}">
|
||||
Rear Port
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="tab-content p-0 border-0">
|
||||
<div class="tab-pane {% if form.initial.consoleport or form.no_component %}active{% endif %}" id="consoleport" role="tabpanel" aria-labeled-by="consoleport_tab">
|
||||
{% render_field form.consoleport %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.consoleserverport %}active{% endif %}" id="consoleserverport" role="tabpanel" aria-labeled-by="consoleserverport_tab">
|
||||
{% render_field form.consoleserverport %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.frontport %}active{% endif %}" id="frontport" role="tabpanel" aria-labeled-by="frontport_tab">
|
||||
{% render_field form.frontport %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.interface %}active{% endif %}" id="interface" role="tabpanel" aria-labeled-by="interface_tab">
|
||||
{% render_field form.interface %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.poweroutlet %}active{% endif %}" id="poweroutlet" role="tabpanel" aria-labeled-by="poweroutlet_tab">
|
||||
{% render_field form.poweroutlet %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.powerport %}active{% endif %}" id="powerport" role="tabpanel" aria-labeled-by="powerport_tab">
|
||||
{% render_field form.powerport %}
|
||||
</div>
|
||||
<div class="tab-pane {% if form.initial.rearport %}active{% endif %}" id="rearport" role="tabpanel" aria-labeled-by="rearport_tab">
|
||||
{% render_field form.rearport %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if form.custom_fields %}
|
||||
<div class="field-group my-5">
|
||||
<div class="row mb-2">
|
||||
<h5 class="offset-sm-3">Custom Fields</h5>
|
||||
</div>
|
||||
{% render_custom_fields form %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -112,7 +112,7 @@
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||
</div>
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:powerfeed_trace' %}
|
||||
{% else %}
|
||||
<div class="text-muted">
|
||||
Not connected
|
||||
|
@ -66,7 +66,7 @@
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||
</div>
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:poweroutlet_trace' %}
|
||||
{% else %}
|
||||
<div class="text-muted">
|
||||
Not Connected
|
||||
|
@ -66,7 +66,7 @@
|
||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||
</div>
|
||||
{% elif object.cable %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||
{% include 'dcim/inc/connection_endpoints.html' with trace_url='dcim:powerport_trace' %}
|
||||
{% else %}
|
||||
<div class="text-muted">
|
||||
Not Connected
|
||||
|
Loading…
Reference in New Issue
Block a user