2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 21:15:41 +00:00

Merge branch 'inventree:master' into plugin-2037

This commit is contained in:
Matthias Mair
2021-11-28 17:26:09 +01:00
committed by GitHub
60 changed files with 18993 additions and 17267 deletions

View File

@ -259,18 +259,18 @@ $("#param-table").inventreeTable({
columns: [
{
field: 'pk',
title: 'ID',
title: '{% trans "ID" %}',
visible: false,
switchable: false,
},
{
field: 'name',
title: 'Name',
title: '{% trans "Name" %}',
sortable: 'true',
},
{
field: 'units',
title: 'Units',
title: '{% trans "Units" %}',
sortable: 'true',
},
{

View File

@ -210,14 +210,14 @@
<div class='input-group-append'>
<input type="submit" value="{% trans 'Set Language' %}" class="btn btn btn-primary">
</div>
<p>{% trans "Some languages are not complete" %}
{% if ALL_LANG %}
. <a href="{% url 'settings' %}">{% trans "Show only sufficent" %}</a>
{% else %}
and hidden. <a href="?alllang">{% trans "Show them too" %}</a>
{% endif %}
</p>
</div>
<p>{% trans "Some languages are not complete" %}
{% if ALL_LANG %}
. <a href="{% url 'settings' %}">{% trans "Show only sufficent" %}</a>
{% else %}
{% trans "and hidden." %} <a href="?alllang">{% trans "Show them too" %}</a>
{% endif %}
</p>
</form>
</div>
<div class="col-sm-6">

View File

@ -1,5 +1,8 @@
{% load i18n %}
<button type='button' class='btn btn-outline-success' id='new-attachment-link'>
<span class='fas fa-link'></span> {% trans "Add Link" %}
</button>
<button type='button' class='btn btn-success' id='new-attachment'>
<span class='fas fa-plus-circle'></span> {% trans "Add Attachment" %}
</button>

View File

@ -54,6 +54,7 @@ function inventreeGet(url, filters={}, options={}) {
data: filters,
dataType: 'json',
contentType: 'application/json',
async: (options.async == false) ? false : true,
success: function(response) {
if (options.success) {
options.success(response);

View File

@ -6,10 +6,57 @@
*/
/* exported
addAttachmentButtonCallbacks,
loadAttachmentTable,
reloadAttachmentTable,
*/
/*
* Add callbacks to buttons for creating new attachments.
*
* Note: Attachments can also be external links!
*/
function addAttachmentButtonCallbacks(url, fields={}) {
// Callback for 'new attachment' button
$('#new-attachment').click(function() {
var file_fields = {
attachment: {},
comment: {},
};
Object.assign(file_fields, fields);
constructForm(url, {
fields: file_fields,
method: 'POST',
onSuccess: reloadAttachmentTable,
title: '{% trans "Add Attachment" %}',
});
});
// Callback for 'new link' button
$('#new-attachment-link').click(function() {
var link_fields = {
link: {},
comment: {},
};
Object.assign(link_fields, fields);
constructForm(url, {
fields: link_fields,
method: 'POST',
onSuccess: reloadAttachmentTable,
title: '{% trans "Add Link" %}',
});
});
}
function reloadAttachmentTable() {
$('#attachment-table').bootstrapTable('refresh');
@ -20,6 +67,8 @@ function loadAttachmentTable(url, options) {
var table = options.table || '#attachment-table';
addAttachmentButtonCallbacks(url, options.fields || {});
$(table).inventreeTable({
url: url,
name: options.name || 'attachments',
@ -34,56 +83,77 @@ function loadAttachmentTable(url, options) {
$(table).find('.button-attachment-edit').click(function() {
var pk = $(this).attr('pk');
if (options.onEdit) {
options.onEdit(pk);
}
constructForm(`${url}${pk}/`, {
fields: {
link: {},
comment: {},
},
processResults: function(data, fields, opts) {
// Remove the "link" field if the attachment is a file!
if (data.attachment) {
delete opts.fields.link;
}
},
onSuccess: reloadAttachmentTable,
title: '{% trans "Edit Attachment" %}',
});
});
// Add callback for 'delete' button
$(table).find('.button-attachment-delete').click(function() {
var pk = $(this).attr('pk');
if (options.onDelete) {
options.onDelete(pk);
}
constructForm(`${url}${pk}/`, {
method: 'DELETE',
confirmMessage: '{% trans "Confirm Delete" %}',
title: '{% trans "Delete Attachment" %}',
onSuccess: reloadAttachmentTable,
});
});
},
columns: [
{
field: 'attachment',
title: '{% trans "File" %}',
formatter: function(value) {
title: '{% trans "Attachment" %}',
formatter: function(value, row) {
var icon = 'fa-file-alt';
if (row.attachment) {
var icon = 'fa-file-alt';
var fn = value.toLowerCase();
var fn = value.toLowerCase();
if (fn.endsWith('.csv')) {
icon = 'fa-file-csv';
} else if (fn.endsWith('.pdf')) {
icon = 'fa-file-pdf';
} else if (fn.endsWith('.xls') || fn.endsWith('.xlsx')) {
icon = 'fa-file-excel';
} else if (fn.endsWith('.doc') || fn.endsWith('.docx')) {
icon = 'fa-file-word';
} else if (fn.endsWith('.zip') || fn.endsWith('.7z')) {
icon = 'fa-file-archive';
if (fn.endsWith('.csv')) {
icon = 'fa-file-csv';
} else if (fn.endsWith('.pdf')) {
icon = 'fa-file-pdf';
} else if (fn.endsWith('.xls') || fn.endsWith('.xlsx')) {
icon = 'fa-file-excel';
} else if (fn.endsWith('.doc') || fn.endsWith('.docx')) {
icon = 'fa-file-word';
} else if (fn.endsWith('.zip') || fn.endsWith('.7z')) {
icon = 'fa-file-archive';
} else {
var images = ['.png', '.jpg', '.bmp', '.gif', '.svg', '.tif'];
images.forEach(function(suffix) {
if (fn.endsWith(suffix)) {
icon = 'fa-file-image';
}
});
}
var split = value.split('/');
var filename = split[split.length - 1];
var html = `<span class='fas ${icon}'></span> ${filename}`;
return renderLink(html, value);
} else if (row.link) {
var html = `<span class='fas fa-link'></span> ${row.link}`;
return renderLink(html, row.link);
} else {
var images = ['.png', '.jpg', '.bmp', '.gif', '.svg', '.tif'];
images.forEach(function(suffix) {
if (fn.endsWith(suffix)) {
icon = 'fa-file-image';
}
});
return '-';
}
var split = value.split('/');
var filename = split[split.length - 1];
var html = `<span class='fas ${icon}'></span> ${filename}`;
return renderLink(html, value);
}
},
{

View File

@ -192,6 +192,7 @@ function bomSubstitutesDialog(bom_item_id, substitutes, options={}) {
</a>
</td>
<td id='description-${pk}'><em>${part.description}</em></td>
<td id='stock-${pk}'><em>${part.stock}</em></td>
<td>${buttons}</td>
</tr>
`;
@ -212,6 +213,7 @@ function bomSubstitutesDialog(bom_item_id, substitutes, options={}) {
<tr>
<th>{% trans "Part" %}</th>
<th>{% trans "Description" %}</th>
<th>{% trans "Stock" %}</th>
<th><!-- Actions --></th>
</tr>
</thead>

View File

@ -124,6 +124,7 @@ function supplierPartFields() {
part_detail: true,
manufacturer_detail: true,
},
auto_fill: true,
},
description: {},
link: {

View File

@ -273,7 +273,7 @@ function setupFilterList(tableKey, table, target) {
var element = $(target);
if (!element) {
if (!element || !element.exists()) {
console.log(`WARNING: setupFilterList could not find target '${target}'`);
return;
}

View File

@ -28,6 +28,7 @@
disableFormInput,
enableFormInput,
hideFormInput,
setFormInputPlaceholder,
setFormGroupVisibility,
showFormInput,
*/
@ -1276,6 +1277,11 @@ function initializeGroups(fields, options) {
}
}
// Set the placeholder value for a field
function setFormInputPlaceholder(name, placeholder, options) {
$(options.modal).find(`#id_${name}`).attr('placeholder', placeholder);
}
// Clear a form input
function clearFormInput(name, options) {
updateFieldValue(name, null, {}, options);

View File

@ -695,6 +695,23 @@ function loadPurchaseOrderTable(table, options) {
title: '{% trans "Items" %}',
sortable: true,
},
{
field: 'responsible',
title: '{% trans "Responsible" %}',
switchable: true,
sortable: false,
formatter: function(value, row) {
var html = row.responsible_detail.name;
if (row.responsible_detail.label == 'group') {
html += `<span class='float-right fas fa-users'></span>`;
} else {
html += `<span class='float-right fas fa-user'></span>`;
}
return html;
}
},
],
});
}

View File

@ -32,6 +32,7 @@
loadPartTable,
loadPartTestTemplateTable,
loadPartVariantTable,
loadRelatedPartsTable,
loadSellPricingChart,
loadSimplePartTable,
loadStockPricingChart,
@ -705,6 +706,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 = `<div class='btn-group float-right' role='group'>`;
html += makeIconButton('fa-trash-alt icon-red', 'button-related-delete', row.pk, '{% trans "Delete part relationship" %}');
html += '</div>';
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 +928,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
@ -878,7 +971,7 @@ function loadPartTable(table, url, options={}) {
col = {
field: 'IPN',
title: 'IPN',
title: '{% trans "IPN" %}',
};
if (!options.params.ordering) {
@ -895,7 +988,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 +1086,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 +1128,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 ? [
{

View File

@ -80,6 +80,20 @@ function serializeStockItem(pk, options={}) {
notes: {},
};
if (options.part) {
// Work out the next available serial number
inventreeGet(`/api/part/${options.part}/serial-numbers/`, {}, {
success: function(data) {
if (data.next) {
options.fields.serial_numbers.placeholder = `{% trans "Next available serial number" %}: ${data.next}`;
} else if (data.latest) {
options.fields.serial_numbers.placeholder = `{% trans "Latest serial number" %}: ${data.latest}`;
}
},
async: false,
});
}
constructForm(url, options);
}
@ -144,10 +158,26 @@ function stockItemFields(options={}) {
// If a "trackable" part is selected, enable serial number field
if (data.trackable) {
enableFormInput('serial_numbers', opts);
// showFormInput('serial_numbers', opts);
// Request part serial number information from the server
inventreeGet(`/api/part/${data.pk}/serial-numbers/`, {}, {
success: function(data) {
var placeholder = '';
if (data.next) {
placeholder = `{% trans "Next available serial number" %}: ${data.next}`;
} else if (data.latest) {
placeholder = `{% trans "Latest serial number" %}: ${data.latest}`;
}
setFormInputPlaceholder('serial_numbers', placeholder, opts);
}
});
} else {
clearFormInput('serial_numbers', opts);
disableFormInput('serial_numbers', opts);
setFormInputPlaceholder('serial_numbers', '{% trans "This part cannot be serialized" %}', opts);
}
// Enable / disable fields based on purchaseable status
@ -1101,7 +1131,7 @@ function loadStockTable(table, options) {
col = {
field: 'part_detail.IPN',
title: 'IPN',
title: '{% trans "IPN" %}',
sortName: 'part__IPN',
visible: params['part_detail'],
switchable: params['part_detail'],

View File

@ -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 {