From 0ad7ae28377f44ff7d1ed119a6ff7a8f43bf8e91 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 2 Nov 2022 16:26:26 -0400 Subject: [PATCH] Closes #10698: Omit app label from content type in table columns --- docs/release-notes/version-3.4.md | 1 + netbox/netbox/search/backends.py | 5 ++--- netbox/netbox/tables/columns.py | 4 ++-- netbox/netbox/tables/tables.py | 5 ++--- netbox/utilities/templatetags/builtins/filters.py | 4 ++-- netbox/utilities/utils.py | 15 +++++++++++++-- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index a50686158..b15eb0262 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -38,6 +38,7 @@ A new `PluginMenu` class has been introduced, which enables a plugin to inject a * [#10348](https://github.com/netbox-community/netbox/issues/10348) - Add decimal custom field type * [#10556](https://github.com/netbox-community/netbox/issues/10556) - Include a `display` field in all GraphQL object types * [#10595](https://github.com/netbox-community/netbox/issues/10595) - Add GraphQL relationships for additional generic foreign key fields +* [#10698](https://github.com/netbox-community/netbox/issues/10698) - Omit app label from content type in table columns * [#10761](https://github.com/netbox-community/netbox/issues/10761) - Enable associating an export template with multiple object types * [#10781](https://github.com/netbox-community/netbox/issues/10781) - Add support for Python v3.11 diff --git a/netbox/netbox/search/backends.py b/netbox/netbox/search/backends.py index 3aa6c4f47..dfc251aa9 100644 --- a/netbox/netbox/search/backends.py +++ b/netbox/netbox/search/backends.py @@ -11,7 +11,7 @@ from django.utils.module_loading import import_string from extras.models import CachedValue, CustomField from netbox.registry import registry from utilities.querysets import RestrictedPrefetch -from utilities.templatetags.builtins.filters import bettertitle +from utilities.utils import title from . import FieldTypes, LookupTypes, get_indexer DEFAULT_LOOKUP_TYPE = LookupTypes.PARTIAL @@ -34,8 +34,7 @@ class SearchBackend: # Organize choices by category categories = defaultdict(dict) for label, idx in registry['search'].items(): - title = bettertitle(idx.model._meta.verbose_name) - categories[idx.get_category()][label] = title + categories[idx.get_category()][label] = title(idx.model._meta.verbose_name) # Compile a nested tuple of choices for form rendering results = ( diff --git a/netbox/netbox/tables/columns.py b/netbox/netbox/tables/columns.py index c7545192a..5e92196e5 100644 --- a/netbox/netbox/tables/columns.py +++ b/netbox/netbox/tables/columns.py @@ -300,7 +300,7 @@ class ContentTypeColumn(tables.Column): def render(self, value): if value is None: return None - return content_type_name(value) + return content_type_name(value, include_app=False) def value(self, value): if value is None: @@ -319,7 +319,7 @@ class ContentTypesColumn(tables.ManyToManyColumn): super().__init__(separator=separator, *args, **kwargs) def transform(self, obj): - return content_type_name(obj) + return content_type_name(obj, include_app=False) def value(self, value): return ','.join([ diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py index 50c109be8..3a2e71084 100644 --- a/netbox/netbox/tables/tables.py +++ b/netbox/netbox/tables/tables.py @@ -12,8 +12,7 @@ from extras.models import CustomField, CustomLink from extras.choices import CustomFieldVisibilityChoices from netbox.tables import columns from utilities.paginator import EnhancedPaginator, get_paginate_count -from utilities.templatetags.builtins.filters import bettertitle -from utilities.utils import highlight_string +from utilities.utils import highlight_string, title __all__ = ( 'BaseTable', @@ -223,7 +222,7 @@ class SearchTable(tables.Table): def render_field(self, value, record): if hasattr(record.object, value): - return bettertitle(record.object._meta.get_field(value).verbose_name) + return title(record.object._meta.get_field(value).verbose_name) return value def render_value(self, value): diff --git a/netbox/utilities/templatetags/builtins/filters.py b/netbox/utilities/templatetags/builtins/filters.py index 6b548a89d..8c9315ffe 100644 --- a/netbox/utilities/templatetags/builtins/filters.py +++ b/netbox/utilities/templatetags/builtins/filters.py @@ -11,7 +11,7 @@ from markdown import markdown from netbox.config import get_config from utilities.markdown import StrikethroughExtension -from utilities.utils import clean_html, foreground_color +from utilities.utils import clean_html, foreground_color, title register = template.Library() @@ -46,7 +46,7 @@ def bettertitle(value): Alternative to the builtin title(). Ensures that the first letter of each word is uppercase but retains the original case of all others. """ - return ' '.join([w[0].upper() + w[1:] for w in value.split()]) + return title(value) @register.filter() diff --git a/netbox/utilities/utils.py b/netbox/utilities/utils.py index e1fbbfe84..a5bccfbea 100644 --- a/netbox/utilities/utils.py +++ b/netbox/utilities/utils.py @@ -21,6 +21,13 @@ from netbox.config import get_config from utilities.constants import HTTP_REQUEST_META_SAFE_COPY +def title(value): + """ + Improved implementation of str.title(); retains all existing uppercase letters. + """ + return ' '.join([w[0].upper() + w[1:] for w in str(value).split()]) + + def get_viewname(model, action=None, rest_api=False): """ Return the view name for the given model and action, if valid. @@ -393,13 +400,17 @@ def array_to_string(array): return ', '.join(ret) -def content_type_name(ct): +def content_type_name(ct, include_app=True): """ Return a human-friendly ContentType name (e.g. "DCIM > Site"). """ try: meta = ct.model_class()._meta - return f'{meta.app_config.verbose_name} > {meta.verbose_name}' + app_label = title(meta.app_config.verbose_name) + model_name = title(meta.verbose_name) + if include_app: + return f'{app_label} > {model_name}' + return model_name except AttributeError: # Model no longer exists return f'{ct.app_label} > {ct.model}'