mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 09:51:22 -06:00
Merge branch 'develop' into feature
This commit is contained in:
commit
c481a1b6a2
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.3.4
|
placeholder: v3.3.5
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.3.4
|
placeholder: v3.3.5
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
@ -68,7 +68,7 @@ drf-yasg[validation]
|
|||||||
|
|
||||||
# Django wrapper for Graphene (GraphQL support)
|
# Django wrapper for Graphene (GraphQL support)
|
||||||
# https://github.com/graphql-python/graphene-django
|
# https://github.com/graphql-python/graphene-django
|
||||||
graphene_django
|
graphene_django<3.0
|
||||||
|
|
||||||
# WSGI HTTP server
|
# WSGI HTTP server
|
||||||
# https://gunicorn.org/
|
# https://gunicorn.org/
|
||||||
@ -80,7 +80,8 @@ Jinja2
|
|||||||
|
|
||||||
# Simple markup language for rendering HTML
|
# Simple markup language for rendering HTML
|
||||||
# https://github.com/Python-Markdown/markdown
|
# https://github.com/Python-Markdown/markdown
|
||||||
Markdown
|
# mkdocs currently requires Markdown v3.3
|
||||||
|
Markdown<3.4
|
||||||
|
|
||||||
# File inclusion plugin for Python-Markdown
|
# File inclusion plugin for Python-Markdown
|
||||||
# https://github.com/cmacmackin/markdown-include
|
# https://github.com/cmacmackin/markdown-include
|
||||||
|
@ -115,6 +115,14 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
|
|||||||
|
|
||||||
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
|
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
|
||||||
|
|
||||||
|
!!! tip "Accessing Config Parameters"
|
||||||
|
Plugin configuration parameters can be accessed in `settings.PLUGINS_CONFIG`, mapped by plugin name. For example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from django.conf import settings
|
||||||
|
settings.PLUGINS_CONFIG['myplugin']['verbose_name']
|
||||||
|
```
|
||||||
|
|
||||||
#### Important Notes About `django_apps`
|
#### Important Notes About `django_apps`
|
||||||
|
|
||||||
Loading additional apps may cause more harm than good and could make identifying problems within NetBox itself more difficult. The `django_apps` attribute is intended only for advanced use cases that require a deeper Django integration.
|
Loading additional apps may cause more harm than good and could make identifying problems within NetBox itself more difficult. The `django_apps` attribute is intended only for advanced use cases that require a deeper Django integration.
|
||||||
|
@ -1,21 +1,34 @@
|
|||||||
# NetBox v3.3
|
# NetBox v3.3
|
||||||
|
|
||||||
## v3.3.5 (FUTURE)
|
## v3.3.6 (FUTURE)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v3.3.5 (2022-10-05)
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
|
||||||
|
* [#8424](https://github.com/netbox-community/netbox/issues/8424) - Include rack elevation under device view
|
||||||
|
* [#10352](https://github.com/netbox-community/netbox/issues/10352) - Omit extraneous URL query attributes during search
|
||||||
* [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions
|
* [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
|
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
|
||||||
* [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments
|
* [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments
|
||||||
|
* [#10423](https://github.com/netbox-community/netbox/issues/10423) - Enforce object type validation when creating journal entries
|
||||||
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
|
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
|
||||||
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
|
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
|
||||||
* [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values
|
* [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values
|
||||||
|
* [#10460](https://github.com/netbox-community/netbox/issues/10460) - Restore missing connection details for device components
|
||||||
* [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI
|
* [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI
|
||||||
* [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms
|
* [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms
|
||||||
* [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window
|
* [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window
|
||||||
|
* [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion
|
||||||
|
* [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device
|
||||||
|
* [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine
|
||||||
|
* [#10559](https://github.com/netbox-community/netbox/issues/10559) - Permit the pinning of a VM to a particular device within a cluster which has no site assignment
|
||||||
|
* [#10562](https://github.com/netbox-community/netbox/issues/10562) - Correct URL for contacts table tags column
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -686,6 +686,7 @@ class ModuleForm(NetBoxModelForm):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if self.instance.pk:
|
if self.instance.pk:
|
||||||
|
self.fields['device'].disabled = True
|
||||||
self.fields['replicate_components'].initial = False
|
self.fields['replicate_components'].initial = False
|
||||||
self.fields['replicate_components'].disabled = True
|
self.fields['replicate_components'].disabled = True
|
||||||
self.fields['adopt_components'].initial = False
|
self.fields['adopt_components'].initial = False
|
||||||
|
@ -1009,6 +1009,14 @@ class Module(NetBoxModel, ConfigContextModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:module', args=[self.pk])
|
return reverse('dcim:module', args=[self.pk])
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
if self.module_bay.device != self.device:
|
||||||
|
raise ValidationError(
|
||||||
|
f"Module must be installed within a module bay belonging to the assigned device ({self.device})."
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
is_new = self.pk is None
|
is_new = self.pk is None
|
||||||
|
|
||||||
|
@ -1778,10 +1778,12 @@ class ModuleTestCase(
|
|||||||
ModuleBay(device=devices[0], name='Module Bay 2'),
|
ModuleBay(device=devices[0], name='Module Bay 2'),
|
||||||
ModuleBay(device=devices[0], name='Module Bay 3'),
|
ModuleBay(device=devices[0], name='Module Bay 3'),
|
||||||
ModuleBay(device=devices[0], name='Module Bay 4'),
|
ModuleBay(device=devices[0], name='Module Bay 4'),
|
||||||
|
ModuleBay(device=devices[0], name='Module Bay 5'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 1'),
|
ModuleBay(device=devices[1], name='Module Bay 1'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 2'),
|
ModuleBay(device=devices[1], name='Module Bay 2'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 3'),
|
ModuleBay(device=devices[1], name='Module Bay 3'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 4'),
|
ModuleBay(device=devices[1], name='Module Bay 4'),
|
||||||
|
ModuleBay(device=devices[1], name='Module Bay 5'),
|
||||||
)
|
)
|
||||||
ModuleBay.objects.bulk_create(module_bays)
|
ModuleBay.objects.bulk_create(module_bays)
|
||||||
|
|
||||||
@ -1795,7 +1797,7 @@ class ModuleTestCase(
|
|||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
cls.form_data = {
|
cls.form_data = {
|
||||||
'device': devices[1].pk,
|
'device': devices[0].pk,
|
||||||
'module_bay': module_bays[3].pk,
|
'module_bay': module_bays[3].pk,
|
||||||
'module_type': module_types[0].pk,
|
'module_type': module_types[0].pk,
|
||||||
'serial': 'A',
|
'serial': 'A',
|
||||||
@ -1867,7 +1869,6 @@ class ModuleTestCase(
|
|||||||
self.assertIsNone(interface.module)
|
self.assertIsNone(interface.module)
|
||||||
|
|
||||||
# Create a module with adopted components
|
# Create a module with adopted components
|
||||||
form_data['module_bay'] = ModuleBay.objects.filter(device=device).first()
|
|
||||||
form_data['module_type'] = module_type
|
form_data['module_type'] = module_type
|
||||||
form_data['replicate_components'] = False
|
form_data['replicate_components'] = False
|
||||||
form_data['adopt_components'] = True
|
form_data['adopt_components'] = True
|
||||||
|
@ -1616,6 +1616,7 @@ class DeviceView(generic.ObjectView):
|
|||||||
return {
|
return {
|
||||||
'services': services,
|
'services': services,
|
||||||
'vc_members': vc_members,
|
'vc_members': vc_members,
|
||||||
|
'svg_extra': f'highlight=id:{instance.pk}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -471,6 +471,14 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, WebhooksMixin
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('extras:journalentry', args=[self.pk])
|
return reverse('extras:journalentry', args=[self.pk])
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
# Prevent the creation of journal entries on unsupported models
|
||||||
|
permitted_types = ContentType.objects.filter(FeatureQuery('journaling').get_query())
|
||||||
|
if self.assigned_object_type not in permitted_types:
|
||||||
|
raise ValidationError(f"Journaling is not supported for this object type ({self.assigned_object_type}).")
|
||||||
|
|
||||||
def get_kind_color(self):
|
def get_kind_color(self):
|
||||||
return JournalEntryKindChoices.colors.get(self.kind)
|
return JournalEntryKindChoices.colors.get(self.kind)
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ class NetBoxFeatureSet(
|
|||||||
CustomLinksMixin,
|
CustomLinksMixin,
|
||||||
CustomValidationMixin,
|
CustomValidationMixin,
|
||||||
ExportTemplatesMixin,
|
ExportTemplatesMixin,
|
||||||
JournalingMixin,
|
|
||||||
TagsMixin,
|
TagsMixin,
|
||||||
WebhooksMixin
|
WebhooksMixin
|
||||||
):
|
):
|
||||||
@ -51,7 +50,7 @@ class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, models.Model)
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model):
|
class NetBoxModel(CloningMixin, JournalingMixin, NetBoxFeatureSet, models.Model):
|
||||||
"""
|
"""
|
||||||
Primary models represent real objects within the infrastructure being modeled.
|
Primary models represent real objects within the infrastructure being modeled.
|
||||||
"""
|
"""
|
||||||
|
@ -28,7 +28,7 @@ django.utils.encoding.force_text = force_str # type: ignore
|
|||||||
# Environment setup
|
# Environment setup
|
||||||
#
|
#
|
||||||
|
|
||||||
VERSION = '3.3.5-dev'
|
VERSION = '3.4-beta1'
|
||||||
|
|
||||||
# Hostname
|
# Hostname
|
||||||
HOSTNAME = platform.node()
|
HOSTNAME = platform.node()
|
||||||
|
BIN
netbox/project-static/dist/netbox.js
vendored
BIN
netbox/project-static/dist/netbox.js
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox.js.map
vendored
BIN
netbox/project-static/dist/netbox.js.map
vendored
Binary file not shown.
@ -37,6 +37,20 @@ function initDocument(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function initWindow(): void {
|
function initWindow(): void {
|
||||||
|
|
||||||
|
const documentForms = document.forms
|
||||||
|
for (var documentForm of documentForms) {
|
||||||
|
if (documentForm.method.toUpperCase() == 'GET') {
|
||||||
|
// @ts-ignore: Our version of typescript seems to be too old for FormDataEvent
|
||||||
|
documentForm.addEventListener('formdata', function(event: FormDataEvent) {
|
||||||
|
let formData: FormData = event.formData;
|
||||||
|
for (let [name, value] of Array.from(formData.entries())) {
|
||||||
|
if (value === '') formData.delete(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const contentContainer = document.querySelector<HTMLElement>('.content-container');
|
const contentContainer = document.querySelector<HTMLElement>('.content-container');
|
||||||
if (contentContainer !== null) {
|
if (contentContainer !== null) {
|
||||||
// Focus the content container for accessible navigation.
|
// Focus the content container for accessible navigation.
|
||||||
|
@ -55,52 +55,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Connection</h5>
|
||||||
Connection
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.mark_connected %}
|
{% if object.mark_connected %}
|
||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover attr-table">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
<tr>
|
|
||||||
<th scope="row">Cable</th>
|
|
||||||
<td>
|
|
||||||
{{ object.cable|linkify }}
|
|
||||||
<a href="{% url 'dcim:consoleport_trace' 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>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>{{ object.connected_endpoint.device|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ object.connected_endpoint|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ object.connected_endpoint.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
Not Connected
|
Not Connected
|
||||||
|
@ -55,54 +55,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Connection</h5>
|
||||||
Connection
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.mark_connected %}
|
{% if object.mark_connected %}
|
||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover attr-table">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
<tr>
|
|
||||||
<th scope="row">Cable</th>
|
|
||||||
<td>
|
|
||||||
{{ object.cable|linkify }}
|
|
||||||
<a href="{% url 'dcim:consoleserverport_trace' 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>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>
|
|
||||||
{{ object.connected_endpoint.device|linkify }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ object.connected_endpoint|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ object.connected_endpoint.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
Not Connected
|
Not Connected
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col col-md-6">
|
<div class="col col-12 col-xl-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">
|
||||||
Device
|
Device
|
||||||
@ -153,7 +153,7 @@
|
|||||||
{% include 'inc/panels/comments.html' %}
|
{% include 'inc/panels/comments.html' %}
|
||||||
{% plugin_left_page object %}
|
{% plugin_left_page object %}
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-12 col-xl-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">Management</h5>
|
<h5 class="card-header">Management</h5>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -286,6 +286,22 @@
|
|||||||
</div>
|
</div>
|
||||||
{% include 'inc/panels/contacts.html' %}
|
{% include 'inc/panels/contacts.html' %}
|
||||||
{% include 'inc/panels/image_attachments.html' %}
|
{% include 'inc/panels/image_attachments.html' %}
|
||||||
|
{% if object.rack and object.position %}
|
||||||
|
<div class="row" style="margin-bottom: 20px">
|
||||||
|
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
||||||
|
<div style="margin-left: 30px">
|
||||||
|
<h4>Front</h4>
|
||||||
|
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='front' extra_params=svg_extra %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col col-md-6 col-sm-6 col-xs-12 text-center">
|
||||||
|
<div style="margin-left: 30px">
|
||||||
|
<h4>Rear</h4>
|
||||||
|
{% include 'dcim/inc/rack_elevation.html' with object=object.rack face='rear' extra_params=svg_extra %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% plugin_right_page object %}
|
{% plugin_right_page object %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<td>
|
|
||||||
{% if termination.parent_object.provider %}
|
|
||||||
<i class="mdi mdi-lightning-bolt" title="Circuit"></i>
|
|
||||||
<a href="{{ termination.parent_object.get_absolute_url }}">
|
|
||||||
{{ termination.parent_object.provider }}
|
|
||||||
{{ termination.parent_object }}
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
{{ termination.parent_object|linkify }}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ termination|linkify }}
|
|
||||||
</td>
|
|
36
netbox/templates/dcim/inc/connection_endpoints.html
Normal file
36
netbox/templates/dcim/inc/connection_endpoints.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<table class="table table-hover">
|
||||||
|
<tr>
|
||||||
|
<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">
|
||||||
|
<i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Path Status</th>
|
||||||
|
<td>
|
||||||
|
{% if object.path.is_complete and object.path.is_active %}
|
||||||
|
<span class="badge bg-success">Reachable</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-danger">Not Reachable</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Path Endpoints</th>
|
||||||
|
<td>
|
||||||
|
{% for endpoint in object.connected_endpoints %}
|
||||||
|
{% if endpoint.parent_object %}
|
||||||
|
{{ endpoint.parent_object|linkify }}
|
||||||
|
<i class="mdi mdi-chevron-right"></i>
|
||||||
|
{% endif %}
|
||||||
|
{{ endpoint|linkify }}
|
||||||
|
{% if not forloop.last %}<br />{% endif %}
|
||||||
|
{% empty %}
|
||||||
|
{{ ''|placeholder }}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
@ -144,89 +144,7 @@
|
|||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||||
</div>
|
</div>
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
{% if object.connected_endpoint.device %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">
|
|
||||||
{% if object.connected_endpoint.enabled %}
|
|
||||||
<span class="badge bg-success">Enabled</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Disabled</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr>
|
|
||||||
<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">
|
|
||||||
<i class="mdi mdi-transit-connection-variant" aria-hidden="true"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint.device %}
|
|
||||||
{% with iface=object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>{{ iface.device|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ iface|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ iface.get_type_display }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">LAG</th>
|
|
||||||
<td>{{ iface.lag|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ iface.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">MTU</th>
|
|
||||||
<td>{{ iface.mtu|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">MAC Address</th>
|
|
||||||
<td>{{ iface.mac_address|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">802.1Q Mode</th>
|
|
||||||
<td>{{ iface.get_mode_display }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endwith %}
|
|
||||||
{% elif object.connected_endpoint.circuit %}
|
|
||||||
{% with ct=object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Provider</th>
|
|
||||||
<td>{{ ct.circuit.provider|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Circuit</th>
|
|
||||||
<td>{{ ct.circuit|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Side</th>
|
|
||||||
<td>{{ ct.term_side }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endwith %}
|
|
||||||
{% endif %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_complete and object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
{% elif object.wireless_link %}
|
{% elif object.wireless_link %}
|
||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<tr>
|
<tr>
|
||||||
@ -238,7 +156,7 @@
|
|||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% with peer_interface=object.connected_endpoint %}
|
{% with peer_interface=object.link_peers.0 %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Device</th>
|
<th scope="row">Device</th>
|
||||||
<td>{{ peer_interface.device|linkify }}</td>
|
<td>{{ peer_interface.device|linkify }}</td>
|
||||||
|
@ -41,8 +41,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Connected Device</th>
|
<th scope="row">Connected Device</th>
|
||||||
<td>
|
<td>
|
||||||
{% if object.connected_endpoint %}
|
{% if object.connected_endpoints %}
|
||||||
{{ object.connected_endpoint.device|linkify }} ({{ object.connected_endpoint }})
|
{{ object.connected_endpoints.0.device|linkify }} ({{ object.connected_endpoints.0|linkify:"name" }})
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ ''|placeholder }}
|
{{ ''|placeholder }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -50,7 +50,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Utilization (Allocated)</th>
|
<th scope="row">Utilization (Allocated)</th>
|
||||||
{% with utilization=object.connected_endpoint.get_power_draw %}
|
{% with utilization=object.connected_endpoints.0.get_power_draw %}
|
||||||
{% if utilization %}
|
{% if utilization %}
|
||||||
<td>
|
<td>
|
||||||
{{ utilization.allocated }}VA / {{ object.available_power }}VA
|
{{ utilization.allocated }}VA / {{ object.available_power }}VA
|
||||||
@ -101,54 +101,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Connection</h5>
|
||||||
Connection
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.mark_connected %}
|
{% if object.mark_connected %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as connected
|
||||||
</div>
|
</div>
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover attr-table">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
<tr>
|
|
||||||
<th scope="row">Cable</th>
|
|
||||||
<td>
|
|
||||||
{{ object.cable|linkify }}
|
|
||||||
<a href="{% url 'dcim:powerfeed_trace' 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>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>{{ object.connected_endpoint.device|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ object.connected_endpoint|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ object.connected_endpoint.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
Not connected
|
Not connected
|
||||||
|
@ -59,54 +59,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Connection</h5>
|
||||||
Connection
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.mark_connected %}
|
{% if object.mark_connected %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||||
</div>
|
</div>
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover attr-table">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
<tr>
|
|
||||||
<th scope="row">Cable</th>
|
|
||||||
<td>
|
|
||||||
{{ object.cable|linkify }}
|
|
||||||
<a href="{% url 'dcim:poweroutlet_trace' 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>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>{{ object.connected_endpoint.device|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ object.connected_endpoint|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ object.connected_endpoint.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
Not Connected
|
Not Connected
|
||||||
|
@ -59,54 +59,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col col-md-6">
|
<div class="col col-md-6">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h5 class="card-header">
|
<h5 class="card-header">Connection</h5>
|
||||||
Connection
|
|
||||||
</h5>
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
{% if object.mark_connected %}
|
{% if object.mark_connected %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
<span class="text-success"><i class="mdi mdi-check-bold"></i></span> Marked as Connected
|
||||||
</div>
|
</div>
|
||||||
{% elif object.cable %}
|
{% elif object.cable %}
|
||||||
<table class="table table-hover attr-table">
|
{% include 'dcim/inc/connection_endpoints.html' %}
|
||||||
<tr>
|
|
||||||
<th scope="row">Cable</th>
|
|
||||||
<td>
|
|
||||||
{{ object.cable|linkify }}
|
|
||||||
<a href="{% url 'dcim:powerport_trace' 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>
|
|
||||||
</tr>
|
|
||||||
{% if object.connected_endpoint %}
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Device</th>
|
|
||||||
<td>{{ object.connected_endpoint.device|linkify }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Name</th>
|
|
||||||
<td>{{ object.connected_endpoint|linkify:"name" }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Type</th>
|
|
||||||
<td>{{ object.connected_endpoint.get_type_display|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Description</th>
|
|
||||||
<td>{{ object.connected_endpoint.description|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Path Status</th>
|
|
||||||
<td>
|
|
||||||
{% if object.path.is_active %}
|
|
||||||
<span class="badge bg-success">Reachable</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-danger">Not Reachable</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
Not Connected
|
Not Connected
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Group</th>
|
<th scope="row">Group</th>
|
||||||
<td>{{ object.group|linkify }}</td>
|
<td>{{ object.group|linkify|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Tenant</th>
|
<th scope="row">Tenant</th>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Site</th>
|
<th scope="row">Site</th>
|
||||||
<td>{{ object.site|linkify }}</td>
|
<td>{{ object.site|linkify|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Virtual Machines</th>
|
<th scope="row">Virtual Machines</th>
|
||||||
|
@ -174,8 +174,8 @@ class ContactAssignment(WebhooksMixin, ChangeLoggedModel):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.priority:
|
if self.priority:
|
||||||
return f"{self.contact} ({self.get_priority_display()})"
|
return f"{self.contact} ({self.get_priority_display()}) -> {self.object}"
|
||||||
return str(self.contact)
|
return str(f"{self.contact} -> {self.object}")
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('tenancy:contact', args=[self.contact.pk])
|
return reverse('tenancy:contact', args=[self.contact.pk])
|
||||||
|
@ -42,7 +42,7 @@ class TenantTable(NetBoxTable):
|
|||||||
linkify_item=True
|
linkify_item=True
|
||||||
)
|
)
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='tenancy:tenant_list'
|
url_name='tenancy:contact_list'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
|
@ -350,14 +350,12 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
|
|||||||
})
|
})
|
||||||
|
|
||||||
# Validate site for cluster & device
|
# Validate site for cluster & device
|
||||||
if self.cluster and self.cluster.site != self.site:
|
if self.cluster and self.site and self.cluster.site != self.site:
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'cluster': f'The selected cluster ({self.cluster} is not assigned to this site ({self.site}).'
|
'cluster': f'The selected cluster ({self.cluster}) is not assigned to this site ({self.site}).'
|
||||||
})
|
|
||||||
if self.device and self.device.site != self.site:
|
|
||||||
raise ValidationError({
|
|
||||||
'device': f'The selected device ({self.device} is not assigned to this site ({self.site}).'
|
|
||||||
})
|
})
|
||||||
|
elif self.cluster:
|
||||||
|
self.site = self.cluster.site
|
||||||
|
|
||||||
# Validate assigned cluster device
|
# Validate assigned cluster device
|
||||||
if self.device and not self.cluster:
|
if self.device and not self.cluster:
|
||||||
@ -366,7 +364,7 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
|
|||||||
})
|
})
|
||||||
if self.device and self.device not in self.cluster.devices.all():
|
if self.device and self.device not in self.cluster.devices.all():
|
||||||
raise ValidationError({
|
raise ValidationError({
|
||||||
'device': f'The selected device ({self.device} is not assigned to this cluster ({self.cluster}).'
|
'device': f'The selected device ({self.device}) is not assigned to this cluster ({self.cluster}).'
|
||||||
})
|
})
|
||||||
|
|
||||||
# Validate primary IP addresses
|
# Validate primary IP addresses
|
||||||
|
@ -70,9 +70,10 @@ class VirtualMachineTestCase(TestCase):
|
|||||||
with self.assertRaises(ValidationError):
|
with self.assertRaises(ValidationError):
|
||||||
VirtualMachine(name='vm1', site=sites[0], cluster=clusters[1]).full_clean()
|
VirtualMachine(name='vm1', site=sites[0], cluster=clusters[1]).full_clean()
|
||||||
|
|
||||||
# VM with cluster site but no direct site should fail
|
# VM with cluster site but no direct site should have its site set automatically
|
||||||
with self.assertRaises(ValidationError):
|
vm = VirtualMachine(name='vm1', site=None, cluster=clusters[0])
|
||||||
VirtualMachine(name='vm1', site=None, cluster=clusters[0]).full_clean()
|
vm.full_clean()
|
||||||
|
self.assertEqual(vm.site, sites[0])
|
||||||
|
|
||||||
def test_vm_name_case_sensitivity(self):
|
def test_vm_name_case_sensitivity(self):
|
||||||
vm1 = VirtualMachine(
|
vm1 = VirtualMachine(
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
bleach==5.0.1
|
bleach==5.0.1
|
||||||
Django==4.1.1
|
Django==4.1.1
|
||||||
django-cors-headers==3.13.0
|
django-cors-headers==3.13.0
|
||||||
django-debug-toolbar==3.6.0
|
django-debug-toolbar==3.7.0
|
||||||
django-filter==22.1
|
django-filter==22.1
|
||||||
django-graphiql-debug-toolbar==0.2.0
|
django-graphiql-debug-toolbar==0.2.0
|
||||||
django-mptt==0.13.4
|
django-mptt==0.14
|
||||||
django-pglocks==1.0.4
|
django-pglocks==1.0.4
|
||||||
django-prometheus==2.2.0
|
django-prometheus==2.2.0
|
||||||
django-redis==5.2.0
|
django-redis==5.2.0
|
||||||
@ -13,24 +13,24 @@ django-rq==2.5.1
|
|||||||
django-tables2==2.4.1
|
django-tables2==2.4.1
|
||||||
django-taggit==3.0.0
|
django-taggit==3.0.0
|
||||||
django-timezone-field==5.0
|
django-timezone-field==5.0
|
||||||
djangorestframework==3.13.1
|
djangorestframework==3.14.0
|
||||||
drf-yasg[validation]==1.21.3
|
drf-yasg[validation]==1.21.4
|
||||||
graphene-django==2.15.0
|
graphene-django==2.15.0
|
||||||
gunicorn==20.1.0
|
gunicorn==20.1.0
|
||||||
Jinja2==3.1.2
|
Jinja2==3.1.2
|
||||||
Markdown==3.4.1
|
Markdown==3.3.7
|
||||||
mkdocs-material==8.5.1
|
mkdocs-material==8.5.6
|
||||||
mkdocstrings[python-legacy]==0.19.0
|
mkdocstrings[python-legacy]==0.19.0
|
||||||
netaddr==0.8.0
|
netaddr==0.8.0
|
||||||
Pillow==9.2.0
|
Pillow==9.2.0
|
||||||
psycopg2-binary==2.9.3
|
psycopg2-binary==2.9.3
|
||||||
PyYAML==6.0
|
PyYAML==6.0
|
||||||
sentry-sdk==1.9.8
|
sentry-sdk==1.9.10
|
||||||
social-auth-app-django==5.0.0
|
social-auth-app-django==5.0.0
|
||||||
social-auth-core==4.3.0
|
social-auth-core==4.3.0
|
||||||
svgwrite==1.4.3
|
svgwrite==1.4.3
|
||||||
tablib==3.2.1
|
tablib==3.2.1
|
||||||
tzdata==2022.2
|
tzdata==2022.4
|
||||||
|
|
||||||
# Workaround for #7401
|
# Workaround for #7401
|
||||||
jsonschema==3.2.0
|
jsonschema==3.2.0
|
||||||
|
Loading…
Reference in New Issue
Block a user