From 6bd95f3b1515ad7142de041c66760b16dc2d5a4e Mon Sep 17 00:00:00 2001 From: Lavissa Date: Tue, 2 May 2023 00:13:50 +0200 Subject: [PATCH] Link changes and in-table clipboards (#4697) * Add clipboard to tables and external link changes * Clipboard icon added to tables for screens >1200px wide. Enables copying of SKU/MPN/IPN from table cells where these otherwise are hyperlinks * External links now open in new tabs with noreferrer * Move external links into separate template * All statically rendered external links have been moved out to a new template. --- InvenTree/InvenTree/static/css/inventree.css | 8 ++++- InvenTree/build/templates/build/detail.html | 2 +- .../templates/company/manufacturer_part.html | 2 +- .../templates/company/supplier_part.html | 2 +- .../order/templates/order/order_base.html | 4 +-- .../templates/order/return_order_base.html | 4 +-- .../templates/order/sales_order_base.html | 4 +-- InvenTree/part/templates/part/part_base.html | 2 +- .../stock/templates/stock/item_base.html | 2 +- InvenTree/templates/clip_link.html | 5 +++ InvenTree/templates/js/translated/company.js | 10 +++--- InvenTree/templates/js/translated/helpers.js | 31 ++++++++++++++++++- InvenTree/templates/js/translated/part.js | 4 +-- .../templates/js/translated/purchase_order.js | 6 ++-- InvenTree/templates/js/translated/stock.js | 4 +-- 15 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 InvenTree/templates/clip_link.html diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index c5bc9ea58e..288c6f6581 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -1094,4 +1094,10 @@ a { .sso-provider-link a { width: 100%; text-align: left; -} \ No newline at end of file +} + +.flex-cell { + display: flex; + align-items: center; + justify-content: space-between; +} diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 66933629a8..9e4d7c1afb 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -106,7 +106,7 @@ {% trans "External Link" %} - {{ build.link }}{% include "clip.html"%} + {% include 'clip_link.html' with link=build.link %} {% endif %} {% if build.issued_by %} diff --git a/InvenTree/company/templates/company/manufacturer_part.html b/InvenTree/company/templates/company/manufacturer_part.html index 6c3da85448..50663c620f 100644 --- a/InvenTree/company/templates/company/manufacturer_part.html +++ b/InvenTree/company/templates/company/manufacturer_part.html @@ -105,7 +105,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "External Link" %} - {{ part.link }}{% include "clip.html"%} + {% include 'clip_link.html' with link=part.link %} {% endif %} diff --git a/InvenTree/company/templates/company/supplier_part.html b/InvenTree/company/templates/company/supplier_part.html index 7bb9f06560..90f85faed8 100644 --- a/InvenTree/company/templates/company/supplier_part.html +++ b/InvenTree/company/templates/company/supplier_part.html @@ -180,7 +180,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "External Link" %} - {{ part.link }}{% include "clip.html"%} + {% include 'clip_link.html' with link=part.link %} {% endif %} diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html index bce90acfa2..6890ce7858 100644 --- a/InvenTree/order/templates/order/order_base.html +++ b/InvenTree/order/templates/order/order_base.html @@ -168,8 +168,8 @@ src="{% static 'img/blank_image.png' %}" {% if order.link %} - External Link - {{ order.link }}{% include "clip.html"%} + {% trans "External Link" %} + {% include 'clip_link.html' with link=order.link %} {% endif %} diff --git a/InvenTree/order/templates/order/return_order_base.html b/InvenTree/order/templates/order/return_order_base.html index 178ea71b46..990d5cd5c0 100644 --- a/InvenTree/order/templates/order/return_order_base.html +++ b/InvenTree/order/templates/order/return_order_base.html @@ -143,8 +143,8 @@ src="{% static 'img/blank_image.png' %}" {% if order.link %} - External Link - {{ order.link }}{% include "clip.html"%} + {% trans "External Link" %} + {% include 'clip_link.html' with link=order.link %} {% endif %} diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html index f6810553b1..c78d3e5391 100644 --- a/InvenTree/order/templates/order/sales_order_base.html +++ b/InvenTree/order/templates/order/sales_order_base.html @@ -178,8 +178,8 @@ src="{% static 'img/blank_image.png' %}" {% if order.link %} - External Link - {{ order.link }}{% include "clip.html"%} + {% trans "External Link" %} + {% include 'clip_link.html' with link=order.link %} {% endif %} diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index 7f89f87cd3..208dc8404a 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -383,7 +383,7 @@ {% trans "External Link" %} - {{ part.link }}{% include "clip.html"%} + {% include 'clip_link.html' with link=part.link %} {% endif %} {% if part.responsible %} diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 959b0d7457..db50bfd571 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -199,7 +199,7 @@ {% trans "External Link" %} - {{ item.link }} + {% include 'clip_link.html' with link=item.link %} {% endif %} {% if item.supplier_part.manufacturer_part %} diff --git a/InvenTree/templates/clip_link.html b/InvenTree/templates/clip_link.html new file mode 100644 index 0000000000..bdbb962b80 --- /dev/null +++ b/InvenTree/templates/clip_link.html @@ -0,0 +1,5 @@ +{% load i18n %} + +{% if link %} +{{ link }}{% include 'clip.html' %} +{% endif %} diff --git a/InvenTree/templates/js/translated/company.js b/InvenTree/templates/js/translated/company.js index f91a97c793..53180d26c7 100644 --- a/InvenTree/templates/js/translated/company.js +++ b/InvenTree/templates/js/translated/company.js @@ -954,7 +954,7 @@ function loadManufacturerPartTable(table, url, options) { field: 'MPN', title: '{% trans "MPN" %}', formatter: function(value, row) { - return renderLink(value, `/manufacturer-part/${row.pk}/`); + return renderClipboard(renderLink(value, `/manufacturer-part/${row.pk}/`)); } }, { @@ -962,7 +962,7 @@ function loadManufacturerPartTable(table, url, options) { title: '{% trans "Link" %}', formatter: function(value) { if (value) { - return renderLink(value, value); + return renderLink(value, value, {external: true}); } else { return ''; } @@ -1194,7 +1194,7 @@ function loadSupplierPartTable(table, url, options) { field: 'SKU', title: '{% trans "Supplier Part" %}', formatter: function(value, row) { - return renderLink(value, `/supplier-part/${row.pk}/`); + return renderClipboard(renderLink(value, `/supplier-part/${row.pk}/`)); } }, { @@ -1225,7 +1225,7 @@ function loadSupplierPartTable(table, url, options) { title: '{% trans "MPN" %}', formatter: function(value, row) { if (value && row.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.manufacturer_part}/`); + return renderClipboard(renderLink(value, `/manufacturer-part/${row.manufacturer_part}/`)); } else { return '-'; } @@ -1261,7 +1261,7 @@ function loadSupplierPartTable(table, url, options) { title: '{% trans "Link" %}', formatter: function(value) { if (value) { - return renderLink(value, value); + return renderLink(value, value, {external: true}); } else { return ''; } diff --git a/InvenTree/templates/js/translated/helpers.js b/InvenTree/templates/js/translated/helpers.js index 4f7aa2de4b..b3623ee5c1 100644 --- a/InvenTree/templates/js/translated/helpers.js +++ b/InvenTree/templates/js/translated/helpers.js @@ -23,6 +23,7 @@ yesNoLabel, withTitle, wrapButtons, + renderClipboard, */ /* exported @@ -376,7 +377,13 @@ function renderLink(text, url, options={}) { extras += ` download`; } - return `${text}`; + let suffix = ''; + if (options.external) { + extras += ` target="_blank" rel="noopener noreferrer"`; + + suffix = ` `; + } + return `${text}${suffix}`; } @@ -516,3 +523,25 @@ function sanitizeInputString(s, options={}) { return s; } + +/* + * Inserts HTML data equal to clip.html into input string + * Enables insertion of clipboard icons in dynamic tables + * + * clipString relies on ClipboardJS in the same manner as clip.html + * Thus, this functionality will break if the call to + * attachClipboard('.clip-btn') in script/inventree/inventree.js is altered + */ +function renderClipboard(s, prepend=false) { + if (!s || typeof s != 'string') { + return s; + } + + let clipString = ``; + + if (prepend === true) { + return `
${clipString+s}
`; + } else { + return `
${s+clipString}
`; + } +} diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 0209120219..0898c0c591 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -1447,7 +1447,7 @@ function loadPartPurchaseOrderTable(table, part_id, options={}) { if (row.supplier_part_detail) { var supp = row.supplier_part_detail; - return renderLink(supp.SKU, `/supplier-part/${supp.pk}/`); + return renderClipboard(renderLink(supp.SKU, `/supplier-part/${supp.pk}/`)); } else { return '-'; } @@ -1460,7 +1460,7 @@ function loadPartPurchaseOrderTable(table, part_id, options={}) { formatter: function(value, row) { if (row.supplier_part_detail && row.supplier_part_detail.manufacturer_part_detail) { var manu = row.supplier_part_detail.manufacturer_part_detail; - return renderLink(manu.MPN, `/manufacturer-part/${manu.pk}/`); + return renderClipboard(renderLink(manu.MPN, `/manufacturer-part/${manu.pk}/`)); } } }, diff --git a/InvenTree/templates/js/translated/purchase_order.js b/InvenTree/templates/js/translated/purchase_order.js index 4eccbdf602..51967b32c2 100644 --- a/InvenTree/templates/js/translated/purchase_order.js +++ b/InvenTree/templates/js/translated/purchase_order.js @@ -1955,7 +1955,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) { title: '{% trans "SKU" %}', formatter: function(value, row, index, field) { if (value) { - return renderLink(value, `/supplier-part/${row.part}/`); + return renderClipboard(renderLink(value, `/supplier-part/${row.part}/`)); } else { return '-'; } @@ -1967,7 +1967,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) { title: '{% trans "Link" %}', formatter: function(value, row, index, field) { if (value) { - return renderLink(value, value); + return renderLink(value, value, {external: true}); } else { return ''; } @@ -1980,7 +1980,7 @@ function loadPurchaseOrderLineItemTable(table, options={}) { title: '{% trans "MPN" %}', formatter: function(value, row, index, field) { if (row.supplier_part_detail && row.supplier_part_detail.manufacturer_part) { - return renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part}/`); + return renderClipboard(renderLink(value, `/manufacturer-part/${row.supplier_part_detail.manufacturer_part}/`)); } else { return '-'; } diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index 7d4979d129..4770dcadfb 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -1782,7 +1782,7 @@ function loadStockTable(table, options) { formatter: function(value, row) { var ipn = row.part_detail.IPN; if (ipn) { - return withTitle(shortenString(ipn), ipn); + return renderClipboard(withTitle(shortenString(ipn), ipn)); } else { return '-'; } @@ -2014,7 +2014,7 @@ function loadStockTable(table, options) { text = `{% trans "Supplier part not specified" %}`; } - return renderLink(text, link); + return renderClipboard(renderLink(text, link)); } };