diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html
index 57d59a2942..f8a2c4ba01 100644
--- a/InvenTree/part/templates/part/detail.html
+++ b/InvenTree/part/templates/part/detail.html
@@ -326,7 +326,7 @@
@@ -746,16 +746,9 @@
// Load the "related parts" tab
onPanelLoad("related-parts", function() {
- loadPartTable(
- '#related-parts-table',
- '{% url "api-part-list" %}',
- {
- params: {
- related: {{ part.pk }},
- },
- gridView: true,
- checkbox: false,
- }
+ loadRelatedPartsTable(
+ "#related-parts-table",
+ {{ part.pk }}
);
$("#add-related-part").click(function() {
diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js
index 9f67794e4c..855aa05385 100644
--- a/InvenTree/templates/js/translated/part.js
+++ b/InvenTree/templates/js/translated/part.js
@@ -705,6 +705,97 @@ function loadPartParameterTable(table, url, options) {
}
+function loadRelatedPartsTable(table, part_id, options={}) {
+ /*
+ * Load table of "related" parts
+ */
+
+ options.params = options.params || {};
+
+ options.params.part = part_id;
+
+ var filters = {};
+
+ for (var key in options.params) {
+ filters[key] = options.params[key];
+ }
+
+ setupFilterList('related', $(table), options.filterTarget);
+
+ function getPart(row) {
+ if (row.part_1 == part_id) {
+ return row.part_2_detail;
+ } else {
+ return row.part_1_detail;
+ }
+ }
+
+ var columns = [
+ {
+ field: 'name',
+ title: '{% trans "Part" %}',
+ switchable: false,
+ formatter: function(value, row) {
+
+ var part = getPart(row);
+
+ var html = imageHoverIcon(part.thumbnail) + renderLink(part.full_name, `/part/${part.pk}/`)
+
+ html += makePartIcons(part);
+
+ return html;
+ }
+ },
+ {
+ field: 'description',
+ title: '{% trans "Description" %}',
+ formatter: function(value, row) {
+ return getPart(row).description;
+ }
+ },
+ {
+ field: 'actions',
+ title: '',
+ switchable: false,
+ formatter: function(value, row) {
+
+ var html = `
`;
+
+ html += makeIconButton('fa-trash-alt icon-red', 'button-related-delete', row.pk, '{% trans "Delete part relationship" %}');
+
+ html += '
';
+
+ return html;
+ }
+ }
+ ];
+
+ $(table).inventreeTable({
+ url: '{% url "api-part-related-list" %}',
+ groupBy: false,
+ name: 'related',
+ original: options.params,
+ queryParams: filters,
+ columns: columns,
+ showColumns: false,
+ search: true,
+ onPostBody: function() {
+ $(table).find('.button-related-delete').click(function() {
+ var pk = $(this).attr('pk');
+
+ constructForm(`/api/part/related/${pk}/`, {
+ method: 'DELETE',
+ title: '{% trans "Delete Part Relationship" %}',
+ onSuccess: function() {
+ $(table).bootstrapTable('refresh');
+ }
+ });
+ });
+ },
+ });
+}
+
+
function loadParametricPartTable(table, options={}) {
/* Load parametric table for part parameters
*
@@ -836,6 +927,7 @@ function loadPartTable(table, url, options={}) {
* query: extra query params for API request
* buttons: If provided, link buttons to selection status of this table
* disableFilters: If true, disable custom filters
+ * actions: Provide a callback function to construct an "actions" column
*/
// Ensure category detail is included
@@ -895,7 +987,7 @@ function loadPartTable(table, url, options={}) {
var name = row.full_name;
- var display = imageHoverIcon(row.thumbnail) + renderLink(name, '/part/' + row.pk + '/');
+ var display = imageHoverIcon(row.thumbnail) + renderLink(name, `/part/${row.pk}/`);
display += makePartIcons(row);
@@ -993,6 +1085,21 @@ function loadPartTable(table, url, options={}) {
}
});
+ // Push an "actions" column
+ if (options.actions) {
+ columns.push({
+ field: 'actions',
+ title: '',
+ switchable: false,
+ visible: true,
+ searchable: false,
+ sortable: false,
+ formatter: function(value, row) {
+ return options.actions(value, row);
+ }
+ });
+ }
+
var grid_view = options.gridView && inventreeLoad('part-grid-view') == 1;
$(table).inventreeTable({
@@ -1020,6 +1127,10 @@ function loadPartTable(table, url, options={}) {
$('#view-part-grid').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-part-list').removeClass('btn-outline-secondary').addClass('btn-secondary');
}
+
+ if (options.onPostBody) {
+ options.onPostBody();
+ }
},
buttons: options.gridView ? [
{
diff --git a/InvenTree/templates/js/translated/table_filters.js b/InvenTree/templates/js/translated/table_filters.js
index 903774f8e5..409192f74d 100644
--- a/InvenTree/templates/js/translated/table_filters.js
+++ b/InvenTree/templates/js/translated/table_filters.js
@@ -74,6 +74,12 @@ function getAvailableTableFilters(tableKey) {
};
}
+ // Filters for the "related parts" table
+ if (tableKey == 'related') {
+ return {
+ };
+ }
+
// Filters for the "used in" table
if (tableKey == 'usedin') {
return {