mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Fixes #6895: Remove errant markup for null values in CSV export
This commit is contained in:
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#6895](https://github.com/netbox-community/netbox/issues/6895) - Remove errant markup for null values in CSV export
|
||||||
* [#7373](https://github.com/netbox-community/netbox/issues/7373) - Fix flashing when server, client, and browser color-mode preferences are mismatched
|
* [#7373](https://github.com/netbox-community/netbox/issues/7373) - Fix flashing when server, client, and browser color-mode preferences are mismatched
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -2,7 +2,7 @@ import django_tables2 as tables
|
|||||||
from django_tables2.utils import Accessor
|
from django_tables2.utils import Accessor
|
||||||
|
|
||||||
from dcim.models import Cable
|
from dcim.models import Cable
|
||||||
from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, ToggleColumn
|
from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, TemplateColumn, ToggleColumn
|
||||||
from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT
|
from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -45,7 +45,7 @@ class CableTable(BaseTable):
|
|||||||
verbose_name='Termination B'
|
verbose_name='Termination B'
|
||||||
)
|
)
|
||||||
status = ChoiceFieldColumn()
|
status = ChoiceFieldColumn()
|
||||||
length = tables.TemplateColumn(
|
length = TemplateColumn(
|
||||||
template_code=CABLE_LENGTH,
|
template_code=CABLE_LENGTH,
|
||||||
order_by='_abs_length'
|
order_by='_abs_length'
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,7 @@ from dcim.models import (
|
|||||||
from tenancy.tables import TenantColumn
|
from tenancy.tables import TenantColumn
|
||||||
from utilities.tables import (
|
from utilities.tables import (
|
||||||
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
|
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
|
||||||
MarkdownColumn, TagColumn, ToggleColumn,
|
MarkdownColumn, TagColumn, TemplateColumn, ToggleColumn,
|
||||||
)
|
)
|
||||||
from .template_code import (
|
from .template_code import (
|
||||||
CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
|
CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
|
||||||
@ -258,7 +258,7 @@ class CableTerminationTable(BaseTable):
|
|||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Cable Color'
|
verbose_name='Cable Color'
|
||||||
)
|
)
|
||||||
cable_peer = tables.TemplateColumn(
|
cable_peer = TemplateColumn(
|
||||||
accessor='_cable_peer',
|
accessor='_cable_peer',
|
||||||
template_code=CABLETERMINATION,
|
template_code=CABLETERMINATION,
|
||||||
orderable=False,
|
orderable=False,
|
||||||
@ -268,7 +268,7 @@ class CableTerminationTable(BaseTable):
|
|||||||
|
|
||||||
|
|
||||||
class PathEndpointTable(CableTerminationTable):
|
class PathEndpointTable(CableTerminationTable):
|
||||||
connection = tables.TemplateColumn(
|
connection = TemplateColumn(
|
||||||
accessor='_path.last_node',
|
accessor='_path.last_node',
|
||||||
template_code=CABLETERMINATION,
|
template_code=CABLETERMINATION,
|
||||||
verbose_name='Connection',
|
verbose_name='Connection',
|
||||||
@ -470,7 +470,7 @@ class BaseInterfaceTable(BaseTable):
|
|||||||
verbose_name='IP Addresses'
|
verbose_name='IP Addresses'
|
||||||
)
|
)
|
||||||
untagged_vlan = tables.Column(linkify=True)
|
untagged_vlan = tables.Column(linkify=True)
|
||||||
tagged_vlans = tables.TemplateColumn(
|
tagged_vlans = TemplateColumn(
|
||||||
template_code=INTERFACE_TAGGED_VLANS,
|
template_code=INTERFACE_TAGGED_VLANS,
|
||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Tagged VLANs'
|
verbose_name='Tagged VLANs'
|
||||||
|
@ -5,13 +5,11 @@ CABLETERMINATION = """
|
|||||||
<i class="mdi mdi-chevron-right"></i>
|
<i class="mdi mdi-chevron-right"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ value.get_absolute_url }}">{{ value }}</a>
|
<a href="{{ value.get_absolute_url }}">{{ value }}</a>
|
||||||
{% else %}
|
|
||||||
—
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CABLE_LENGTH = """
|
CABLE_LENGTH = """
|
||||||
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% else %}—{% endif %}
|
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
CABLE_TERMINATION_PARENT = """
|
CABLE_TERMINATION_PARENT = """
|
||||||
@ -63,8 +61,6 @@ INTERFACE_TAGGED_VLANS = """
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% elif record.mode == 'tagged-all' %}
|
{% elif record.mode == 'tagged-all' %}
|
||||||
All
|
All
|
||||||
{% else %}
|
|
||||||
—
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -39,15 +39,7 @@ PREFIXFLAT_LINK = """
|
|||||||
{% if record.pk %}
|
{% if record.pk %}
|
||||||
<a href="{% url 'ipam:prefix' pk=record.pk %}">{{ record.prefix }}</a>
|
<a href="{% url 'ipam:prefix' pk=record.pk %}">{{ record.prefix }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
—
|
{{ record.prefix }}
|
||||||
{% endif %}
|
|
||||||
"""
|
|
||||||
|
|
||||||
PREFIX_ROLE_LINK = """
|
|
||||||
{% if record.role %}
|
|
||||||
<a href="{% url 'ipam:prefix_list' %}?role={{ record.role.slug }}">{{ record.role }}</a>
|
|
||||||
{% else %}
|
|
||||||
—
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -218,8 +210,8 @@ class PrefixTable(BaseTable):
|
|||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name='VLAN'
|
verbose_name='VLAN'
|
||||||
)
|
)
|
||||||
role = tables.TemplateColumn(
|
role = tables.Column(
|
||||||
template_code=PREFIX_ROLE_LINK
|
linkify=True
|
||||||
)
|
)
|
||||||
is_pool = BooleanColumn(
|
is_pool = BooleanColumn(
|
||||||
verbose_name='Pool'
|
verbose_name='Pool'
|
||||||
@ -264,8 +256,8 @@ class IPRangeTable(BaseTable):
|
|||||||
status = ChoiceFieldColumn(
|
status = ChoiceFieldColumn(
|
||||||
default=AVAILABLE_LABEL
|
default=AVAILABLE_LABEL
|
||||||
)
|
)
|
||||||
role = tables.TemplateColumn(
|
role = tables.Column(
|
||||||
template_code=PREFIX_ROLE_LINK
|
linkify=True
|
||||||
)
|
)
|
||||||
tenant = TenantColumn()
|
tenant = TenantColumn()
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ from dcim.models import Interface
|
|||||||
from tenancy.tables import TenantColumn
|
from tenancy.tables import TenantColumn
|
||||||
from utilities.tables import (
|
from utilities.tables import (
|
||||||
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn,
|
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn,
|
||||||
ToggleColumn,
|
TemplateColumn, ToggleColumn,
|
||||||
)
|
)
|
||||||
from virtualization.models import VMInterface
|
from virtualization.models import VMInterface
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
@ -35,19 +35,9 @@ VLAN_LINK = """
|
|||||||
VLAN_PREFIXES = """
|
VLAN_PREFIXES = """
|
||||||
{% for prefix in record.prefixes.all %}
|
{% for prefix in record.prefixes.all %}
|
||||||
<a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %}
|
<a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %}
|
||||||
{% empty %}
|
|
||||||
—
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VLAN_ROLE_LINK = """
|
|
||||||
{% if record.role %}
|
|
||||||
<a href="{% url 'ipam:vlan_list' %}?role={{ record.role.slug }}">{{ record.role }}</a>
|
|
||||||
{% else %}
|
|
||||||
—
|
|
||||||
{% endif %}
|
|
||||||
"""
|
|
||||||
|
|
||||||
VLANGROUP_ADD_VLAN = """
|
VLANGROUP_ADD_VLAN = """
|
||||||
{% with next_vid=record.get_next_available_vid %}
|
{% with next_vid=record.get_next_available_vid %}
|
||||||
{% if next_vid and perms.ipam.add_vlan %}
|
{% if next_vid and perms.ipam.add_vlan %}
|
||||||
@ -115,10 +105,10 @@ class VLANTable(BaseTable):
|
|||||||
status = ChoiceFieldColumn(
|
status = ChoiceFieldColumn(
|
||||||
default=AVAILABLE_LABEL
|
default=AVAILABLE_LABEL
|
||||||
)
|
)
|
||||||
role = tables.TemplateColumn(
|
role = tables.Column(
|
||||||
template_code=VLAN_ROLE_LINK
|
linkify=True
|
||||||
)
|
)
|
||||||
prefixes = tables.TemplateColumn(
|
prefixes = TemplateColumn(
|
||||||
template_code=VLAN_PREFIXES,
|
template_code=VLAN_PREFIXES,
|
||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Prefixes'
|
verbose_name='Prefixes'
|
||||||
@ -190,8 +180,8 @@ class InterfaceVLANTable(BaseTable):
|
|||||||
)
|
)
|
||||||
tenant = TenantColumn()
|
tenant = TenantColumn()
|
||||||
status = ChoiceFieldColumn()
|
status = ChoiceFieldColumn()
|
||||||
role = tables.TemplateColumn(
|
role = tables.Column(
|
||||||
template_code=VLAN_ROLE_LINK
|
linkify=True
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from tenancy.tables import TenantColumn
|
from tenancy.tables import TenantColumn
|
||||||
from utilities.tables import BaseTable, BooleanColumn, TagColumn, ToggleColumn
|
from utilities.tables import BaseTable, BooleanColumn, TagColumn, TemplateColumn, ToggleColumn
|
||||||
from ipam.models import *
|
from ipam.models import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -11,9 +11,7 @@ __all__ = (
|
|||||||
|
|
||||||
VRF_TARGETS = """
|
VRF_TARGETS = """
|
||||||
{% for rt in value.all %}
|
{% for rt in value.all %}
|
||||||
<a href="{{ rt.get_absolute_url }}">{{ rt }}</a>{% if not forloop.last %}<br />{% endif %}
|
<a href="{{ rt.get_absolute_url }}">{{ rt }}</a>{% if not forloop.last %}<br />{% endif %}
|
||||||
{% empty %}
|
|
||||||
—
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -34,11 +32,11 @@ class VRFTable(BaseTable):
|
|||||||
enforce_unique = BooleanColumn(
|
enforce_unique = BooleanColumn(
|
||||||
verbose_name='Unique'
|
verbose_name='Unique'
|
||||||
)
|
)
|
||||||
import_targets = tables.TemplateColumn(
|
import_targets = TemplateColumn(
|
||||||
template_code=VRF_TARGETS,
|
template_code=VRF_TARGETS,
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
export_targets = tables.TemplateColumn(
|
export_targets = TemplateColumn(
|
||||||
template_code=VRF_TARGETS,
|
template_code=VRF_TARGETS,
|
||||||
orderable=False
|
orderable=False
|
||||||
)
|
)
|
||||||
|
@ -157,6 +157,25 @@ class BooleanColumn(tables.Column):
|
|||||||
return str(value)
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateColumn(tables.TemplateColumn):
|
||||||
|
"""
|
||||||
|
Overrides the stock TemplateColumn to render a placeholder if the returned value is an empty string.
|
||||||
|
"""
|
||||||
|
PLACEHOLDER = mark_safe('—')
|
||||||
|
|
||||||
|
def render(self, *args, **kwargs):
|
||||||
|
ret = super().render(*args, **kwargs)
|
||||||
|
if not ret.strip():
|
||||||
|
return self.PLACEHOLDER
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def value(self, **kwargs):
|
||||||
|
ret = super().value(**kwargs)
|
||||||
|
if ret == self.PLACEHOLDER:
|
||||||
|
return ''
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
class ButtonsColumn(tables.TemplateColumn):
|
class ButtonsColumn(tables.TemplateColumn):
|
||||||
"""
|
"""
|
||||||
Render edit, delete, and changelog buttons for an object.
|
Render edit, delete, and changelog buttons for an object.
|
||||||
|
Reference in New Issue
Block a user