From 62bdb90f61c2b83148b3c0008d64e5b2168db036 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Thu, 6 Jul 2023 23:49:55 +0530 Subject: [PATCH] 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 --- netbox/ipam/tables/ip.py | 31 ++++++++++++++++-- netbox/project-static/dist/netbox.js | Bin 530632 -> 530613 bytes netbox/project-static/dist/netbox.js.map | Bin 450874 -> 450868 bytes netbox/project-static/src/clipboard.ts | 2 +- netbox/templates/core/datafile.html | 8 ++--- netbox/templates/dcim/device.html | 6 ++-- .../templates/dcim/virtualdevicecontext.html | 14 ++++++-- netbox/templates/users/api_token.html | 6 ++-- .../virtualization/virtualmachine.html | 6 ++-- netbox/users/tables.py | 4 +-- .../templates/builtins/copy_content.html | 3 ++ .../utilities/templatetags/builtins/tags.py | 12 +++++++ 12 files changed, 69 insertions(+), 23 deletions(-) create mode 100644 netbox/utilities/templates/builtins/copy_content.html diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 86d1a3775..aff090f3a 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -19,14 +19,22 @@ __all__ = ( AVAILABLE_LABEL = mark_safe('Available') +AGGREGATE_COPY_BUTTON = """ +{% copy_content record.pk prefix="aggregate_" %} +""" + PREFIX_LINK = """ {% if record.pk %} - {{ record.prefix }} + {{ record.prefix }} {% else %} {{ record.prefix }} {% 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 %} - {{ record.address }} + {{ record.address }} {% elif perms.ipam.add_ipaddress %} {% if record.0 <= 65536 %}{{ record.0 }}{% else %}Many{% endif %} IP{{ record.0|pluralize }} available {% else %} @@ -48,6 +56,10 @@ IPADDRESS_LINK = """ {% endif %} """ +IPADDRESS_COPY_BUTTON = """ +{% copy_content record.pk prefix="ipaddress_" %} +""" + IPADDRESS_ASSIGN_LINK = """ {{ record }} """ @@ -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 diff --git a/netbox/project-static/dist/netbox.js b/netbox/project-static/dist/netbox.js index 9642d15851c5238db66f5a46ac81880ce2f10e1f..b62436d757a2b299e5bf0f33dcc4fbd67ec21e8c 100644 GIT binary patch delta 40 wcmX@HQDN&wg@zW!7N!>F7M2#)7Pc+yaw2TW`FSO&dF|#R?Ay&nI3}_H03@djzW@LL delta 59 zcmdnGQQ^c!g@zW!7N!>F7M2#)7Pc+yaw3u?`Pr#?N;*nOr6nc#d3wqD1(mwRsmVpD P?J6Sd+f_t3Cb9qkYoQZ* diff --git a/netbox/project-static/dist/netbox.js.map b/netbox/project-static/dist/netbox.js.map index f86d50148d419322456611b15cb949883cc3d9c2..ed3833f982a5d0f0d81c6bcf7e90a86aeb99d789 100644 GIT binary patch delta 34 qcmdmWNP5d5>4p}@7N!>F7M2#)Eo^FBY}rnZ&Kb_zjkwr2t^)wp@(S<( delta 40 wcmdmTNP5>H>4p}@7N!>F7M2#)Eo^FBJgJV3=}tPuPL9qQF57ju*f_2O03L1(wEzGB diff --git a/netbox/project-static/src/clipboard.ts b/netbox/project-static/src/clipboard.ts index a04acba39..46ca5e36c 100644 --- a/netbox/project-static/src/clipboard.ts +++ b/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); } } diff --git a/netbox/templates/core/datafile.html b/netbox/templates/core/datafile.html index 3d79d17e2..785617ae5 100644 --- a/netbox/templates/core/datafile.html +++ b/netbox/templates/core/datafile.html @@ -39,9 +39,7 @@ Path {{ object.path }} - - - + {% copy_content "datafile_path" %} @@ -56,9 +54,7 @@ SHA256 Hash {{ object.hash }} - - - + {% copy_content "datafile_hash" %} diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index b0e67269c..df5209add 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -194,12 +194,13 @@ Primary IPv4 {% if object.primary_ip4 %} - {{ object.primary_ip4.address.ip }} + {{ object.primary_ip4.address.ip }} {% if object.primary_ip4.nat_inside %} (NAT for {{ object.primary_ip4.nat_inside.address.ip }}) {% elif object.primary_ip4.nat_outside.exists %} (NAT: {% for nat in object.primary_ip4.nat_outside.all %}{{ nat.address.ip }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% endif %} + {% copy_content "primary_ip4" %} {% else %} {{ ''|placeholder }} {% endif %} @@ -209,12 +210,13 @@ Primary IPv6 {% if object.primary_ip6 %} - {{ object.primary_ip6.address.ip }} + {{ object.primary_ip6.address.ip }} {% if object.primary_ip6.nat_inside %} (NAT for {{ object.primary_ip6.nat_inside.address.ip }}) {% elif object.primary_ip6.nat_outside.exists %} (NAT: {% for nat in object.primary_ip6.nat_outside.all %}{{ nat.address.ip }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% endif %} + {% copy_content "primary_ip6" %} {% else %} {{ ''|placeholder }} {% endif %} diff --git a/netbox/templates/dcim/virtualdevicecontext.html b/netbox/templates/dcim/virtualdevicecontext.html index d6e3e0c63..1caf05bd2 100644 --- a/netbox/templates/dcim/virtualdevicecontext.html +++ b/netbox/templates/dcim/virtualdevicecontext.html @@ -31,13 +31,23 @@ Primary IPv4 - {{ object.primary_ip4|linkify|placeholder }} + {% if object.primary_ip4 %} + {{ object.primary_ip4 }} + {% copy_content "primary_ip4" %} + {% else %} + + {% endif %} Primary IPv6 - {{ object.primary_ip6|linkify|placeholder }} + {% if object.primary_ip6 %} + {{ object.primary_ip6 }} + {% copy_content "primary_ip6" %} + {% else %} + + {% endif %} diff --git a/netbox/templates/users/api_token.html b/netbox/templates/users/api_token.html index 1a9296704..7fd6f064d 100644 --- a/netbox/templates/users/api_token.html +++ b/netbox/templates/users/api_token.html @@ -8,7 +8,7 @@
{% if not settings.ALLOW_TOKEN_RETRIEVAL %} {% endif %}
@@ -19,9 +19,7 @@ Key
- - - + {% copy_content "token_id" %}
{{ key }}
diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index 51fd8aa80..3d3b498ad 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -46,12 +46,13 @@ Primary IPv4 {% if object.primary_ip4 %} - {{ object.primary_ip4.address.ip }} + {{ object.primary_ip4.address.ip }} {% if object.primary_ip4.nat_inside %} (NAT for {{ object.primary_ip4.nat_inside.address.ip }}) {% elif object.primary_ip4.nat_outside.exists %} (NAT: {% for nat in object.primary_ip4.nat_outside.all %}{{ nat.address.ip }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% endif %} + {% copy_content "primary_ip4" %} {% else %} {{ ''|placeholder }} {% endif %} @@ -61,12 +62,13 @@ Primary IPv6 {% if object.primary_ip6 %} - {{ object.primary_ip6.address.ip }} + {{ object.primary_ip6.address.ip }} {% if object.primary_ip6.nat_inside %} (NAT for {{ object.primary_ip6.nat_inside.address.ip }}) {% elif object.primary_ip6.nat_outside.exists %} (NAT: {% for nat in object.primary_ip6.nat_outside.all %}{{ nat.address.ip }}{% if not forloop.last %}, {% endif %}{% endfor %}) {% endif %} + {% copy_content "primary_ip6" %} {% else %} {{ ''|placeholder }} {% endif %} diff --git a/netbox/users/tables.py b/netbox/users/tables.py index 0f1484887..cea50b10f 100644 --- a/netbox/users/tables.py +++ b/netbox/users/tables.py @@ -12,9 +12,7 @@ ALLOWED_IPS = """{{ value|join:", " }}""" COPY_BUTTON = """ {% if settings.ALLOW_TOKEN_RETRIEVAL %} - - - + {% copy_content record.pk prefix="token_" color="success" %} {% endif %} """ diff --git a/netbox/utilities/templates/builtins/copy_content.html b/netbox/utilities/templates/builtins/copy_content.html new file mode 100644 index 000000000..9025a71a1 --- /dev/null +++ b/netbox/utilities/templates/builtins/copy_content.html @@ -0,0 +1,3 @@ + + + diff --git a/netbox/utilities/templatetags/builtins/tags.py b/netbox/utilities/templatetags/builtins/tags.py index f9fe5f4e3..35aec1000 100644 --- a/netbox/utilities/templatetags/builtins/tags.py +++ b/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): """