mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
Merge branch 'develop' into feature
This commit is contained in:
commit
3b9fda0169
@ -79,7 +79,22 @@ A human-friendly description of what your script does.
|
|||||||
|
|
||||||
### `field_order`
|
### `field_order`
|
||||||
|
|
||||||
By default, script variables will be ordered in the form as they are defined in the script. `field_order` may be defined as an iterable of field names to determine the order in which variables are rendered. Any fields not included in this iterable be listed last.
|
By default, script variables will be ordered in the form as they are defined in the script. `field_order` may be defined as an iterable of field names to determine the order in which variables are rendered within a default "Script Data" group. Any fields not included in this iterable be listed last. If `fieldsets` is defined, `field_order` will be ignored. A fieldset group for "Script Execution Parameters" will be added to the end of the form by default for the user.
|
||||||
|
|
||||||
|
### `fieldsets`
|
||||||
|
|
||||||
|
`fieldsets` may be defined as an iterable of field groups and their field names to determine the order in which variables are group and rendered. Any fields not included in this iterable will not be displayed in the form. If `fieldsets` is defined, `field_order` will be ignored. A fieldset group for "Script Execution Parameters" will be added to the end of the fieldsets by default for the user.
|
||||||
|
|
||||||
|
An example fieldset definition is provided below:
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MyScript(Script):
|
||||||
|
class Meta:
|
||||||
|
fieldsets = (
|
||||||
|
('First group', ('field1', 'field2', 'field3')),
|
||||||
|
('Second group', ('field4', 'field5')),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
### `commit_default`
|
### `commit_default`
|
||||||
|
|
||||||
@ -300,7 +315,7 @@ Optionally `schedule_at` can be passed in the form data with a datetime string t
|
|||||||
Scripts can be run on the CLI by invoking the management command:
|
Scripts can be run on the CLI by invoking the management command:
|
||||||
|
|
||||||
```
|
```
|
||||||
python3 manage.py runscript [--commit] [--loglevel {debug,info,warning,error,critical}] [--data "<data>"] <module>.<script>
|
python3 manage.py runscript [--commit] [--loglevel {debug,info,warning,error,critical}] [--data "<data>"] <module>.<script>
|
||||||
```
|
```
|
||||||
|
|
||||||
The required ``<module>.<script>`` argument is the script to run where ``<module>`` is the name of the python file in the ``scripts`` directory without the ``.py`` extension and ``<script>`` is the name of the script class in the ``<module>`` to run.
|
The required ``<module>.<script>`` argument is the script to run where ``<module>`` is the name of the python file in the ``scripts`` directory without the ``.py`` extension and ``<script>`` is the name of the script class in the ``<module>`` to run.
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
# NetBox v3.4
|
# NetBox v3.4
|
||||||
|
|
||||||
|
## v3.4.7 (FUTURE)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [#11833](https://github.com/netbox-community/netbox/issues/11833) - Add fieldset support for custom script forms
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#11984](https://github.com/netbox-community/netbox/issues/11984) - Remove erroneous 802.3az PoE type
|
||||||
|
* [#11979](https://github.com/netbox-community/netbox/issues/11979) - Correct URL for tags in route targets list
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## v3.4.6 (2023-03-13)
|
## v3.4.6 (2023-03-13)
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
@ -1137,7 +1137,6 @@ class InterfacePoETypeChoices(ChoiceSet):
|
|||||||
|
|
||||||
TYPE_1_8023AF = 'type1-ieee802.3af'
|
TYPE_1_8023AF = 'type1-ieee802.3af'
|
||||||
TYPE_2_8023AT = 'type2-ieee802.3at'
|
TYPE_2_8023AT = 'type2-ieee802.3at'
|
||||||
TYPE_2_8023AZ = 'type2-ieee802.3az'
|
|
||||||
TYPE_3_8023BT = 'type3-ieee802.3bt'
|
TYPE_3_8023BT = 'type3-ieee802.3bt'
|
||||||
TYPE_4_8023BT = 'type4-ieee802.3bt'
|
TYPE_4_8023BT = 'type4-ieee802.3bt'
|
||||||
|
|
||||||
@ -1152,7 +1151,6 @@ class InterfacePoETypeChoices(ChoiceSet):
|
|||||||
(
|
(
|
||||||
(TYPE_1_8023AF, '802.3af (Type 1)'),
|
(TYPE_1_8023AF, '802.3af (Type 1)'),
|
||||||
(TYPE_2_8023AT, '802.3at (Type 2)'),
|
(TYPE_2_8023AT, '802.3at (Type 2)'),
|
||||||
(TYPE_2_8023AZ, '802.3az (Type 2)'),
|
|
||||||
(TYPE_3_8023BT, '802.3bt (Type 3)'),
|
(TYPE_3_8023BT, '802.3bt (Type 3)'),
|
||||||
(TYPE_4_8023BT, '802.3bt (Type 4)'),
|
(TYPE_4_8023BT, '802.3bt (Type 4)'),
|
||||||
)
|
)
|
||||||
|
@ -352,6 +352,18 @@ class BaseScript:
|
|||||||
# Set initial "commit" checkbox state based on the script's Meta parameter
|
# Set initial "commit" checkbox state based on the script's Meta parameter
|
||||||
form.fields['_commit'].initial = getattr(self.Meta, 'commit_default', True)
|
form.fields['_commit'].initial = getattr(self.Meta, 'commit_default', True)
|
||||||
|
|
||||||
|
# Append the default fieldset if defined in the Meta class
|
||||||
|
default_fieldset = (
|
||||||
|
('Script Execution Parameters', ('_schedule_at', '_interval', '_commit')),
|
||||||
|
)
|
||||||
|
if not hasattr(self.Meta, 'fieldsets'):
|
||||||
|
fields = (
|
||||||
|
name for name, _ in self._get_vars().items()
|
||||||
|
)
|
||||||
|
self.Meta.fieldsets = (('Script Data', fields),)
|
||||||
|
|
||||||
|
self.Meta.fieldsets += default_fieldset
|
||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
@ -122,11 +124,14 @@ class SavedFilterTable(NetBoxTable):
|
|||||||
enabled = columns.BooleanColumn()
|
enabled = columns.BooleanColumn()
|
||||||
shared = columns.BooleanColumn()
|
shared = columns.BooleanColumn()
|
||||||
|
|
||||||
|
def value_parameters(self, value):
|
||||||
|
return json.dumps(value)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = SavedFilter
|
model = SavedFilter
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'slug', 'content_types', 'description', 'user', 'weight', 'enabled', 'shared',
|
'pk', 'id', 'name', 'slug', 'content_types', 'description', 'user', 'weight', 'enabled', 'shared',
|
||||||
'created', 'last_updated',
|
'created', 'last_updated', 'parameters'
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'content_types', 'user', 'description', 'enabled', 'shared',
|
'pk', 'name', 'content_types', 'user', 'description', 'enabled', 'shared',
|
||||||
|
@ -62,7 +62,7 @@ class RouteTargetTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
)
|
)
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='ipam:vrf_list'
|
url_name='ipam:routetarget_list'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
|
BIN
netbox/project-static/dist/netbox-dark.css
vendored
BIN
netbox/project-static/dist/netbox-dark.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox-light.css
vendored
BIN
netbox/project-static/dist/netbox-light.css
vendored
Binary file not shown.
BIN
netbox/project-static/dist/netbox-print.css
vendored
BIN
netbox/project-static/dist/netbox-print.css
vendored
Binary file not shown.
@ -42,3 +42,9 @@ input[type='search']::-webkit-search-results-button,
|
|||||||
input[type='search']::-webkit-search-results-decoration {
|
input[type='search']::-webkit-search-results-decoration {
|
||||||
-webkit-appearance: none !important;
|
-webkit-appearance: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove x-axis padding from highlighted text
|
||||||
|
mark {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
@ -47,16 +47,34 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="field-group my-4">
|
<div class="field-group my-4">
|
||||||
{% if form.requires_input %}
|
{% if form.requires_input %}
|
||||||
<div class="row mb-2">
|
{% if script.Meta.fieldsets %}
|
||||||
<h5 class="offset-sm-3">Script Data</h5>
|
{# Render grouped fields according to declared fieldsets #}
|
||||||
</div>
|
{% for group, fields in script.Meta.fieldsets %}
|
||||||
|
<div class="field-group mb-5">
|
||||||
|
<div class="row mb-2">
|
||||||
|
<h5 class="offset-sm-3">{{ group }}</h5>
|
||||||
|
</div>
|
||||||
|
{% for name in fields %}
|
||||||
|
{% with field=form|getfield:name %}
|
||||||
|
{% render_field field %}
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{# Render all fields as a single group #}
|
||||||
|
<div class="row mb-2">
|
||||||
|
<h5 class="offset-sm-3">Script Data</h5>
|
||||||
|
</div>
|
||||||
|
{% render_form form %}
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
<i class="mdi mdi-information"></i>
|
<i class="mdi mdi-information"></i>
|
||||||
This script does not require any input to run.
|
This script does not require any input to run.
|
||||||
</div>
|
</div>
|
||||||
|
{% render_form form %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% render_form form %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="float-end">
|
<div class="float-end">
|
||||||
<a href="{% url 'extras:script_list' %}" class="btn btn-outline-danger">Cancel</a>
|
<a href="{% url 'extras:script_list' %}" class="btn btn-outline-danger">Cancel</a>
|
||||||
|
@ -214,8 +214,12 @@ def parse_csv(reader):
|
|||||||
header = header.strip()
|
header = header.strip()
|
||||||
if '.' in header:
|
if '.' in header:
|
||||||
field, to_field = header.split('.', 1)
|
field, to_field = header.split('.', 1)
|
||||||
|
if field in headers:
|
||||||
|
raise forms.ValidationError(f'Duplicate or conflicting column header for "{field}"')
|
||||||
headers[field] = to_field
|
headers[field] = to_field
|
||||||
else:
|
else:
|
||||||
|
if header in headers:
|
||||||
|
raise forms.ValidationError(f'Duplicate or conflicting column header for "{header}"')
|
||||||
headers[header] = None
|
headers[header] = None
|
||||||
|
|
||||||
# Parse CSV rows into a list of dictionaries mapped from the column headers.
|
# Parse CSV rows into a list of dictionaries mapped from the column headers.
|
||||||
|
@ -190,7 +190,7 @@ class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'#{self.pk}'
|
return self.ssid or f'#{self.pk}'
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('wireless:wirelesslink', args=[self.pk])
|
return reverse('wireless:wirelesslink', args=[self.pk])
|
||||||
|
Loading…
Reference in New Issue
Block a user