2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-08-11 06:10:54 +00:00

Merge remote-tracking branch 'inventree/master' into stock-item-forms

This commit is contained in:
Oliver
2021-11-04 10:57:40 +11:00
17 changed files with 238 additions and 141 deletions

View File

@@ -10,6 +10,26 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Favicon -->
<link rel="apple-touch-icon" sizes="57x57" href="{% static 'img/favicon/apple-icon-57x57.png' %}">
<link rel="apple-touch-icon" sizes="60x60" href="{% static 'img/favicon/apple-icon-60x60.png' %}">
<link rel="apple-touch-icon" sizes="72x72" href="{% static 'img/favicon/apple-icon-72x72.png' %}">
<link rel="apple-touch-icon" sizes="76x76" href="{% static 'img/favicon/apple-icon-76x76.png' %}">
<link rel="apple-touch-icon" sizes="114x114" href="{% static 'img/favicon/apple-icon-114x114.png' %}">
<link rel="apple-touch-icon" sizes="120x120" href="{% static 'img/favicon/apple-icon-120x120.png' %}">
<link rel="apple-touch-icon" sizes="144x144" href="{% static 'img/favicon/apple-icon-144x144.png' %}">
<link rel="apple-touch-icon" sizes="152x152" href="{% static 'img/favicon/apple-icon-152x152.png' %}">
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/favicon/apple-icon-180x180.png' %}">
<link rel="icon" type="image/png" sizes="192x192" href="{% static 'img/favicon/android-icon-192x192.png' %}">
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'img/favicon/favicon-32x32.png' %}">
<link rel="icon" type="image/png" sizes="96x96" href="{% static 'img/favicon/favicon-96x96.png' %}">
<link rel="icon" type="image/png" sizes="16x16" href="{% static 'img/favicon/favicon-16x16.png' %}">
<link rel="manifest" href="{% static 'img/favicon/manifest.json' %}">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="{% static 'img/favicon/ms-icon-144x144.png' %}">
<meta name="theme-color" content="#ffffff">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
@@ -33,16 +53,23 @@
<!--
Background Image Attribution: https://unsplash.com/photos/Ixvv3YZkd7w
-->
<div class='container-fluid'>
<div class='notification-area' id='alerts'>
<!-- Div for displayed alerts -->
</div>
</div>
<div class='main body-wrapper login-screen d-flex'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<div class='clearfix content-heading login-header d-flex flex-wrap'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>{% inventree_title %}</h3></span>
{% include "spacer.html" %}
<span class='float-right'><h3>{% inventree_title %}</h3></span>
</div>
<hr>
<div class='container-fluid'>{% block content %}{% endblock %}</div>
@@ -52,22 +79,31 @@
{% block extra_body %}
{% endblock %}
{% include 'notification.html' %}
</div>
<!-- Scripts -->
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/jquery-ui/jquery-ui.min.js' %}"></script>
<script type="text/javascript" src="{% static 'bootstrap/js/bootstrap.bundle.min.js' %}"></script>
<!-- general InvenTree -->
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
<!-- dynamic javascript templates -->
<script type='text/javascript' src="{% url 'inventree.js' %}"></script>
<!-- fontawesome -->
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<!-- 3rd party general js -->
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
<script type="text/javascript" src="{% static 'fullcalendar/locales-all.js' %}"></script>
<script type="text/javascript" src="{% static 'select2/js/select2.full.js' %}"></script>
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
<script type='text/javascript' src="{% static 'script/chart.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/clipboard.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/randomColor.min.js' %}"></script>
<script type='text/javascript'>
@@ -75,12 +111,10 @@ $(document).ready(function () {
// notifications
{% if messages %}
{% for message in messages %}
showAlertOrCache('alert-info', '{{message}}', true);
showAlertOrCache('{{ message }}', 'info', true);
{% endfor %}
{% endif %}
showCachedAlerts();
inventreeDocReady();
});

View File

@@ -32,12 +32,12 @@ for a account and sign in below:{% endblocktrans %}</p>
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<div class="btn-toolbar">
<button class="btn btn-primary col-md-8" type="submit">{% trans "Sign In" %}</button>
{% if mail_conf and enable_pwd_forgot %}
<a class="btn btn-primary" href="{% url 'account_reset_password' %}">{% trans "Forgot Password?" %}</a>
{% endif %}
</div>
<div class="btn-group float-right" role="group">
<button class="btn btn-success" type="submit">{% trans "Sign In" %}</button>
</div>
{% if mail_conf and enable_pwd_forgot %}
<a class="" href="{% url 'account_reset_password' %}"><small>{% trans "Forgot Password?" %}</small></a>
{% endif %}
</form>
{% if enable_sso %}

View File

@@ -14,7 +14,10 @@
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/>
{% endif %}
<button type="submit" class="btn btn-primary btn-block">{% trans 'Sign Out' %}</button>
<div class='btn-group float-right' role='group'>
<a type='button' class='btn btn-secondary' href='{% url "index" %}'><span class='fas fa-undo-alt'></span> {% trans "Back to Site" %}</a>
<button type="submit" class="btn btn-danger btn-block">{% trans 'Sign Out' %}</button>
</div>
</form>

View File

@@ -14,7 +14,9 @@
<form method="POST" action="{{ action_url }}">
{% csrf_token %}
{{ form|crispy }}
<input type="submit" name="action" class="btn btn-primary btn-block" value="{% trans 'change password' %}"/>
<div class='btn-group float-right' role='group'>
<input type="submit" name="action" class="btn btn-success" value="{% trans 'Change password' %}"/>
</div>
</form>
{% else %}
<p>{% trans 'Your password is now changed.' %}</p>

View File

@@ -141,9 +141,9 @@
<!-- general InvenTree -->
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
<!-- dynamic javascript templates -->
<script type='text/javascript' src="{% url 'inventree.js' %}"></script>
<script type='text/javascript' src="{% url 'calendar.js' %}"></script>
<script type='text/javascript' src="{% url 'nav.js' %}"></script>
<script type='text/javascript' src="{% url 'settings.js' %}"></script>
@@ -183,15 +183,13 @@ $(document).ready(function () {
inventreeDocReady();
showCachedAlerts();
{% if barcodes %}
$('#barcode-scan').click(function() {
barcodeScanDialog();
});
{% endif %}
moment.locale('{{request.LANGUAGE_CODE}}');
moment.locale('{{ request.LANGUAGE_CODE }}');
});
</script>

View File

@@ -1,317 +0,0 @@
{% load inventree_extras %}
/* globals
ClipboardJS,
inventreeFormDataUpload,
launchModalForm,
user_settings,
*/
/* exported
attachClipboard,
enableDragAndDrop,
exportFormatOptions,
inventreeDocReady,
inventreeLoad,
inventreeSave,
*/
function attachClipboard(selector, containerselector, textElement) {
// set container
if (containerselector) {
containerselector = document.getElementById(containerselector);
} else {
containerselector = document.body;
}
var text = null;
// set text-function
if (textElement) {
text = function() {
return document.getElementById(textElement).textContent;
};
} else {
text = function(trigger) {
var content = trigger.parentElement.parentElement.textContent;
return content.trim();
};
}
// create Clipboard
// eslint-disable-next-line no-unused-vars
var cis = new ClipboardJS(selector, {
text: text,
container: containerselector
});
}
/**
* Return a standard list of export format options *
*/
function exportFormatOptions() {
return [
{
value: 'csv',
display_name: 'CSV',
},
{
value: 'tsv',
display_name: 'TSV',
},
{
value: 'xls',
display_name: 'XLS',
},
{
value: 'xlsx',
display_name: 'XLSX',
},
];
}
function inventreeDocReady() {
/* Run this function when the HTML document is loaded.
* This will be called for every page that extends "base.html"
*/
window.addEventListener('dragover', function(e) {
e = e || event;
e.preventDefault();
}, false);
window.addEventListener('drop', function(e) {
e = e || event;
e.preventDefault();
}, false);
/* Add drag-n-drop functionality to any element
* marked with the class 'dropzone'
*/
$('.dropzone').on('dragenter', function(event) {
// TODO - Only indicate that a drop event will occur if a file is being dragged
var transfer = event.originalEvent.dataTransfer;
// eslint-disable-next-line no-constant-condition
if (true || isFileTransfer(transfer)) {
$(this).addClass('dragover');
}
});
$('.dropzone').on('dragleave drop', function() {
$(this).removeClass('dragover');
});
// Callback to launch the 'About' window
$('#launch-about').click(function() {
var modal = $('#modal-about');
modal.modal({
backdrop: 'static',
keyboard: true,
});
modal.modal('show');
});
// Callback to launch the 'Database Stats' window
$('#launch-stats').click(function() {
launchModalForm('/stats/', {
no_post: true,
});
});
// Initialize clipboard-buttons
attachClipboard('.clip-btn');
attachClipboard('.clip-btn', 'modal-about');
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text');
// Add autocomplete to the search-bar
$('#search-bar').autocomplete({
source: function(request, response) {
$.ajax({
url: '/api/part/',
data: {
search: request.term,
limit: user_settings.SEARCH_PREVIEW_RESULTS,
offset: 0
},
success: function(data) {
var transformed = $.map(data.results, function(el) {
return {
label: el.full_name,
id: el.pk,
thumbnail: el.thumbnail,
data: el,
};
});
response(transformed);
},
error: function() {
response([]);
}
});
},
create: function() {
$(this).data('ui-autocomplete')._renderItem = function(ul, item) {
var html = `<a href='/part/${item.id}/'><span>`;
html += `<img class='hover-img-thumb' src='`;
html += item.thumbnail || `/static/img/blank_image.png`;
html += `'> `;
html += item.label;
html += '</span>';
if (user_settings.SEARCH_SHOW_STOCK_LEVELS) {
html += partStockLabel(
item.data,
{
classes: 'badge-right',
}
);
}
html += '</a>';
return $('<li>').append(html).appendTo(ul);
};
},
select: function( event, ui ) {
window.location = '/part/' + ui.item.id + '/';
},
minLength: 2,
classes: {
'ui-autocomplete': 'dropdown-menu search-menu',
},
});
// Generate brand-icons
$('.brand-icon').each(function(i, obj) {
loadBrandIcon($(this), $(this).attr('brand_name'));
});
// Callback for "admin view" button
$('#admin-button').click(function() {
var url = $(this).attr('url');
location.href = url;
});
}
function isFileTransfer(transfer) {
/* Determine if a transfer (e.g. drag-and-drop) is a file transfer
*/
return transfer.files.length > 0;
}
function enableDragAndDrop(element, url, options) {
/* Enable drag-and-drop file uploading for a given element.
Params:
element - HTML element lookup string e.g. "#drop-div"
url - URL to POST the file to
options - object with following possible values:
label - Label of the file to upload (default='file')
data - Other form data to upload
success - Callback function in case of success
error - Callback function in case of error
method - HTTP method
*/
var data = options.data || {};
$(element).on('drop', function(event) {
var transfer = event.originalEvent.dataTransfer;
var label = options.label || 'file';
var formData = new FormData();
// Add the extra data
for (var key in data) {
formData.append(key, data[key]);
}
if (isFileTransfer(transfer)) {
formData.append(label, transfer.files[0]);
inventreeFormDataUpload(
url,
formData,
{
success: function(data, status, xhr) {
console.log('Uploaded file via drag-and-drop');
if (options.success) {
options.success(data, status, xhr);
}
},
error: function(xhr, status, error) {
console.log('File upload failed');
if (options.error) {
options.error(xhr, status, error);
}
},
method: options.method || 'POST',
}
);
} else {
console.log('Ignoring drag-and-drop event (not a file)');
}
});
}
/**
* Save a key:value pair to local storage
* @param {String} name - settting key
* @param {String} value - setting value
*/
function inventreeSave(name, value) {
var key = `inventree-${name}`;
localStorage.setItem(key, value);
}
/**
* Retrieve a key:value pair from local storage
* @param {*} name - setting key
* @param {*} defaultValue - default value (returned if no matching key:value pair is found)
* @returns
*/
function inventreeLoad(name, defaultValue) {
var key = `inventree-${name}`;
var value = localStorage.getItem(key);
if (value == null) {
return defaultValue;
} else {
return value;
}
}
function loadBrandIcon(element, name) {
// check if icon exists
var icon = window.FontAwesome.icon({prefix: 'fab', iconName: name});
if (icon) {
// add icon to button
element.addClass('fab fa-' + name);
}
}
// Convenience function to determine if an element exists
$.fn.exists = function() {
return this.length !== 0;
};

View File

@@ -2,8 +2,6 @@
{% load inventree_extras %}
/* globals
renderErrorMessage,
showAlertDialog,
*/
/* exported
@@ -68,6 +66,8 @@ function inventreeGet(url, filters={}, options={}) {
options.error({
error: thrownError
});
} else {
showApiError(xhr, url);
}
}
});
@@ -104,6 +104,8 @@ function inventreeFormDataUpload(url, data, options={}) {
if (options.error) {
options.error(xhr, status, error);
} else {
showApiError(xhr, url);
}
}
});
@@ -139,6 +141,8 @@ function inventreePut(url, data={}, options={}) {
} else {
console.error(`Error on ${method} to '${url}' - STATUS ${xhr.status}`);
console.error(thrownError);
showApiError(xhr, url);
}
},
complete: function(xhr, status) {
@@ -162,8 +166,10 @@ function inventreeDelete(url, options={}) {
return inventreePut(url, {}, options);
}
function showApiError(xhr) {
/*
* Display a notification with error information
*/
function showApiError(xhr, url) {
var title = null;
var message = null;
@@ -208,7 +214,11 @@ function showApiError(xhr) {
}
message += '<hr>';
message += renderErrorMessage(xhr);
message += `URL: ${url}`;
showAlertDialog(title, message);
showMessage(title, {
style: 'danger',
icon: 'fas fa-server icon-red',
details: message,
});
}

View File

@@ -480,10 +480,10 @@ function barcodeCheckIn(location_id) {
$(modal).modal('hide');
if (status == 'success' && 'success' in response) {
showAlertOrCache('alert-success', response.success, true);
showAlertOrCache(response.success, 'success', true);
location.reload();
} else {
showAlertOrCache('alert-success', '{% trans "Error transferring stock" %}', false);
showAlertOrCache('{% trans "Error transferring stock" %}', 'danger', false);
}
}
}
@@ -604,10 +604,10 @@ function scanItemsIntoLocation(item_id_list, options={}) {
$(modal).modal('hide');
if (status == 'success' && 'success' in response) {
showAlertOrCache('alert-success', response.success, true);
showAlertOrCache(response.success, 'success', true);
location.reload();
} else {
showAlertOrCache('alert-danger', '{% trans "Error transferring stock" %}', false);
showAlertOrCache('{% trans "Error transferring stock" %}', 'danger', false);
}
}
}

View File

@@ -339,7 +339,7 @@ function completeBuildOutputs(build_id, outputs, options={}) {
break;
default:
$(opts.modal).modal('hide');
showApiError(xhr);
showApiError(xhr, opts.url);
break;
}
}
@@ -1527,7 +1527,7 @@ function allocateStockToBuild(build_id, part_id, bom_items, options={}) {
break;
default:
$(opts.modal).modal('hide');
showApiError(xhr);
showApiError(xhr, opts.url);
break;
}
}

View File

@@ -125,9 +125,10 @@ function getApiEndpointOptions(url, callback) {
json: 'application/json',
},
success: callback,
error: function() {
error: function(xhr) {
// TODO: Handle error
console.log(`ERROR in getApiEndpointOptions at '${url}'`);
showApiError(xhr, url);
}
});
}
@@ -213,12 +214,14 @@ function constructChangeForm(fields, options) {
// Store the entire data object
options.instance = data;
constructFormBody(fields, options);
},
error: function() {
error: function(xhr) {
// TODO: Handle error here
console.log(`ERROR in constructChangeForm at '${options.url}'`);
showApiError(xhr, options.url);
}
});
}
@@ -255,9 +258,11 @@ function constructDeleteForm(fields, options) {
constructFormBody(fields, options);
},
error: function() {
error: function(xhr) {
// TODO: Handle error here
console.log(`ERROR in constructDeleteForm at '${options.url}`);
showApiError(xhr, options.url);
}
});
}
@@ -722,7 +727,7 @@ function submitFormData(fields, options) {
break;
default:
$(options.modal).modal('hide');
showApiError(xhr);
showApiError(xhr, options.url);
break;
}
}
@@ -899,19 +904,19 @@ function handleFormSuccess(response, options) {
// Display any messages
if (response && response.success) {
showAlertOrCache('alert-success', response.success, cache);
showAlertOrCache(response.success, 'success', cache);
}
if (response && response.info) {
showAlertOrCache('alert-info', response.info, cache);
showAlertOrCache(response.info, 'info', cache);
}
if (response && response.warning) {
showAlertOrCache('alert-warning', response.warning, cache);
showAlertOrCache(response.warning, 'warning', cache);
}
if (response && response.danger) {
showAlertOrCache('alert-danger', response.danger, cache);
showAlertOrCache(response.danger, 'dagner', cache);
}
if (options.onSuccess) {

View File

@@ -399,19 +399,19 @@ function afterForm(response, options) {
// Display any messages
if (response.success) {
showAlertOrCache('alert-success', response.success, cache);
showAlertOrCache(response.success, 'success', cache);
}
if (response.info) {
showAlertOrCache('alert-info', response.info, cache);
showAlertOrCache(response.info, 'info', cache);
}
if (response.warning) {
showAlertOrCache('alert-warning', response.warning, cache);
showAlertOrCache(response.warning, 'warning', cache);
}
if (response.danger) {
showAlertOrCache('alert-danger', response.danger, cache);
showAlertOrCache(response.danger, 'danger', cache);
}
// Was a callback provided?

View File

@@ -555,7 +555,7 @@ function receivePurchaseOrderItems(order_id, line_items, options={}) {
break;
default:
$(opts.modal).modal('hide');
showApiError(xhr);
showApiError(xhr, opts.url);
break;
}
}

View File

@@ -680,7 +680,7 @@ function adjustStock(action, items, options={}) {
break;
default:
$(opts.modal).modal('hide');
showApiError(xhr);
showApiError(xhr, opts.url);
break;
}
}