2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-02 03:30:54 +00:00

Merge branch 'master' into partial-shipment

# Conflicts:
#	InvenTree/build/templates/build/build_base.html
#	InvenTree/order/templates/order/order_base.html
#	InvenTree/order/templates/order/sales_order_base.html
#	InvenTree/order/templates/order/sales_order_detail.html
#	InvenTree/order/templates/order/so_navbar.html
This commit is contained in:
Oliver
2021-10-30 23:44:06 +11:00
251 changed files with 72023 additions and 5855 deletions

View File

@ -27,7 +27,7 @@ function loadAttachmentTable(url, options) {
return '{% trans "No attachments found" %}';
},
sortable: true,
search: false,
search: true,
queryParams: options.filters || {},
onPostBody: function() {
// Add callback for 'edit' button
@ -58,12 +58,16 @@ function loadAttachmentTable(url, options) {
var fn = value.toLowerCase();
if (fn.endsWith('.pdf')) {
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'];

View File

@ -407,7 +407,7 @@ function loadBomTable(table, options) {
// Display an extra icon if this part is an assembly
if (sub_part.assembly) {
var text = `<span title='{% trans "Open subassembly" %}' class='fas fa-stream label-right'></span>`;
var text = `<span title='{% trans "Open subassembly" %}' class='fas fa-stream float-right'></span>`;
html += renderLink(text, `/part/${row.sub_part}/bom/`);
}
@ -470,7 +470,7 @@ function loadBomTable(table, options) {
var text = value;
if (value == null || value <= 0) {
text = `<span class='label label-warning'>{% trans "No Stock" %}</span>`;
text = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock" %}</span>`;
}
return renderLink(text, url);
@ -612,7 +612,7 @@ function loadBomTable(table, options) {
var bValidate = makeIconButton('fa-check-circle icon-green', 'bom-validate-button', row.pk, '{% trans "Validate BOM Item" %}');
var bValid = `<span title='{% trans "This line has been validated" %}' class='fas fa-check-double icon-green'/>`;
var bValid = makeIconButton('fa-check-double icon-green', 'bom-valid-button', row.pk, '{% trans "This line has been validated" %}', {disabled: true});
var bSubs = makeIconButton('fa-exchange-alt icon-blue', 'bom-substitutes-button', row.pk, '{% trans "Edit substitute parts" %}');

View File

@ -34,8 +34,8 @@ function buildFormFields() {
reference: {
prefix: global_settings.BUILDORDER_REFERENCE_PREFIX,
},
title: {},
part: {},
title: {},
quantity: {},
parent: {
filters: {
@ -937,7 +937,10 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) {
var progress = makeProgressBar(
allocatedLines,
totalLines
totalLines,
{
max_width: '150px',
}
);
build_progress.html(progress);

View File

@ -325,15 +325,15 @@ function loadCompanyTable(table, url, options={}) {
var html = imageHoverIcon(row.image) + renderLink(value, row.url);
if (row.is_customer) {
html += `<span title='{% trans "Customer" %}' class='fas fa-user-tie label-right'></span>`;
html += `<span title='{% trans "Customer" %}' class='fas fa-user-tie float-right'></span>`;
}
if (row.is_manufacturer) {
html += `<span title='{% trans "Manufacturer" %}' class='fas fa-industry label-right'></span>`;
html += `<span title='{% trans "Manufacturer" %}' class='fas fa-industry float-right'></span>`;
}
if (row.is_supplier) {
html += `<span title='{% trans "Supplier" %}' class='fas fa-building label-right'></span>`;
html += `<span title='{% trans "Supplier" %}' class='fas fa-building float-right'></span>`;
}
return html;
@ -493,15 +493,15 @@ function loadManufacturerPartTable(table, url, options) {
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(value, url);
if (row.part_detail.is_template) {
html += `<span class='fas fa-clone label-right' title='{% trans "Template part" %}'></span>`;
html += `<span class='fas fa-clone float-right' title='{% trans "Template part" %}'></span>`;
}
if (row.part_detail.assembly) {
html += `<span class='fas fa-tools label-right' title='{% trans "Assembled part" %}'></span>`;
html += `<span class='fas fa-tools float-right' title='{% trans "Assembled part" %}'></span>`;
}
if (!row.part_detail.active) {
html += `<span class='label label-warning label-right'>{% trans "Inactive" %}</span>`;
html += `<span class='badge badge-right rounded-pill bg-warning'>{% trans "Inactive" %}</span>`;
}
return html;
@ -750,15 +750,15 @@ function loadSupplierPartTable(table, url, options) {
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(value, url);
if (row.part_detail.is_template) {
html += `<span class='fas fa-clone label-right' title='{% trans "Template part" %}'></span>`;
html += `<span class='fas fa-clone float-right' title='{% trans "Template part" %}'></span>`;
}
if (row.part_detail.assembly) {
html += `<span class='fas fa-tools label-right' title='{% trans "Assembled part" %}'></span>`;
html += `<span class='fas fa-tools float-right' title='{% trans "Assembled part" %}'></span>`;
}
if (!row.part_detail.active) {
html += `<span class='label label-warning label-right'>{% trans "Inactive" %}</span>`;
html += `<span class='badge badge-right rounded-pill bg-warning'>{% trans "Inactive" %}</span>`;
}
return html;

View File

@ -281,7 +281,7 @@ function setupFilterList(tableKey, table, target) {
// One blank slate, please
element.empty();
element.append(`<button id='reload-${tableKey}' title='{% trans "Reload data" %}' class='btn btn-default filter-tag'><span class='fas fa-redo-alt'></span></button>`);
element.append(`<button id='reload-${tableKey}' title='{% trans "Reload data" %}' class='btn btn-outline-secondary filter-tag'><span class='fas fa-redo-alt'></span></button>`);
// Callback for reloading the table
element.find(`#reload-${tableKey}`).click(function() {
@ -294,10 +294,10 @@ function setupFilterList(tableKey, table, target) {
}
// If there are filters currently "in use", add them in!
element.append(`<button id='${add}' title='{% trans "Add new filter" %}' class='btn btn-default filter-tag'><span class='fas fa-filter'></span></button>`);
element.append(`<button id='${add}' title='{% trans "Add new filter" %}' class='btn btn-outline-secondary filter-tag'><span class='fas fa-filter'></span></button>`);
if (Object.keys(filters).length > 0) {
element.append(`<button id='${clear}' title='{% trans "Clear all filters" %}' class='btn btn-default filter-tag'><span class='fas fa-backspace icon-red'></span></button>`);
element.append(`<button id='${clear}' title='{% trans "Clear all filters" %}' class='btn btn-outline-secondary filter-tag'><span class='fas fa-backspace icon-red'></span></button>`);
}
for (var key in filters) {
@ -320,7 +320,7 @@ function setupFilterList(tableKey, table, target) {
html += generateAvailableFilterList(tableKey);
html += generateFilterInput(tableKey);
html += `<button title='{% trans "Create filter" %}' class='btn btn-default filter-tag' id='${make}'><span class='fas fa-plus'></span></button>`;
html += `<button title='{% trans "Create filter" %}' class='btn btn-outline-secondary filter-tag' id='${make}'><span class='fas fa-plus'></span></button>`;
element.append(html);

View File

@ -2,7 +2,6 @@
{% load inventree_extras %}
/* globals
attachToggle,
createNewModal,
inventreeFormDataUpload,
inventreeGet,
@ -49,6 +48,9 @@
*
*/
// Set global default theme for select2
$.fn.select2.defaults.set('theme', 'bootstrap-5');
/*
* Return true if the OPTIONS specify that the user
* can perform a GET method at the endpoint.
@ -519,11 +521,6 @@ function constructFormBody(fields, options) {
// Attach clear callbacks (if required)
addClearCallbacks(fields, options);
attachToggle(modal);
$(modal + ' .select2-container').addClass('select-full-width');
$(modal + ' .select2-container').css('width', '100%');
modalShowSubmitButton(modal, true);
$(modal).on('click', '#modal-form-submit', function() {
@ -563,13 +560,14 @@ function insertConfirmButton(options) {
var message = options.confirmMessage || '{% trans "Confirm" %}';
var confirm = `
<span style='float: left;'>
${message}
<input id='modal-confirm' name='confirm' type='checkbox'>
</span>`;
var html = `
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="modal-confirm">
<label class="form-check-label" for="modal-confirm">${message}</label>
</div>
`;
$(options.modal).find('#modal-footer-buttons').append(confirm);
$(options.modal).find('#modal-footer-buttons').append(html);
// Disable the 'submit' button
$(options.modal).find('#modal-form-submit').prop('disabled', true);
@ -930,7 +928,7 @@ function clearFormErrors(options) {
$(options.modal).find('.form-error-message').remove();
// Remove the "has error" class
$(options.modal).find('.has-error').removeClass('has-error');
$(options.modal).find('.form-field-error').removeClass('form-field-error');
// Hide the 'non field errors'
$(options.modal).find('#non-field-errors').html('');
@ -1103,8 +1101,8 @@ function handleFormErrors(errors, fields, options) {
*/
function addFieldErrorMessage(field_name, error_text, error_idx, options) {
// Add the 'has-error' class
$(options.modal).find(`#div_id_${field_name}`).addClass('has-error');
// Add the 'form-field-error' class
$(options.modal).find(`#div_id_${field_name}`).addClass('form-field-error');
var field_dom = $(options.modal).find(`#errors-${field_name}`);
@ -1299,7 +1297,7 @@ function addSecondaryModal(field, fields, options) {
var html = `
<span style='float: right;'>
<div type='button' class='btn btn-primary btn-secondary' title='${secondary.title || secondary.label}' id='btn-new-${name}'>
<div type='button' class='btn btn-primary btn-secondary btn-form-secondary' title='${secondary.title || secondary.label}' id='btn-new-${name}'>
${secondary.label || secondary.title}
</div>
</span>`;
@ -1585,7 +1583,6 @@ function initializeChoiceField(field, fields, options) {
select.select2({
dropdownAutoWidth: false,
dropdownParent: $(options.modal),
width: '100%',
});
}
@ -1734,7 +1731,7 @@ function constructField(name, parameters, options) {
<div class='panel-heading form-panel-heading' id='form-panel-heading-${group}'>`;
if (group_options.collapsible) {
html += `
<div data-toggle='collapse' data-target='#form-panel-content-${group}'>
<div data-bs-toggle='collapse' data-bs-target='#form-panel-content-${group}'>
<a href='#'><span id='group-icon-${group}' class='fas fa-angle-up'></span>
`;
} else {
@ -1760,7 +1757,7 @@ function constructField(name, parameters, options) {
var form_classes = 'form-group';
if (parameters.errors) {
form_classes += ' has-error';
form_classes += ' form-field-error';
}
// Optional content to render before the field
@ -1802,7 +1799,7 @@ function constructField(name, parameters, options) {
html += `<div class='input-group'>`;
if (parameters.prefix) {
html += `<span class='input-group-addon'>${parameters.prefix}</span>`;
html += `<span class='input-group-text'>${parameters.prefix}</span>`;
}
}
@ -1812,7 +1809,7 @@ function constructField(name, parameters, options) {
if (!parameters.required) {
html += `
<span class='input-group-addon form-clear' id='clear_${name}' title='{% trans "Clear input" %}'>
<span class='input-group-text form-clear' id='clear_${name}' title='{% trans "Clear input" %}'>
<span class='icon-red fas fa-backspace'></span>
</span>`;
}
@ -1821,7 +1818,11 @@ function constructField(name, parameters, options) {
}
if (parameters.help_text && !options.hideLabels) {
html += constructHelpText(name, parameters, options);
// Boolean values are handled differently!
if (parameters.type != 'boolean') {
html += constructHelpText(name, parameters, options);
}
}
// Div for error messages
@ -1996,7 +1997,6 @@ function constructInputOptions(name, classes, type, parameters) {
switch (parameters.type) {
case 'boolean':
opts.push(`style='display: inline-block; width: 20px; margin-right: 20px;'`);
break;
case 'integer':
case 'float':
@ -2009,6 +2009,15 @@ function constructInputOptions(name, classes, type, parameters) {
if (parameters.multiline) {
return `<textarea ${opts.join(' ')}></textarea>`;
} else if (parameters.type == 'boolean') {
return `
<div class='form-check form-switch'>
<input ${opts.join(' ')}>
<label class='form-check-label' for=''>
<em><small>${parameters.help_text}</small></em>
</label>
</div>
`;
} else {
return `<input ${opts.join(' ')}>`;
}
@ -2032,7 +2041,7 @@ function constructCheckboxInput(name, parameters) {
return constructInputOptions(
name,
'checkboxinput',
'form-check-input',
'checkbox',
parameters
);
@ -2117,7 +2126,7 @@ function constructChoiceInput(name, parameters) {
*/
function constructRelatedFieldInput(name) {
var html = `<select id='id_${name}' class='select form-control' name='${name}' style='width: 100%;'></select>`;
var html = `<select id='id_${name}' class='select form-control' name='${name}'></select>`;
// Don't load any options - they will be filled via an AJAX request
@ -2191,13 +2200,7 @@ function constructRawInput(name, parameters) {
*/
function constructHelpText(name, parameters) {
var style = '';
if (parameters.type == 'boolean') {
style = `style='display: inline-block; margin-left: 25px' `;
}
var html = `<div id='hint_id_${name}' ${style}class='help-block'><i>${parameters.help_text}</i></div>`;
var html = `<div id='hint_id_${name}' class='help-block'><i>${parameters.help_text}</i></div>`;
return html;
}

View File

@ -16,9 +16,9 @@
function yesNoLabel(value) {
if (value) {
return `<span class='label label-green'>{% trans "YES" %}</span>`;
return `<span class='badge rounded-pill bg-success'>{% trans "YES" %}</span>`;
} else {
return `<span class='label label-yellow'>{% trans "NO" %}</span>`;
return `<span class='badge rounded-pill bg-warning'>{% trans "NO" %}</span>`;
}
}
@ -92,7 +92,7 @@ function select2Thumbnail(image) {
*/
function makeIconBadge(icon, title) {
var html = `<span class='fas ${icon} label-right' title='${title}'></span>`;
var html = `<span class='icon-badge fas ${icon} float-right' title='${title}'></span>`;
return html;
}
@ -103,7 +103,7 @@ function makeIconBadge(icon, title) {
*/
function makeIconButton(icon, cls, pk, title, options={}) {
var classes = `btn btn-default btn-glyph ${cls}`;
var classes = `btn btn-outline-secondary ${cls}`;
var id = `${cls}-${pk}`;
@ -182,8 +182,14 @@ function makeProgressBar(value, maximum, opts={}) {
var id = options.id || 'progress-bar';
var style = '';
if (opts.max_width) {
style += `max-width: ${options.max_width}; `;
}
return `
<div id='${id}' class='progress'>
<div id='${id}' class='progress' style='${style}'>
<div class='progress-bar ${extraclass}' role='progressbar' aria-valuenow='${percent}' aria-valuemin='0' aria-valuemax='100' style='width:${percent}%'></div>
<div class='progress-value'>${text}</div>
</div>

View File

@ -47,14 +47,12 @@ function createNewModal(options={}) {
<div class='modal-dialog'>
<div class='modal-content'>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label='{% trans "Close" %}'>
<span aria-hidden="true">&times;</span>
</button>
<h3 id='modal-title'>
<h4 id='modal-title' class='modal-title'>
<!-- Form title to be injected here -->
</h3>
</h4>
<button type='button' class='btn-close' data-bs-dismiss='modal' aria-label='{% trans "Close" %}'></button>
</div>
<div class='modal-form-content-wrapper'>
<div class='modal-body modal-form-content-wrapper'>
<div id='non-field-errors'>
<!-- Form error messages go here -->
</div>
@ -73,7 +71,8 @@ function createNewModal(options={}) {
<div id='modal-footer-buttons'>
<!-- Extra buttons can be inserted here -->
</div>
<button type='button' class='btn btn-default' id='modal-form-close' data-dismiss='modal'>{% trans "Cancel" %}</button>
<span class='flex-item' style='flex-grow: 1;'></span>
<button type='button' class='btn btn-secondary' id='modal-form-close' data-bs-dismiss='modal'>{% trans "Cancel" %}</button>
<button type='button' class='btn btn-primary' id='modal-form-submit'>{% trans "Submit" %}</button>
</div>
</div>
@ -355,22 +354,6 @@ function partialMatcher(params, data) {
}
function attachToggle(modal) {
/* Attach 'bootstrap-toggle' functionality to any checkbox in the modal.
* This is simple for visual improvement,
* and also larger toggle style buttons are easier to press!
*/
$(modal).find(`input[type='checkbox']`).each(function() {
$(this).bootstrapToggle({
size: 'small',
onstyle: 'success',
offstyle: 'warning',
});
});
}
function attachSelect(modal) {
/* Attach 'select2' functionality to any drop-down list in the modal.
* Provides search filtering for dropdown items
@ -550,14 +533,14 @@ function renderErrorMessage(xhr) {
html += `
<div class='panel-group'>
<div class='panel panel-default'>
<div class='panel'>
<div class='panel panel-heading'>
<div class='panel-title'>
<a data-toggle='collapse' href="#collapse-error-info">{% trans "Show Error Information" %}</a>
<a data-bs-toggle='collapse' href="#collapse-error-info">{% trans "Show Error Information" %}</a>
</div>
</div>
<div class='panel-collapse collapse' id='collapse-error-info'>
<div class='panel-body'>`;
<div class='panel-content'>`;
html += xhr.responseText;
@ -698,7 +681,6 @@ function injectModalForm(modal, form_html) {
*/
$(modal).find('.modal-form-content').html(form_html);
attachSelect(modal);
attachToggle(modal);
}
@ -806,7 +788,7 @@ function insertActionButton(modal, options) {
if (already_present == false) {
var html = `
<span style='float: right;'>
<button name='${options.name}' type='submit' class='btn btn-default modal-form-button' value='${options.name}'>
<button name='${options.name}' type='submit' class='btn btn-outline-secondary modal-form-button' value='${options.name}'>
${options.title}
</button>
</span>`;

View File

@ -94,7 +94,7 @@ function renderStockItem(name, data, parameters, options) {
if (data.serial && data.quantity == 1) {
stock_detail = `{% trans "Serial Number" %}: ${data.serial}`;
} else if (data.quantity == 0) {
stock_detail = `<span class='label-form label-red'>{% trans "No Stock"% }</span>`;
stock_detail = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock"% }</span>`;
} else {
stock_detail = `{% trans "Quantity" %}: ${data.quantity}`;
}
@ -172,7 +172,7 @@ function renderPart(name, data, parameters, options) {
}
if (!data.active) {
extra += `<span class='label-form label-red'>{% trans "Inactive" %}</span>`;
extra += `<span class='badge badge-right rounded-pill bg-danger'>{% trans "Inactive" %}</span>`;
}
html += `

View File

@ -118,6 +118,7 @@ function createPurchaseOrder(options={}) {
prefix: global_settings.PURCHASEORDER_REFERENCE_PREFIX,
},
supplier: {
icon: 'fa-building',
value: options.supplier,
secondary: {
title: '{% trans "Add Supplier" %}',

View File

@ -410,14 +410,12 @@ function toggleStar(options) {
}
function partStockLabel(part, options={}) {
var label_class = options.label_class || 'label-form';
function partStockLabel(part) {
if (part.in_stock) {
return `<span class='label ${label_class} label-green'>{% trans "Stock" %}: ${part.in_stock}</span>`;
return `<span class='badge rounded-pill bg-success'>{% trans "Stock" %}: ${part.in_stock}</span>`;
} else {
return `<span class='label ${label_class} label-red'>{% trans "No Stock" %}</span>`;
return `<span class='badge rounded-pill bg-danger'>{% trans "No Stock" %}</span>`;
}
}
@ -453,7 +451,7 @@ function makePartIcons(part) {
}
if (!part.active) {
html += `<span class='label label-warning label-right'>{% trans "Inactive" %}</span>`;
html += `<span class='badge badge-right rounded-pill bg-warning'>{% trans "Inactive" %}</span>`;
}
return html;
@ -530,7 +528,7 @@ function loadPartVariantTable(table, partId, options={}) {
}
if (!row.active) {
html += `<span class='label label-warning label-right'>{% trans "Inactive" %}</span>`;
html += `<span class='badge badge-right rounded-pill bg-warning'>{% trans "Inactive" %}</span>`;
}
return html;
@ -769,14 +767,10 @@ function partGridTile(part) {
// Rows for table view
var rows = '';
if (part.IPN) {
rows += `<tr><td><b>{% trans "IPN" %}</b></td><td>${part.IPN}</td></tr>`;
}
var stock = `${part.in_stock}`;
if (!part.in_stock) {
stock = `<span class='label label-red'>{% trans "No Stock" %}</label>`;
stock = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock" %}</span>`;
}
rows += `<tr><td><b>{% trans "Stock" %}</b></td><td>${stock}</td></tr>`;
@ -791,8 +785,8 @@ function partGridTile(part) {
var html = `
<div class='product-card card'>
<div class='panel panel-default panel-inventree product-card-panel'>
<div class='card product-card borderless'>
<div class='panel product-card-panel'>
<div class='panel-heading'>
<a href='/part/${part.pk}/'>
<b>${part.full_name}</b>
@ -949,20 +943,20 @@ function loadPartTable(table, url, options={}) {
// Is stock "low" (below the 'minimum_stock' quantity)?
if (row.minimum_stock && row.minimum_stock > value) {
value += `<span class='label label-right label-warning'>{% trans "Low stock" %}</span>`;
value += `<span class='badge badge-right rounded-pill bg-warning'>{% trans "Low stock" %}</span>`;
}
} else if (row.on_order) {
// There is no stock available, but stock is on order
value = `0<span class='label label-right label-primary'>{% trans "On Order" %}: ${row.on_order}</span>`;
value = `0<span class='badge badge-right rounded-pill bg-info'>{% trans "On Order" %}: ${row.on_order}</span>`;
link = '?display=purchase-orders';
} else if (row.building) {
// There is no stock available, but stock is being built
value = `0<span class='label label-right label-info'>{% trans "Building" %}: ${row.building}</span>`;
value = `0<span class='badge badge-right rounded-pill bg-info'>{% trans "Building" %}: ${row.building}</span>`;
link = '?display=build-orders';
} else {
// There is no stock available
value = `0<span class='label label-right label-danger'>{% trans "No Stock" %}</span>`;
value = `0<span class='badge badge-right rounded-pill bg-danger'>{% trans "No Stock" %}</span>`;
}
return renderLink(value, `/part/${row.pk}/${link}`);
@ -989,6 +983,8 @@ function loadPartTable(table, url, options={}) {
}
});
var grid_view = inventreeLoad('part-grid-view') == 1;
$(table).inventreeTable({
url: url,
method: 'get',
@ -1003,8 +999,52 @@ function loadPartTable(table, url, options={}) {
},
columns: columns,
showColumns: true,
showCustomView: false,
showCustomView: grid_view,
showCustomViewButton: false,
onPostBody: function() {
grid_view = inventreeLoad('part-grid-view') == 1;
if (grid_view) {
$('#view-part-list').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-part-grid').removeClass('btn-outline-secondary').addClass('btn-secondary');
} else {
$('#view-part-grid').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-part-list').removeClass('btn-outline-secondary').addClass('btn-secondary');
}
},
buttons: [
{
icon: 'fas fa-bars',
attributes: {
title: '{% trans "Display as list" %}',
id: 'view-part-list',
},
event: () => {
inventreeSave('part-grid-view', 0);
$(table).bootstrapTable(
'refreshOptions',
{
showCustomView: false,
}
);
}
},
{
icon: 'fas fa-th',
attributes: {
title: '{% trans "Display as grid" %}',
id: 'view-part-grid',
},
event: () => {
inventreeSave('part-grid-view', 1);
$(table).bootstrapTable(
'refreshOptions',
{
showCustomView: true,
}
);
}
}
],
customView: function(data) {
var html = '';
@ -1117,14 +1157,88 @@ function loadPartCategoryTable(table, options) {
setupFilterList(filterKey, table, filterListElement);
var tree_view = inventreeLoad('category-tree-view') == 1;
table.inventreeTable({
treeEnable: tree_view,
rootParentId: options.params.parent,
uniqueId: 'pk',
idField: 'pk',
treeShowField: 'name',
parentIdField: 'parent',
method: 'get',
url: options.url || '{% url "api-part-category-list" %}',
queryParams: filters,
sidePagination: 'server',
disablePagination: tree_view,
sidePagination: tree_view ? 'client' : 'server',
serverSort: !tree_view,
search: !tree_view,
name: 'category',
original: original,
showColumns: true,
buttons: [
{
icon: 'fas fa-bars',
attributes: {
title: '{% trans "Display as list" %}',
id: 'view-category-list',
},
event: () => {
inventreeSave('category-tree-view', 0);
table.bootstrapTable(
'refreshOptions',
{
treeEnable: false,
serverSort: true,
search: true,
pagination: true,
}
);
}
},
{
icon: 'fas fa-sitemap',
attributes: {
title: '{% trans "Display as tree" %}',
id: 'view-category-tree',
},
event: () => {
inventreeSave('category-tree-view', 1);
table.bootstrapTable(
'refreshOptions',
{
treeEnable: true,
serverSort: false,
search: false,
pagination: false,
}
);
}
}
],
onPostBody: function() {
tree_view = inventreeLoad('category-tree-view') == 1;
if (tree_view) {
$('#view-category-list').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-category-tree').removeClass('btn-outline-secondary').addClass('btn-secondary');
table.treegrid({
treeColumn: 0,
onChange: function() {
table.bootstrapTable('resetView');
},
onExpand: function() {
}
});
} else {
$('#view-category-tree').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-category-list').removeClass('btn-outline-secondary').addClass('btn-secondary');
}
},
columns: [
{
checkbox: true,
@ -1154,7 +1268,8 @@ function loadPartCategoryTable(table, options) {
{
field: 'pathstring',
title: '{% trans "Path" %}',
switchable: true,
switchable: !tree_view,
visible: !tree_view,
sortable: false,
},
{

View File

@ -450,17 +450,17 @@ function removeStockRow(e) {
}
function passFailBadge(result, align='float-right') {
function passFailBadge(result) {
if (result) {
return `<span class='label label-green ${align}'>{% trans "PASS" %}</span>`;
return `<span class='badge badge-right rounded-pill bg-success'>{% trans "PASS" %}</span>`;
} else {
return `<span class='label label-red ${align}'>{% trans "FAIL" %}</span>`;
return `<span class='badge badge-right rounded-pill bg-danger'>{% trans "FAIL" %}</span>`;
}
}
function noResultBadge(align='float-right') {
return `<span class='label label-blue ${align}'>{% trans "NO RESULT" %}</span>`;
function noResultBadge() {
return `<span class='badge badge-right rounded-pill bg-info'>{% trans "NO RESULT" %}</span>`;
}
function formatDate(row) {
@ -468,11 +468,7 @@ function formatDate(row) {
var html = row.date;
if (row.user_detail) {
html += `<span class='badge'>${row.user_detail.username}</span>`;
}
if (row.attachment) {
html += `<a href='${row.attachment}'><span class='fas fa-file-alt label-right'></span></a>`;
html += `<span class='badge badge-right rounded-pill bg-secondary'>${row.user_detail.username}</span>`;
}
return html;
@ -553,6 +549,15 @@ function loadStockTestResultsTable(table, options) {
{
field: 'value',
title: '{% trans "Value" %}',
formatter: function(value, row) {
var html = value;
if (row.attachment) {
html += `<a href='${row.attachment}'><span class='fas fa-file-alt float-right'></span></a>`;
}
return html;
}
},
{
field: 'notes',
@ -878,16 +883,12 @@ function loadStockTable(table, options) {
}
if (row.quantity <= 0) {
html += `<span class='label label-right label-danger'>{% trans "Depleted" %}</span>`;
html += `<span class='badge rounded-pill bg-danger'>{% trans "Depleted" %}</span>`;
}
return html;
}
};
if (!options.params.ordering) {
col['sortable'] = true;
}
columns.push(col);
@ -1442,7 +1443,19 @@ function loadStockLocationTable(table, options) {
filters[key] = params[key];
}
var tree_view = inventreeLoad('location-tree-view') == 1;
table.inventreeTable({
treeEnable: tree_view,
rootParentId: options.params.parent,
uniqueId: 'pk',
idField: 'pk',
treeShowField: 'name',
parentIdField: 'parent',
disablePagination: tree_view,
sidePagination: tree_view ? 'client' : 'server',
serverSort: !tree_view,
search: !tree_view,
method: 'get',
url: options.url || '{% url "api-location-list" %}',
queryParams: filters,
@ -1450,6 +1463,69 @@ function loadStockLocationTable(table, options) {
name: 'location',
original: original,
showColumns: true,
onPostBody: function() {
tree_view = inventreeLoad('location-tree-view') == 1;
if (tree_view) {
$('#view-location-list').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-location-tree').removeClass('btn-outline-secondary').addClass('btn-secondary');
table.treegrid({
treeColumn: 1,
onChange: function() {
table.bootstrapTable('resetView');
},
onExpand: function() {
}
});
} else {
$('#view-location-tree').removeClass('btn-secondary').addClass('btn-outline-secondary');
$('#view-location-list').removeClass('btn-outline-secondary').addClass('btn-secondary');
}
},
buttons: [
{
icon: 'fas fa-bars',
attributes: {
title: '{% trans "Display as list" %}',
id: 'view-location-list',
},
event: () => {
inventreeSave('location-tree-view', 0);
table.bootstrapTable(
'refreshOptions',
{
treeEnable: false,
serverSort: true,
search: true,
pagination: true,
}
);
}
},
{
icon: 'fas fa-sitemap',
attributes: {
title: '{% trans "Display as tree" %}',
id: 'view-location-tree',
},
event: () => {
inventreeSave('location-tree-view', 1);
table.bootstrapTable(
'refreshOptions',
{
treeEnable: true,
serverSort: false,
search: false,
pagination: false,
}
);
}
}
],
columns: [
{
checkbox: true,
@ -1684,8 +1760,8 @@ function loadStockTrackingTable(table, options) {
formatter: function(value, row, index, field) {
// Manually created entries can be edited or deleted
if (false && !row.system) {
var bEdit = "<button title='{% trans 'Edit tracking entry' %}' class='btn btn-entry-edit btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
var bDel = "<button title='{% trans 'Delete tracking entry' %}' class='btn btn-entry-delete btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
var bEdit = "<button title='{% trans 'Edit tracking entry' %}' class='btn btn-entry-edit btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
var bDel = "<button title='{% trans 'Delete tracking entry' %}' class='btn btn-entry-delete btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
return "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
} else {

View File

@ -214,6 +214,8 @@ $.fn.inventreeTable = function(options) {
options.pageList = [25, 50, 100, 250, 'all'];
options.totalField = 'count';
options.dataField = 'results';
} else {
options.pagination = false;
}
// Extract query params
@ -397,3 +399,8 @@ function customGroupSorter(sortName, sortOrder, sortData) {
$.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']);
})(jQuery);
$.extend($.fn.treegrid.defaults, {
expanderExpandedClass: 'treegrid-expander-expanded',
expanderCollapsedClass: 'treegrid-expander-collapsed'
});