diff --git a/netbox/core/ui/__init__.py b/netbox/core/ui/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/netbox/core/ui/panels.py b/netbox/core/ui/panels.py new file mode 100644 index 000000000..a2a0781bd --- /dev/null +++ b/netbox/core/ui/panels.py @@ -0,0 +1,91 @@ +from django.utils.translation import gettext_lazy as _ + +from netbox.ui import attrs, panels + + +class DataSourcePanel(panels.ObjectAttributesPanel): + title = _('Data Source') + name = attrs.TextAttr('name') + type = attrs.ChoiceAttr('type') + enabled = attrs.BooleanAttr('enabled') + status = attrs.ChoiceAttr('status') + sync_interval = attrs.ChoiceAttr('sync_interval', label=_('Sync interval')) + last_synced = attrs.DateTimeAttr('last_synced', label=_('Last synced')) + description = attrs.TextAttr('description') + source_url = attrs.TemplatedAttr( + 'source_url', + label=_('URL'), + template_name='core/datasource/attrs/source_url.html', + ) + ignore_rules = attrs.TemplatedAttr( + 'ignore_rules', + label=_('Ignore rules'), + template_name='core/datasource/attrs/ignore_rules.html', + ) + + +class DataSourceBackendPanel(panels.ObjectPanel): + template_name = 'core/panels/datasource_backend.html' + title = _('Backend') + + +class DataFilePanel(panels.ObjectAttributesPanel): + title = _('Data File') + source = attrs.RelatedObjectAttr('source', linkify=True) + path = attrs.TextAttr('path', style='font-monospace', copy_button=True) + last_updated = attrs.DateTimeAttr('last_updated') + size = attrs.TemplatedAttr('size', template_name='core/datafile/attrs/size.html') + hash = attrs.TextAttr('hash', label=_('SHA256 hash'), style='font-monospace', copy_button=True) + + +class DataFileContentPanel(panels.ObjectPanel): + template_name = 'core/panels/datafile_content.html' + title = _('Content') + + +class JobPanel(panels.ObjectAttributesPanel): + title = _('Job') + object_type = attrs.TemplatedAttr( + 'object_type', + label=_('Object type'), + template_name='core/job/attrs/object_type.html', + ) + name = attrs.TextAttr('name') + status = attrs.ChoiceAttr('status') + error = attrs.TextAttr('error') + user = attrs.TextAttr('user', label=_('Created by')) + + +class JobSchedulingPanel(panels.ObjectAttributesPanel): + title = _('Scheduling') + created = attrs.DateTimeAttr('created') + scheduled = attrs.TemplatedAttr('scheduled', template_name='core/job/attrs/scheduled.html') + started = attrs.DateTimeAttr('started') + completed = attrs.DateTimeAttr('completed') + queue = attrs.TextAttr('queue_name', label=_('Queue')) + + +class ObjectChangePanel(panels.ObjectAttributesPanel): + title = _('Change') + time = attrs.DateTimeAttr('time') + user = attrs.TemplatedAttr( + 'user_name', + label=_('User'), + template_name='core/objectchange/attrs/user.html', + ) + action = attrs.ChoiceAttr('action') + changed_object_type = attrs.TextAttr( + 'changed_object_type', + label=_('Object type'), + ) + changed_object = attrs.TemplatedAttr( + 'object_repr', + label=_('Object'), + template_name='core/objectchange/attrs/changed_object.html', + ) + message = attrs.TextAttr('message') + request_id = attrs.TemplatedAttr( + 'request_id', + label=_('Request ID'), + template_name='core/objectchange/attrs/request_id.html', + ) diff --git a/netbox/core/views.py b/netbox/core/views.py index 21e68d1b6..b7b5c6335 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -23,9 +23,20 @@ from rq.worker import Worker from rq.worker_registration import clean_worker_registry from core.utils import delete_rq_job, enqueue_rq_job, get_rq_jobs_from_status, requeue_rq_job, stop_rq_job +from extras.ui.panels import CustomFieldsPanel, TagsPanel from netbox.config import PARAMS, get_config from netbox.object_actions import AddObject, BulkDelete, BulkExport, DeleteObject from netbox.plugins.utils import get_installed_plugins +from netbox.ui import layout +from netbox.ui.panels import ( + CommentsPanel, + ContextTablePanel, + JSONPanel, + ObjectsTablePanel, + PluginContentPanel, + RelatedObjectsPanel, + TemplatePanel, +) from netbox.views import generic from netbox.views.generic.base import BaseObjectView from netbox.views.generic.mixins import TableMixin @@ -48,6 +59,7 @@ from .jobs import SyncDataSourceJob from .models import * from .plugins import get_catalog_plugins, get_local_plugins from .tables import CatalogPluginTable, JobLogEntryTable, PluginVersionTable +from .ui import panels # # Data sources @@ -67,6 +79,24 @@ class DataSourceListView(generic.ObjectListView): @register_model_view(DataSource) class DataSourceView(GetRelatedModelsMixin, generic.ObjectView): queryset = DataSource.objects.all() + layout = layout.SimpleLayout( + left_panels=[ + panels.DataSourcePanel(), + TagsPanel(), + CommentsPanel(), + ], + right_panels=[ + panels.DataSourceBackendPanel(), + RelatedObjectsPanel(), + CustomFieldsPanel(), + ], + bottom_panels=[ + ObjectsTablePanel( + model='core.DataFile', + filters={'source_id': lambda ctx: ctx['object'].pk}, + ), + ], + ) def get_extra_context(self, request, instance): return { @@ -157,6 +187,12 @@ class DataFileListView(generic.ObjectListView): class DataFileView(generic.ObjectView): queryset = DataFile.objects.all() actions = (DeleteObject,) + layout = layout.SimpleLayout( + left_panels=[ + panels.DataFilePanel(), + panels.DataFileContentPanel(), + ], + ) @register_model_view(DataFile, 'delete') @@ -188,6 +224,17 @@ class JobListView(generic.ObjectListView): class JobView(generic.ObjectView): queryset = Job.objects.all() actions = (DeleteObject,) + layout = layout.SimpleLayout( + left_panels=[ + panels.JobPanel(), + ], + right_panels=[ + panels.JobSchedulingPanel(), + ], + bottom_panels=[ + JSONPanel('data', title=_('Data')), + ], + ) @register_model_view(Job, 'log') @@ -200,6 +247,13 @@ class JobLogView(generic.ObjectView): badge=lambda obj: len(obj.log_entries), weight=500, ) + layout = layout.Layout( + layout.Row( + layout.Column( + ContextTablePanel('table', title=_('Log Entries')), + ), + ), + ) def get_extra_context(self, request, instance): table = JobLogEntryTable(instance.log_entries) @@ -241,6 +295,26 @@ class ObjectChangeListView(generic.ObjectListView): @register_model_view(ObjectChange) class ObjectChangeView(generic.ObjectView): queryset = None + layout = layout.Layout( + layout.Row( + layout.Column(panels.ObjectChangePanel()), + layout.Column(TemplatePanel('core/panels/objectchange_difference.html')), + ), + layout.Row( + layout.Column(TemplatePanel('core/panels/objectchange_prechange.html')), + layout.Column(TemplatePanel('core/panels/objectchange_postchange.html')), + ), + layout.Row( + layout.Column(PluginContentPanel('left_page')), + layout.Column(PluginContentPanel('right_page')), + ), + layout.Row( + layout.Column( + TemplatePanel('core/panels/objectchange_related.html'), + PluginContentPanel('full_width_page'), + ), + ), + ) def get_queryset(self, request): return ObjectChange.objects.valid_models() @@ -312,6 +386,14 @@ class ConfigRevisionListView(generic.ObjectListView): @register_model_view(ConfigRevision) class ConfigRevisionView(generic.ObjectView): queryset = ConfigRevision.objects.all() + layout = layout.Layout( + layout.Row( + layout.Column( + TemplatePanel('core/panels/configrevision_data.html'), + TemplatePanel('core/panels/configrevision_comment.html'), + ), + ), + ) def get_extra_context(self, request, instance): """ diff --git a/netbox/templates/core/configrevision.html b/netbox/templates/core/configrevision.html index 28179b7fd..2bd361a84 100644 --- a/netbox/templates/core/configrevision.html +++ b/netbox/templates/core/configrevision.html @@ -1,10 +1,7 @@ {% extends 'generic/object.html' %} {% load buttons %} -{% load custom_links %} {% load helpers %} {% load perms %} -{% load plugins %} -{% load static %} {% load i18n %} {% block breadcrumbs %} @@ -27,22 +24,3 @@ {% endif %} {% endblock subtitle %} - -{% block content %} -
-
-
-

{% trans "Configuration Data" %}

- {% include 'core/inc/config_data.html' %} -
- -
-

{% trans "Comment" %}

-
- {{ object.comment|placeholder }} -
-
- -
-
-{% endblock %} diff --git a/netbox/templates/core/datafile.html b/netbox/templates/core/datafile.html index 0747547b1..714ef22f8 100644 --- a/netbox/templates/core/datafile.html +++ b/netbox/templates/core/datafile.html @@ -1,62 +1,7 @@ {% extends 'generic/object.html' %} -{% load buttons %} -{% load custom_links %} -{% load helpers %} -{% load perms %} -{% load plugins %} {% load i18n %} {% block breadcrumbs %} {{ block.super }} {% endblock %} - -{% block content %} -
-
-
-

{% trans "Data File" %}

- - - - - - - - - - - - - - - - - - - - - -
{% trans "Source" %}{{ object.source|linkify }}
{% trans "Path" %} - {{ object.path }} - {% copy_content "datafile_path" %} -
{% trans "Last Updated" %}{{ object.last_updated }}
{% trans "Size" %}{{ object.size }} {% trans "bytes" %}
{% trans "SHA256 Hash" %} - {{ object.hash }} - {% copy_content "datafile_hash" %} -
-
-
-

{% trans "Content" %}

-
-
{{ object.data_as_string }}
-
-
- {% plugin_left_page object %} -
-
-
-
- {% plugin_full_width_page object %} -
-
-{% endblock %} diff --git a/netbox/templates/core/datafile/attrs/size.html b/netbox/templates/core/datafile/attrs/size.html new file mode 100644 index 000000000..ac54aca60 --- /dev/null +++ b/netbox/templates/core/datafile/attrs/size.html @@ -0,0 +1 @@ +{% load i18n %}{{ value }} {% trans "bytes" %} diff --git a/netbox/templates/core/datasource.html b/netbox/templates/core/datasource.html index 519e111af..07a7324ab 100644 --- a/netbox/templates/core/datasource.html +++ b/netbox/templates/core/datasource.html @@ -1,8 +1,4 @@ {% extends 'generic/object.html' %} -{% load static %} -{% load helpers %} -{% load plugins %} -{% load render_table from django_tables2 %} {% load i18n %} {% block extra_controls %} @@ -23,102 +19,3 @@ {% endif %} {% endif %} {% endblock %} - -{% block content %} -
-
-
-

{% trans "Data Source" %}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Name" %}{{ object.name }}
{% trans "Type" %}{{ object.get_type_display }}
{% trans "Enabled" %}{% checkmark object.enabled %}
{% trans "Status" %}{% badge object.get_status_display bg_color=object.get_status_color %}
{% trans "Sync interval" %}{{ object.get_sync_interval_display|placeholder }}
{% trans "Last synced" %}{{ object.last_synced|placeholder }}
{% trans "Description" %}{{ object.description|placeholder }}
{% trans "URL" %} - {% if not object.type.is_local %} - {{ object.source_url }} - {% else %} - {{ object.source_url }} - {% endif %} -
{% trans "Ignore rules" %} - {% if object.ignore_rules %} -
{{ object.ignore_rules }}
- {% else %} - {{ ''|placeholder }} - {% endif %}
-
- {% include 'inc/panels/tags.html' %} - {% include 'inc/panels/comments.html' %} - {% plugin_left_page object %} -
-
-
-

{% trans "Backend" %}

- {% with backend=object.backend_class %} - - {% for name, field in backend.parameters.items %} - - - {% if name in backend.sensitive_parameters %} - - {% else %} - - {% endif %} - - {% empty %} - - - - {% endfor %} -
{{ field.label }}********{{ object.parameters|get_key:name|placeholder }}
- {% trans "No parameters defined" %} -
- {% endwith %} -
- {% include 'inc/panels/related_objects.html' %} - {% include 'inc/panels/custom_fields.html' %} - {% plugin_right_page object %} -
-
-
-
-
-

{% trans "Files" %}

- {% htmx_table 'core:datafile_list' source_id=object.pk %} -
- {% plugin_full_width_page object %} -
-
-{% endblock %} diff --git a/netbox/templates/core/datasource/attrs/ignore_rules.html b/netbox/templates/core/datasource/attrs/ignore_rules.html new file mode 100644 index 000000000..ec1709b99 --- /dev/null +++ b/netbox/templates/core/datasource/attrs/ignore_rules.html @@ -0,0 +1 @@ +
{{ value }}
diff --git a/netbox/templates/core/datasource/attrs/source_url.html b/netbox/templates/core/datasource/attrs/source_url.html new file mode 100644 index 000000000..6a788c3eb --- /dev/null +++ b/netbox/templates/core/datasource/attrs/source_url.html @@ -0,0 +1 @@ +{% if not object.type.is_local %}{{ value }}{% else %}{{ value }}{% endif %} diff --git a/netbox/templates/core/job.html b/netbox/templates/core/job.html index 48adf0319..03302b939 100644 --- a/netbox/templates/core/job.html +++ b/netbox/templates/core/job.html @@ -1,78 +1 @@ {% extends 'core/job/base.html' %} -{% load i18n %} - -{% block content %} -
-
-
-

{% trans "Job" %}

- - - - - - - - - - - - - - {% if object.error %} - - - - - {% endif %} - - - - -
{% trans "Object Type" %} - {{ object.object_type }} -
{% trans "Name" %}{{ object.name|placeholder }}
{% trans "Status" %}{% badge object.get_status_display object.get_status_color %}
{% trans "Error" %}{{ object.error }}
{% trans "Created By" %}{{ object.user|placeholder }}
-
-
-
-
-

{% trans "Scheduling" %}

- - - - - - - - - - - - - - - - - - - - - -
{% trans "Created" %}{{ object.created|isodatetime }}
{% trans "Scheduled" %} - {{ object.scheduled|isodatetime|placeholder }} - {% if object.interval %} - ({% blocktrans with interval=object.interval %}every {{ interval }} minutes{% endblocktrans %}) - {% endif %} -
{% trans "Started" %}{{ object.started|isodatetime|placeholder }}
{% trans "Completed" %}{{ object.completed|isodatetime|placeholder }}
{% trans "Queue" %}{{ object.queue_name|placeholder }}
-
-
-
-
-
-
-

{% trans "Data" %}

-
{{ object.data|json }}
-
-
-
-{% endblock %} diff --git a/netbox/templates/core/job/attrs/object_type.html b/netbox/templates/core/job/attrs/object_type.html new file mode 100644 index 000000000..fd3937c17 --- /dev/null +++ b/netbox/templates/core/job/attrs/object_type.html @@ -0,0 +1 @@ +{{ value }} diff --git a/netbox/templates/core/job/attrs/scheduled.html b/netbox/templates/core/job/attrs/scheduled.html new file mode 100644 index 000000000..2af7fdd49 --- /dev/null +++ b/netbox/templates/core/job/attrs/scheduled.html @@ -0,0 +1,3 @@ +{% load helpers %} +{% load i18n %} +{{ value|isodatetime }}{% if object.interval %} ({% blocktrans with interval=object.interval %}every {{ interval }} minutes{% endblocktrans %}){% endif %} diff --git a/netbox/templates/core/job/log.html b/netbox/templates/core/job/log.html index b8c727299..03302b939 100644 --- a/netbox/templates/core/job/log.html +++ b/netbox/templates/core/job/log.html @@ -1,12 +1 @@ {% extends 'core/job/base.html' %} -{% load render_table from django_tables2 %} - -{% block content %} -
-
-
- {% render_table table %} -
-
-
-{% endblock %} diff --git a/netbox/templates/core/objectchange.html b/netbox/templates/core/objectchange.html index e4c7d4900..3f883bea8 100644 --- a/netbox/templates/core/objectchange.html +++ b/netbox/templates/core/objectchange.html @@ -1,6 +1,4 @@ {% extends 'generic/object.html' %} -{% load helpers %} -{% load plugins %} {% load i18n %} {% block title %}{{ object }}{% endblock %} @@ -21,161 +19,3 @@ {# ObjectChange does not support the default add/edit/delete controls #} {% block control-buttons %}{% endblock %} {% block subtitle %}{% endblock %} - -{% block content %} -
-
-
-

{% trans "Change" %}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{% trans "Time" %}{{ object.time|isodatetime }}
{% trans "User" %} - {% if object.user.get_full_name %} - {{ object.user.get_full_name }} ({{ object.user_name }}) - {% else %} - {{ object.user_name }} - {% endif %} -
{% trans "Action" %} - {{ object.get_action_display }} -
{% trans "Object Type" %} - {{ object.changed_object_type }} -
{% trans "Object" %} - {% if object.changed_object and object.changed_object.get_absolute_url %} - {{ object.changed_object|linkify }} - {% else %} - {{ object.object_repr }} - {% endif %} -
{% trans "Message" %} - {{ object.message|placeholder }} -
{% trans "Request ID" %} - {{ object.request_id }} -
-
-
-
-
-

- {% trans "Difference" %} - -

-
- {% if diff_added == diff_removed %} - - {% if object.action == 'create' %} - {% trans "Object Created" %} - {% elif object.action == 'delete' %} - {% trans "Object Deleted" %} - {% else %} - {% trans "No Changes" %} - {% endif %} - - {% else %} -
{{ diff_removed|json }}
-
{{ diff_added|json }}
- {% endif %} -
-
-
-
-
-
-
-

{% trans "Pre-Change Data" %}

-
- {% if object.prechange_data %} - {% spaceless %} -
-                  {% for k, v in object.prechange_data_clean.items %}
-                    {{ k }}: {{ v|json }}
-                  {% endfor %}
-                
- {% endspaceless %} - {% elif non_atomic_change %} - {% trans "Warning: Comparing non-atomic change to previous change record" %} ({{ prev_change.pk }}) - {% else %} - {% trans "None" %} - {% endif %} -
-
-
-
-
-

{% trans "Post-Change Data" %}

-
- {% if object.postchange_data %} - {% spaceless %} -
-                      {% for k, v in object.postchange_data_clean.items %}
-                        {{ k }}: {{ v|json }}
-                      {% endfor %}
-                    
- {% endspaceless %} - {% else %} - {% trans "None" %} - {% endif %} -
-
-
-
-
-
- {% plugin_left_page object %} -
-
- {% plugin_right_page object %} -
-
-
-
- {% include 'inc/panel_table.html' with table=related_changes_table heading='Related Changes' panel_class='default' %} - {% if related_changes_count > related_changes_table.rows|length %} - - {% endif %} -
-
-
-
- {% plugin_full_width_page object %} -
-
-{% endblock %} diff --git a/netbox/templates/core/objectchange/attrs/changed_object.html b/netbox/templates/core/objectchange/attrs/changed_object.html new file mode 100644 index 000000000..e3d8abe33 --- /dev/null +++ b/netbox/templates/core/objectchange/attrs/changed_object.html @@ -0,0 +1,2 @@ +{% load helpers %} +{% if object.changed_object and object.changed_object.get_absolute_url %}{{ object.changed_object|linkify }}{% else %}{{ value }}{% endif %} diff --git a/netbox/templates/core/objectchange/attrs/request_id.html b/netbox/templates/core/objectchange/attrs/request_id.html new file mode 100644 index 000000000..92011812f --- /dev/null +++ b/netbox/templates/core/objectchange/attrs/request_id.html @@ -0,0 +1 @@ +{{ value }} diff --git a/netbox/templates/core/objectchange/attrs/user.html b/netbox/templates/core/objectchange/attrs/user.html new file mode 100644 index 000000000..e897078c3 --- /dev/null +++ b/netbox/templates/core/objectchange/attrs/user.html @@ -0,0 +1 @@ +{% if object.user and object.user.get_full_name %}{{ object.user.get_full_name }} ({{ value }}){% else %}{{ value }}{% endif %} diff --git a/netbox/templates/core/panels/configrevision_comment.html b/netbox/templates/core/panels/configrevision_comment.html new file mode 100644 index 000000000..5ce365522 --- /dev/null +++ b/netbox/templates/core/panels/configrevision_comment.html @@ -0,0 +1,11 @@ +{% load i18n %} +
+

{% trans "Comment" %}

+
+ {% if object.comment %} + {{ object.comment }} + {% else %} + + {% endif %} +
+
diff --git a/netbox/templates/core/panels/configrevision_data.html b/netbox/templates/core/panels/configrevision_data.html new file mode 100644 index 000000000..461e2ab82 --- /dev/null +++ b/netbox/templates/core/panels/configrevision_data.html @@ -0,0 +1,5 @@ +{% load i18n %} +
+

{% trans "Configuration Data" %}

+ {% include 'core/inc/config_data.html' %} +
diff --git a/netbox/templates/core/panels/datafile_content.html b/netbox/templates/core/panels/datafile_content.html new file mode 100644 index 000000000..90702964e --- /dev/null +++ b/netbox/templates/core/panels/datafile_content.html @@ -0,0 +1,8 @@ +{% extends "ui/panels/_base.html" %} +{% load i18n %} + +{% block panel_content %} +
+
{{ object.data_as_string }}
+
+{% endblock panel_content %} diff --git a/netbox/templates/core/panels/datasource_backend.html b/netbox/templates/core/panels/datasource_backend.html new file mode 100644 index 000000000..97d7ae573 --- /dev/null +++ b/netbox/templates/core/panels/datasource_backend.html @@ -0,0 +1,26 @@ +{% extends "ui/panels/_base.html" %} +{% load helpers %} +{% load i18n %} + +{% block panel_content %} + {% with backend=object.backend_class %} + + {% for name, field in backend.parameters.items %} + + + {% if name in backend.sensitive_parameters %} + + {% else %} + + {% endif %} + + {% empty %} + + + + {% endfor %} +
{{ field.label }}********{{ object.parameters|get_key:name|placeholder }}
+ {% trans "No parameters defined" %} +
+ {% endwith %} +{% endblock panel_content %} diff --git a/netbox/templates/core/panels/objectchange_difference.html b/netbox/templates/core/panels/objectchange_difference.html new file mode 100644 index 000000000..5c954ee56 --- /dev/null +++ b/netbox/templates/core/panels/objectchange_difference.html @@ -0,0 +1,31 @@ +{% load helpers %} +{% load i18n %} +
+

+ {% trans "Difference" %} + +

+
+ {% if diff_added == diff_removed %} + + {% if object.action == 'create' %} + {% trans "Object Created" %} + {% elif object.action == 'delete' %} + {% trans "Object Deleted" %} + {% else %} + {% trans "No Changes" %} + {% endif %} + + {% else %} +
{{ diff_removed|json }}
+
{{ diff_added|json }}
+ {% endif %} +
+
diff --git a/netbox/templates/core/panels/objectchange_postchange.html b/netbox/templates/core/panels/objectchange_postchange.html new file mode 100644 index 000000000..903ec9586 --- /dev/null +++ b/netbox/templates/core/panels/objectchange_postchange.html @@ -0,0 +1,18 @@ +{% load helpers %} +{% load i18n %} +
+

{% trans "Post-Change Data" %}

+
+ {% if object.postchange_data %} + {% spaceless %} +
+          {% for k, v in object.postchange_data_clean.items %}
+            {{ k }}: {{ v|json }}
+          {% endfor %}
+        
+ {% endspaceless %} + {% else %} + {% trans "None" %} + {% endif %} +
+
diff --git a/netbox/templates/core/panels/objectchange_prechange.html b/netbox/templates/core/panels/objectchange_prechange.html new file mode 100644 index 000000000..057f59731 --- /dev/null +++ b/netbox/templates/core/panels/objectchange_prechange.html @@ -0,0 +1,20 @@ +{% load helpers %} +{% load i18n %} +
+

{% trans "Pre-Change Data" %}

+
+ {% if object.prechange_data %} + {% spaceless %} +
+          {% for k, v in object.prechange_data_clean.items %}
+            {{ k }}: {{ v|json }}
+          {% endfor %}
+        
+ {% endspaceless %} + {% elif non_atomic_change %} + {% trans "Warning: Comparing non-atomic change to previous change record" %} ({{ prev_change.pk }}) + {% else %} + {% trans "None" %} + {% endif %} +
+
diff --git a/netbox/templates/core/panels/objectchange_related.html b/netbox/templates/core/panels/objectchange_related.html new file mode 100644 index 000000000..27d26d3f1 --- /dev/null +++ b/netbox/templates/core/panels/objectchange_related.html @@ -0,0 +1,11 @@ +{% load i18n %} +{% include 'inc/panel_table.html' with table=related_changes_table heading='Related Changes' panel_class='default' %} +{% if related_changes_count > related_changes_table.rows|length %} +
+ + {% blocktrans trimmed with count=related_changes_count|add:"1" %} + See All {{ count }} Changes + {% endblocktrans %} + +
+{% endif %}