Przeglądaj źródła

Adds copy content button (#12584)

* adds copy content button #12499

* adds newline

* Omit hash mark from target string

* Clean up HTML element IDs

---------

Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Abhimanyu Saharan 2 lat temu
rodzic
commit
62bdb90f61

+ 28 - 3
netbox/ipam/tables/ip.py

@@ -19,14 +19,22 @@ __all__ = (
 
 AVAILABLE_LABEL = mark_safe('<span class="badge bg-success">Available</span>')
 
+AGGREGATE_COPY_BUTTON = """
+{% copy_content record.pk prefix="aggregate_" %}
+"""
+
 PREFIX_LINK = """
 {% if record.pk %}
-  <a href="{{ record.get_absolute_url }}">{{ record.prefix }}</a>
+  <a href="{{ record.get_absolute_url }}" id="prefix_{{ record.pk }}">{{ record.prefix }}</a>
 {% else %}
   <a href="{% url 'ipam:prefix_add' %}?prefix={{ record }}{% if object.vrf %}&vrf={{ object.vrf.pk }}{% endif %}{% if object.site %}&site={{ object.site.pk }}{% endif %}{% if object.tenant %}&tenant_group={{ object.tenant.group.pk }}&tenant={{ object.tenant.pk }}{% endif %}">{{ record.prefix }}</a>
 {% endif %}
 """
 
+PREFIX_COPY_BUTTON = """
+{% copy_content record.pk prefix="prefix_" %}
+"""
+
 PREFIX_LINK_WITH_DEPTH = """
 {% load helpers %}
 {% if record.depth %}
@@ -40,7 +48,7 @@ PREFIX_LINK_WITH_DEPTH = """
 
 IPADDRESS_LINK = """
 {% if record.pk %}
-    <a href="{{ record.get_absolute_url }}">{{ record.address }}</a>
+    <a href="{{ record.get_absolute_url }}" id="ipaddress_{{ record.pk }}">{{ record.address }}</a>
 {% elif perms.ipam.add_ipaddress %}
     <a href="{% url 'ipam:ipaddress_add' %}?address={{ record.1 }}{% if object.vrf %}&vrf={{ object.vrf.pk }}{% endif %}{% if object.tenant %}&tenant={{ object.tenant.pk }}{% endif %}" class="btn btn-sm btn-success">{% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available</a>
 {% else %}
@@ -48,6 +56,10 @@ IPADDRESS_LINK = """
 {% endif %}
 """
 
+IPADDRESS_COPY_BUTTON = """
+{% copy_content record.pk prefix="ipaddress_" %}
+"""
+
 IPADDRESS_ASSIGN_LINK = """
 <a href="{% url 'ipam:ipaddress_edit' pk=record.pk %}?{% if request.GET.interface %}interface={{ request.GET.interface }}{% elif request.GET.vminterface %}vminterface={{ request.GET.vminterface }}{% endif %}&return_url={{ request.GET.return_url }}">{{ record }}</a>
 """
@@ -99,7 +111,11 @@ class RIRTable(NetBoxTable):
 class AggregateTable(TenancyColumnsMixin, NetBoxTable):
     prefix = tables.Column(
         linkify=True,
-        verbose_name='Aggregate'
+        verbose_name='Aggregate',
+        attrs={
+            # Allow the aggregate to be copied to the clipboard
+            'a': {'id': lambda record: f"aggregate_{record.pk}"}
+        }
     )
     date_added = tables.DateColumn(
         format="Y-m-d",
@@ -116,6 +132,9 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable):
     tags = columns.TagColumn(
         url_name='ipam:aggregate_list'
     )
+    actions = columns.ActionsColumn(
+        extra_buttons=AGGREGATE_COPY_BUTTON
+    )
 
     class Meta(NetBoxTable.Meta):
         model = Aggregate
@@ -242,6 +261,9 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable):
     tags = columns.TagColumn(
         url_name='ipam:prefix_list'
     )
+    actions = columns.ActionsColumn(
+        extra_buttons=PREFIX_COPY_BUTTON
+    )
 
     class Meta(NetBoxTable.Meta):
         model = Prefix
@@ -348,6 +370,9 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable):
     tags = columns.TagColumn(
         url_name='ipam:ipaddress_list'
     )
+    actions = columns.ActionsColumn(
+        extra_buttons=IPADDRESS_COPY_BUTTON
+    )
 
     class Meta(NetBoxTable.Meta):
         model = IPAddress

Plik diff jest za duży
+ 0 - 0
netbox/project-static/dist/netbox.js


Plik diff jest za duży
+ 0 - 0
netbox/project-static/dist/netbox.js.map


+ 1 - 1
netbox/project-static/src/clipboard.ts

@@ -2,7 +2,7 @@ import Clipboard from 'clipboard';
 import { getElements } from './util';
 
 export function initClipboard(): void {
-  for (const element of getElements('a.copy-token', 'button.copy-secret')) {
+  for (const element of getElements('a.copy-content')) {
     new Clipboard(element);
   }
 }

+ 2 - 6
netbox/templates/core/datafile.html

@@ -39,9 +39,7 @@
               <th scope="row">Path</th>
               <td>
                 <span class="font-monospace" id="datafile_path">{{ object.path }}</span>
-                <a class="btn btn-sm btn-primary copy-token" data-clipboard-target="#datafile_path" title="Copy to clipboard">
-                  <i class="mdi mdi-content-copy"></i>
-                </a>
+                {% copy_content "datafile_path" %}
               </td>
             </tr>
             <tr>
@@ -56,9 +54,7 @@
               <th scope="row">SHA256 Hash</th>
               <td>
               <span class="font-monospace" id="datafile_hash">{{ object.hash }}</span>
-                <a class="btn btn-sm btn-primary copy-token" data-clipboard-target="#datafile_hash" title="Copy to clipboard">
-                  <i class="mdi mdi-content-copy"></i>
-                </a>
+                {% copy_content "datafile_hash" %}
               </td>
             </tr>
           </table>

+ 4 - 2
netbox/templates/dcim/device.html

@@ -194,12 +194,13 @@
                             <th scope="row">Primary IPv4</th>
                             <td>
                               {% if object.primary_ip4 %}
-                                <a href="{{ object.primary_ip4.get_absolute_url }}">{{ object.primary_ip4.address.ip }}</a>
+                                <a href="{{ object.primary_ip4.get_absolute_url }}" id="primary_ip4">{{ object.primary_ip4.address.ip }}</a>
                                 {% if object.primary_ip4.nat_inside %}
                                   (NAT for <a href="{{ object.primary_ip4.nat_inside.get_absolute_url }}">{{ object.primary_ip4.nat_inside.address.ip }}</a>)
                                 {% elif object.primary_ip4.nat_outside.exists %}
                                   (NAT: {% for nat in object.primary_ip4.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
                                 {% endif %}
+                                {% copy_content "primary_ip4" %}
                               {% else %}
                                 {{ ''|placeholder }}
                               {% endif %}
@@ -209,12 +210,13 @@
                             <th scope="row">Primary IPv6</th>
                             <td>
                               {% if object.primary_ip6 %}
-                                <a href="{{ object.primary_ip6.get_absolute_url }}">{{ object.primary_ip6.address.ip }}</a>
+                                <a href="{{ object.primary_ip6.get_absolute_url }}" id="primary_ip6">{{ object.primary_ip6.address.ip }}</a>
                                 {% if object.primary_ip6.nat_inside %}
                                   (NAT for <a href="{{ object.primary_ip6.nat_inside.get_absolute_url }}">{{ object.primary_ip6.nat_inside.address.ip }}</a>)
                                 {% elif object.primary_ip6.nat_outside.exists %}
                                   (NAT: {% for nat in object.primary_ip6.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
                                 {% endif %}
+                                {% copy_content "primary_ip6" %}
                               {% else %}
                                 {{ ''|placeholder }}
                               {% endif %}

+ 12 - 2
netbox/templates/dcim/virtualdevicecontext.html

@@ -31,13 +31,23 @@
           <tr>
             <th scope="row">Primary IPv4</th>
             <td>
-              {{ object.primary_ip4|linkify|placeholder }}
+              {% if object.primary_ip4 %}
+                <a href="{{ object.primary_ip4.get_absolute_url }}" id="primary_ip4">{{ object.primary_ip4 }}</a>
+                {% copy_content "primary_ip4" %}
+             {% else %}
+                <span class="text-muted">—</span>
+             {% endif %}
             </td>
           </tr>
           <tr>
             <th scope="row">Primary IPv6</th>
             <td>
-              {{ object.primary_ip6|linkify|placeholder }}
+              {% if object.primary_ip6 %}
+                <a href="{{ object.primary_ip6.get_absolute_url }}" id="primary_ip6">{{ object.primary_ip6 }}</a>
+                {% copy_content "primary_ip6" %}
+             {% else %}
+                <span class="text-muted">—</span>
+             {% endif %}
             </td>
           </tr>
           <tr>

+ 2 - 4
netbox/templates/users/api_token.html

@@ -8,7 +8,7 @@
     <div class="col col-md-12">
       {% if not settings.ALLOW_TOKEN_RETRIEVAL %}
         <div class="alert alert-danger" role="alert">
-          <i class="mdi mdi-alert"></i> Tokens cannot be retrieved at a later time. You must <a href="#" class="copy-token" data-clipboard-target="#token_id" title="Copy to clipboard">copy the token value</a> below and store it securely.
+          <i class="mdi mdi-alert"></i> Tokens cannot be retrieved at a later time. You must <a href="#" class="copy-content" data-clipboard-target="#token_id" title="Copy to clipboard">copy the token value</a> below and store it securely.
         </div>
       {% endif %}
       <div class="card">
@@ -19,9 +19,7 @@
               <th scope="row">Key</th>
               <td>
                 <div class="float-end">
-                  <a class="btn btn-sm btn-success copy-token" data-clipboard-target="#token_id" title="Copy to clipboard">
-                    <i class="mdi mdi-content-copy"></i>
-                  </a>
+                  {% copy_content "token_id" %}
                 </div>
                 <div id="token_id">{{ key }}</div>
               </td>

+ 4 - 2
netbox/templates/virtualization/virtualmachine.html

@@ -46,12 +46,13 @@
                         <th scope="row">Primary IPv4</th>
                         <td>
                           {% if object.primary_ip4 %}
-                            <a href="{% url 'ipam:ipaddress' pk=object.primary_ip4.pk %}">{{ object.primary_ip4.address.ip }}</a>
+                            <a href="{% url 'ipam:ipaddress' pk=object.primary_ip4.pk %}" id="primary_ip4">{{ object.primary_ip4.address.ip }}</a>
                             {% if object.primary_ip4.nat_inside %}
                               (NAT for <a href="{{ object.primary_ip4.nat_inside.get_absolute_url }}">{{ object.primary_ip4.nat_inside.address.ip }}</a>)
                             {% elif object.primary_ip4.nat_outside.exists %}
                               (NAT: {% for nat in object.primary_ip4.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
                             {% endif %}
+                            {% copy_content "primary_ip4" %}
                           {% else %}
                             {{ ''|placeholder }}
                           {% endif %}
@@ -61,12 +62,13 @@
                         <th scope="row">Primary IPv6</th>
                         <td>
                           {% if object.primary_ip6 %}
-                            <a href="{% url 'ipam:ipaddress' pk=object.primary_ip6.pk %}">{{ object.primary_ip6.address.ip }}</a>
+                            <a href="{% url 'ipam:ipaddress' pk=object.primary_ip6.pk %}" id="primary_ip6">{{ object.primary_ip6.address.ip }}</a>
                             {% if object.primary_ip6.nat_inside %}
                               (NAT for <a href="{{ object.primary_ip6.nat_inside.get_absolute_url }}">{{ object.primary_ip6.nat_inside.address.ip }}</a>)
                             {% elif object.primary_ip6.nat_outside.exists %}
                               (NAT: {% for nat in object.primary_ip6.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
                             {% endif %}
+                            {% copy_content "primary_ip6" %}
                           {% else %}
                             {{ ''|placeholder }}
                           {% endif %}

+ 1 - 3
netbox/users/tables.py

@@ -12,9 +12,7 @@ ALLOWED_IPS = """{{ value|join:", " }}"""
 
 COPY_BUTTON = """
 {% if settings.ALLOW_TOKEN_RETRIEVAL %}
-  <a class="btn btn-sm btn-success copy-token" data-clipboard-target="#token_{{ record.pk }}" title="Copy to clipboard">
-    <i class="mdi mdi-content-copy"></i>
-  </a>
+  {% copy_content record.pk prefix="token_" color="success" %}
 {% endif %}
 """
 

+ 3 - 0
netbox/utilities/templates/builtins/copy_content.html

@@ -0,0 +1,3 @@
+<a class="btn btn-sm {{ color }} copy-content" data-clipboard-target="{{ target }}" title="Copy to clipboard">
+  <i class="mdi mdi-content-copy"></i>
+</a>

+ 12 - 0
netbox/utilities/templatetags/builtins/tags.py

@@ -6,6 +6,7 @@ from utilities.utils import dict_to_querydict
 __all__ = (
     'badge',
     'checkmark',
+    'copy_content',
     'customfield_value',
     'tag',
 )
@@ -79,6 +80,17 @@ def checkmark(value, show_false=True, true='Yes', false='No'):
     }
 
 
+@register.inclusion_tag('builtins/copy_content.html')
+def copy_content(target, prefix=None, color='primary'):
+    """
+    Display a copy button to copy the content of a field.
+    """
+    return {
+        'target': f'#{prefix or ""}{target}',
+        'color': f'btn-{color}'
+    }
+
+
 @register.inclusion_tag('builtins/htmx_table.html', takes_context=True)
 def htmx_table(context, viewname, return_url=None, **kwargs):
     """

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików