diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000000..43363404b3 --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,25 @@ +env: + commonjs: false + browser: true + es2021: true + jquery: true +extends: + - google +parserOptions: + ecmaVersion: 12 +rules: + no-var: off + guard-for-in: off + no-trailing-spaces: off + camelcase: off + padded-blocks: off + prefer-const: off + max-len: off + require-jsdoc: off + valid-jsdoc: off + no-multiple-empty-lines: off + comma-dangle: off + prefer-spread: off + indent: + - error + - 4 diff --git a/.github/workflows/javascript.yaml b/.github/workflows/javascript.yaml index 908a87e31c..a07b516ac6 100644 --- a/.github/workflows/javascript.yaml +++ b/.github/workflows/javascript.yaml @@ -18,11 +18,33 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INVENTREE_DB_ENGINE: sqlite3 + INVENTREE_DB_NAME: inventree + INVENTREE_MEDIA_ROOT: ./media + INVENTREE_STATIC_ROOT: ./static steps: + - name: Install node.js + uses: actions/setup-node@v2 + - run: npm install - name: Checkout Code uses: actions/checkout@v2 - - name: Check Files + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install gettext + pip3 install invoke + invoke install + invoke static + - name: Check Templated Files run: | cd ci python check_js_templates.py - \ No newline at end of file + - name: Lint Javascript Files + run: | + npm install eslint eslint-config-google + invoke render-js-files + npx eslint js_tmp/*.js \ No newline at end of file diff --git a/.gitignore b/.gitignore index f3fa0ac8c1..420524d06f 100644 --- a/.gitignore +++ b/.gitignore @@ -67,8 +67,16 @@ secret_key.txt .coverage htmlcov/ +# Temporary javascript files (used for testing) +js_tmp/ + # Development files dev/ # Locale stats file locale_stats.json + +# node.js +package-lock.json +package.json +node_modules/ \ No newline at end of file diff --git a/InvenTree/InvenTree/ci_render_js.py b/InvenTree/InvenTree/ci_render_js.py new file mode 100644 index 0000000000..62e3fc4667 --- /dev/null +++ b/InvenTree/InvenTree/ci_render_js.py @@ -0,0 +1,100 @@ +""" +Pull rendered copies of the templated +""" + +from django.http import response +from django.test import TestCase, testcases +from django.contrib.auth import get_user_model + +import os +import pathlib + + +class RenderJavascriptFiles(TestCase): + """ + A unit test to "render" javascript files. + + The server renders templated javascript files, + we need the fully-rendered files for linting and static tests. + """ + + def setUp(self): + + user = get_user_model() + + self.user = user.objects.create_user( + username='testuser', + password='testpassword', + email='user@gmail.com', + ) + + self.client.login(username='testuser', password='testpassword') + + def download_file(self, filename, prefix): + + url = os.path.join(prefix, filename) + + response = self.client.get(url) + + here = os.path.abspath(os.path.dirname(__file__)) + + output_dir = os.path.join( + here, + '..', + '..', + 'js_tmp', + ) + + output_dir = os.path.abspath(output_dir) + + if not os.path.exists(output_dir): + os.mkdir(output_dir) + + output_file = os.path.join( + output_dir, + filename, + ) + + with open(output_file, 'wb') as output: + output.write(response.content) + + def download_files(self, subdir, prefix): + here = os.path.abspath(os.path.dirname(__file__)) + + js_template_dir = os.path.join( + here, + '..', + 'templates', + 'js', + ) + + directory = os.path.join(js_template_dir, subdir) + + directory = os.path.abspath(directory) + + js_files = pathlib.Path(directory).rglob('*.js') + + n = 0 + + for f in js_files: + js = os.path.basename(f) + + self.download_file(js, prefix) + + n += 1 + + return n + + def test_render_files(self): + """ + Look for all javascript files + """ + + n = 0 + + print("Rendering javascript files...") + + n += self.download_files('translated', '/js/i18n') + n += self.download_files('dynamic', '/js/dynamic') + + print(f"Rendered {n} javascript files.") diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 71f6388c68..7d51c6a4cf 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -111,6 +111,7 @@ translated_javascript_urls = [ url(r'^company.js', DynamicJsView.as_view(template_name='js/translated/company.js'), name='company.js'), url(r'^filters.js', DynamicJsView.as_view(template_name='js/translated/filters.js'), name='filters.js'), url(r'^forms.js', DynamicJsView.as_view(template_name='js/translated/forms.js'), name='forms.js'), + url(r'^helpers.js', DynamicJsView.as_view(template_name='js/translated/helpers.js'), name='helpers.js'), url(r'^label.js', DynamicJsView.as_view(template_name='js/translated/label.js'), name='label.js'), url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/translated/model_renderers.js'), name='model_renderers.js'), url(r'^modals.js', DynamicJsView.as_view(template_name='js/translated/modals.js'), name='modals.js'), diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 6f0cbe4acd..c2316ce4b0 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -160,6 +160,7 @@ + diff --git a/InvenTree/templates/js/dynamic/calendar.js b/InvenTree/templates/js/dynamic/calendar.js index 861bbe1727..268337bd52 100644 --- a/InvenTree/templates/js/dynamic/calendar.js +++ b/InvenTree/templates/js/dynamic/calendar.js @@ -1,17 +1,26 @@ {% load i18n %} +/* globals +*/ + +/* exported + clearEvents, + endDate, + startDate, +*/ + /** * Helper functions for calendar display */ function startDate(calendar) { // Extract the first displayed date on the calendar - return calendar.currentData.dateProfile.activeRange.start.toISOString().split("T")[0]; + return calendar.currentData.dateProfile.activeRange.start.toISOString().split('T')[0]; } function endDate(calendar) { // Extract the last display date on the calendar - return calendar.currentData.dateProfile.activeRange.end.toISOString().split("T")[0]; + return calendar.currentData.dateProfile.activeRange.end.toISOString().split('T')[0]; } function clearEvents(calendar) { @@ -21,5 +30,5 @@ function clearEvents(calendar) { events.forEach(function(event) { event.remove(); - }) -} \ No newline at end of file + }); +} diff --git a/InvenTree/templates/js/dynamic/inventree.js b/InvenTree/templates/js/dynamic/inventree.js index acfd57762c..7d608c1886 100644 --- a/InvenTree/templates/js/dynamic/inventree.js +++ b/InvenTree/templates/js/dynamic/inventree.js @@ -1,26 +1,44 @@ {% load inventree_extras %} +/* globals + ClipboardJS, + inventreeFormDataUpload, + launchModalForm, + user_settings, +*/ + +/* exported + attachClipboard, + enableDragAndDrop, + inventreeDocReady, + inventreeLoad, + inventreeSave, +*/ + function attachClipboard(selector, containerselector, textElement) { // set container - if (containerselector){ + if (containerselector) { containerselector = document.getElementById(containerselector); } else { containerselector = document.body; } + var text = null; + // set text-function - if (textElement){ + 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 @@ -33,15 +51,15 @@ function inventreeDocReady() { * This will be called for every page that extends "base.html" */ - window.addEventListener("dragover",function(e){ + window.addEventListener('dragover', function(e) { e = e || event; e.preventDefault(); - },false); + }, false); - window.addEventListener("drop",function(e){ + window.addEventListener('drop', function(e) { e = e || event; e.preventDefault(); - },false); + }, false); /* Add drag-n-drop functionality to any element * marked with the class 'dropzone' @@ -51,12 +69,13 @@ function inventreeDocReady() { // 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(event) { + $('.dropzone').on('dragleave drop', function() { $(this).removeClass('dragover'); }); @@ -74,19 +93,19 @@ function inventreeDocReady() { // Callback to launch the 'Database Stats' window $('#launch-stats').click(function() { - launchModalForm("/stats/", { + launchModalForm('/stats/', { no_post: true, }); }); // Initialize clipboard-buttons attachClipboard('.clip-btn'); - attachClipboard('.clip-btn', 'modal-about'); // modals - attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text'); // version-text + 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) { + $('#search-bar').autocomplete({ + source: function(request, response) { $.ajax({ url: '/api/part/', data: { @@ -94,8 +113,8 @@ function inventreeDocReady() { limit: user_settings.SEARCH_PREVIEW_RESULTS, offset: 0 }, - success: function (data) { - var transformed = $.map(data.results, function (el) { + success: function(data) { + var transformed = $.map(data.results, function(el) { return { label: el.name, id: el.pk, @@ -104,13 +123,13 @@ function inventreeDocReady() { }); response(transformed); }, - error: function () { + error: function() { response([]); } }); }, - create: function () { - $(this).data('ui-autocomplete')._renderItem = function (ul, item) { + create: function() { + $(this).data('ui-autocomplete')._renderItem = function(ul, item) { var html = ``; @@ -128,7 +147,9 @@ function inventreeDocReady() { window.location = '/part/' + ui.item.id + '/'; }, minLength: 2, - classes: {'ui-autocomplete': 'dropdown-menu search-menu'}, + classes: { + 'ui-autocomplete': 'dropdown-menu search-menu', + }, }); } @@ -140,124 +161,6 @@ function isFileTransfer(transfer) { } -function isOnlineTransfer(transfer) { - /* Determine if a drag-and-drop transfer is from another website. - * e.g. dragged from another browser window - */ - - return transfer.items.length > 0; -} - - -function getImageUrlFromTransfer(transfer) { - /* Extract external image URL from a drag-and-dropped image - */ - - var url = transfer.getData('text/html').match(/src\s*=\s*"(.+?)"/)[1]; - - console.log('Image URL: ' + url); - - return url; -} - -function makeIconBadge(icon, title) { - // Construct an 'icon badge' which floats to the right of an object - - var html = ``; - - return html; -} - -function makeIconButton(icon, cls, pk, title, options={}) { - // Construct an 'icon button' using the fontawesome set - - var classes = `btn btn-default btn-glyph ${cls}`; - - var id = `${cls}-${pk}`; - - var html = ''; - - var extraProps = ''; - - if (options.disabled) { - extraProps += "disabled='true' "; - } - - html += ``; - - return html; -} - -function makeProgressBar(value, maximum, opts={}) { - /* - * Render a progessbar! - * - * @param value is the current value of the progress bar - * @param maximum is the maximum value of the progress bar - */ - - var options = opts || {}; - - value = parseFloat(value); - - var percent = 100; - - // Prevent div-by-zero or null value - if (maximum && maximum > 0) { - maximum = parseFloat(maximum); - percent = parseInt(value / maximum * 100); - } - - if (percent > 100) { - percent = 100; - } - - var extraclass = ''; - - if (value > maximum) { - extraclass='progress-bar-over'; - } else if (value < maximum) { - extraclass = 'progress-bar-under'; - } - - var style = options.style || ''; - - var text = ''; - - if (style == 'percent') { - // Display e.g. "50%" - - text = `${percent}%`; - } else if (style == 'max') { - // Display just the maximum value - text = `${maximum}`; - } else if (style == 'value') { - // Display just the current value - text = `${value}`; - } else if (style == 'blank') { - // No display! - text = ''; - } else { - /* Default style - * Display e.g. "5 / 10" - */ - - text = `${value} / ${maximum}`; - } - - var id = options.id || 'progress-bar'; - - return ` -
-
-
${text}
-
- `; -} - - function enableDragAndDrop(element, url, options) { /* Enable drag-and-drop file uploading for a given element. @@ -272,7 +175,7 @@ function enableDragAndDrop(element, url, options) { method - HTTP method */ - data = options.data || {}; + var data = options.data || {}; $(element).on('drop', function(event) { @@ -315,40 +218,28 @@ function enableDragAndDrop(element, url, options) { }); } -function imageHoverIcon(url) { - /* Render a small thumbnail icon for an image. - * On mouseover, display a full-size version of the image - */ - - if (!url) { - url = '/static/img/blank_image.png'; - } - - var html = ` -
- - - - `; - - return html; -} +/** + * Save a key:value pair to local storage + * @param {String} name - settting key + * @param {String} value - setting value + */ function inventreeSave(name, value) { - /* - * Save a key:value pair to local storage - */ - var key = "inventree-" + name; + var key = `inventree-${name}`; localStorage.setItem(key, value); } -function inventreeLoad(name, defaultValue) { - /* - * Retrieve a key:value pair from local storage - */ - var key = "inventree-" + name; +/** + * 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); @@ -358,27 +249,3 @@ function inventreeLoad(name, defaultValue) { return value; } } - -function inventreeLoadInt(name) { - /* - * Retrieve a value from local storage, and attempt to cast to integer - */ - - var data = inventreeLoad(name); - - return parseInt(data, 10); -} - -function inventreeLoadFloat(name) { - - var data = inventreeLoad(name); - - return parseFloat(data); -} - -function inventreeDel(name) { - - var key = 'inventree-' + name; - - localStorage.removeItem(key); -} \ No newline at end of file diff --git a/InvenTree/templates/js/dynamic/nav.js b/InvenTree/templates/js/dynamic/nav.js index 601c0f4dcf..cf652724ed 100644 --- a/InvenTree/templates/js/dynamic/nav.js +++ b/InvenTree/templates/js/dynamic/nav.js @@ -1,3 +1,10 @@ +/* globals +*/ + +/* exported + attachNavCallbacks, + onPanelLoad, +*/ /* * Attach callbacks to navigation bar elements. @@ -55,7 +62,7 @@ function activatePanel(panelName, options={}) { // Iterate through the available 'select' elements until one matches panelName = null; - $('.nav-toggle').each(function(item) { + $('.nav-toggle').each(function() { var panel_name = $(this).attr('id').replace('select-', ''); if ($(`#panel-${panel_name}`).length && (panelName == null)) { @@ -83,9 +90,9 @@ function activatePanel(panelName, options={}) { $('.list-group-item').removeClass('active'); // Find the associated selector - var select = `#select-${panelName}`; + var selectElement = `#select-${panelName}`; - $(select).parent('.list-group-item').addClass('active'); + $(selectElement).parent('.list-group-item').addClass('active'); } @@ -96,7 +103,7 @@ function onPanelLoad(panel, callback) { var panelId = `#panel-${panel}`; - $(panelId).on('fadeInStarted', function(e) { + $(panelId).on('fadeInStarted', function() { // Trigger the callback callback(); @@ -105,4 +112,4 @@ function onPanelLoad(panel, callback) { $(panelId).off('fadeInStarted'); }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/dynamic/settings.js b/InvenTree/templates/js/dynamic/settings.js index 60172ead64..cb21e1fefc 100644 --- a/InvenTree/templates/js/dynamic/settings.js +++ b/InvenTree/templates/js/dynamic/settings.js @@ -1,18 +1,20 @@ {% load inventree_extras %} -// InvenTree settings + +/* exported + user_settings, + global_settings, +*/ {% user_settings request.user as USER_SETTINGS %} - -var user_settings = { +const user_settings = { {% for key, value in USER_SETTINGS.items %} {{ key }}: {% primitive_to_javascript value %}, {% endfor %} }; {% global_settings as GLOBAL_SETTINGS %} - -var global_settings = { +const global_settings = { {% for key, value in GLOBAL_SETTINGS.items %} {{ key }}: {% primitive_to_javascript value %}, {% endfor %} -}; \ No newline at end of file +}; diff --git a/InvenTree/templates/js/translated/api.js b/InvenTree/templates/js/translated/api.js index 4cf07638dc..841cf467ba 100644 --- a/InvenTree/templates/js/translated/api.js +++ b/InvenTree/templates/js/translated/api.js @@ -1,15 +1,29 @@ {% load i18n %} {% load inventree_extras %} -var jQuery = window.$; +/* globals + renderErrorMessage, + showAlertDialog, +*/ -$.urlParam = function(name){ +/* exported + inventreeGet, + inventreeDelete, + inventreeFormDataUpload, + showApiError, +*/ + +$.urlParam = function(name) { + // eslint-disable-next-line no-useless-escape var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); - if (results==null) { - return null; + + if (results == null) { + return null; } + return decodeURI(results[1]) || 0; -} +}; + // using jQuery function getCookie(name) { @@ -31,11 +45,10 @@ function getCookie(name) { function inventreeGet(url, filters={}, options={}) { // Middleware token required for data update - //var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); var csrftoken = getCookie('csrftoken'); return $.ajax({ - beforeSend: function(xhr, settings) { + beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRFToken', csrftoken); }, url: url, @@ -73,7 +86,7 @@ function inventreeFormDataUpload(url, data, options={}) { var csrftoken = getCookie('csrftoken'); return $.ajax({ - beforeSend: function(xhr, settings) { + beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRFToken', csrftoken); }, url: url, @@ -101,11 +114,10 @@ function inventreePut(url, data={}, options={}) { var method = options.method || 'PUT'; // Middleware token required for data update - //var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); var csrftoken = getCookie('csrftoken'); return $.ajax({ - beforeSend: function(xhr, settings) { + beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRFToken', csrftoken); }, url: url, @@ -157,29 +169,35 @@ function showApiError(xhr) { var message = null; switch (xhr.status) { - case 0: // No response + // No response + case 0: title = '{% trans "No Response" %}'; message = '{% trans "No response from the InvenTree server" %}'; break; - case 400: // Bad request + // Bad request + case 400: // Note: Normally error code 400 is handled separately, // and should now be shown here! title = '{% trans "Error 400: Bad request" %}'; message = '{% trans "API request returned error code 400" %}'; break; - case 401: // Not authenticated + // Not authenticated + case 401: title = '{% trans "Error 401: Not Authenticated" %}'; message = '{% trans "Authentication credentials not supplied" %}'; break; - case 403: // Permission denied + // Permission denied + case 403: title = '{% trans "Error 403: Permission Denied" %}'; message = '{% trans "You do not have the required permissions to access this function" %}'; break; - case 404: // Resource not found + // Resource not found + case 404: title = '{% trans "Error 404: Resource Not Found" %}'; message = '{% trans "The requested resource could not be located on the server" %}'; break; - case 408: // Timeout + // Timeout + case 408: title = '{% trans "Error 408: Timeout" %}'; message = '{% trans "Connection timeout while requesting data from server" %}'; break; @@ -189,8 +207,8 @@ function showApiError(xhr) { break; } - message += "
"; + message += '
'; message += renderErrorMessage(xhr); showAlertDialog(title, message); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/attachment.js b/InvenTree/templates/js/translated/attachment.js index bffe3d9995..88c73ed3e3 100644 --- a/InvenTree/templates/js/translated/attachment.js +++ b/InvenTree/templates/js/translated/attachment.js @@ -1,8 +1,18 @@ {% load i18n %} +/* globals + makeIconButton, + renderLink, +*/ + +/* exported + loadAttachmentTable, + reloadAttachmentTable, +*/ + function reloadAttachmentTable() { - $('#attachment-table').bootstrapTable("refresh"); + $('#attachment-table').bootstrapTable('refresh'); } @@ -13,7 +23,9 @@ function loadAttachmentTable(url, options) { $(table).inventreeTable({ url: url, name: options.name || 'attachments', - formatNoMatches: function() { return '{% trans "No attachments found" %}'}, + formatNoMatches: function() { + return '{% trans "No attachments found" %}'; + }, sortable: true, search: false, queryParams: options.filters || {}, @@ -40,7 +52,7 @@ function loadAttachmentTable(url, options) { { field: 'attachment', title: '{% trans "File" %}', - formatter: function(value, row) { + formatter: function(value) { var icon = 'fa-file-alt'; @@ -55,7 +67,7 @@ function loadAttachmentTable(url, options) { } else { var images = ['.png', '.jpg', '.bmp', '.gif', '.svg', '.tif']; - images.forEach(function (suffix) { + images.forEach(function(suffix) { if (fn.endsWith(suffix)) { icon = 'fa-file-image'; } @@ -106,4 +118,4 @@ function loadAttachmentTable(url, options) { } ] }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/barcode.js b/InvenTree/templates/js/translated/barcode.js index 8308086afb..a1d6fb7adf 100644 --- a/InvenTree/templates/js/translated/barcode.js +++ b/InvenTree/templates/js/translated/barcode.js @@ -1,5 +1,27 @@ {% load i18n %} +/* globals + imageHoverIcon, + inventreePut, + makeIconButton, + modalEnable, + modalSetContent, + modalSetTitle, + modalSetSubmitText, + modalShowSubmitButton, + modalSubmit, + showAlertOrCache, + showQuestionDialog, +*/ + +/* exported + barcodeCheckIn, + barcodeScanDialog, + linkBarcodeDialog, + scanItemsIntoLocation, + unlinkBarcode, +*/ + function makeBarcodeInput(placeholderText='', hintText='') { /* * Generate HTML for a barcode input @@ -99,7 +121,7 @@ function postBarcodeData(barcode_data, options={}) { } } } - ) + ); } @@ -109,7 +131,7 @@ function showBarcodeMessage(modal, message, style='danger') { html += message; - html += ""; + html += ''; $(modal + ' #barcode-error-message').html(html); } @@ -256,7 +278,7 @@ function barcodeScanDialog() { var modal = '#modal-form'; barcodeDialog( - "Scan Barcode", + '{% trans "Scan Barcode" %}', { onScan: function(response) { if ('url' in response) { @@ -280,18 +302,18 @@ function barcodeScanDialog() { /* * Dialog for linking a particular barcode to a stock item. */ -function linkBarcodeDialog(stockitem, options={}) { +function linkBarcodeDialog(stockitem) { var modal = '#modal-form'; barcodeDialog( - "{% trans 'Link Barcode to Stock Item' %}", + '{% trans "Link Barcode to Stock Item" %}', { url: '/api/barcode/link/', data: { stockitem: stockitem, }, - onScan: function(response) { + onScan: function() { $(modal).modal('hide'); location.reload(); @@ -308,13 +330,13 @@ function unlinkBarcode(stockitem) { var html = `{% trans "Unlink Barcode" %}
`; - html += "{% trans 'This will remove the association between this stock item and the barcode' %}"; + html += '{% trans "This will remove the association between this stock item and the barcode" %}'; showQuestionDialog( - "{% trans 'Unlink Barcode' %}", + '{% trans "Unlink Barcode" %}', html, { - accept_text: "{% trans 'Unlink' %}", + accept_text: '{% trans "Unlink" %}', accept: function() { inventreePut( `/api/stock/${stockitem}/`, @@ -324,7 +346,7 @@ function unlinkBarcode(stockitem) { }, { method: 'PATCH', - success: function(response, status) { + success: function() { location.reload(); }, }, @@ -338,7 +360,7 @@ function unlinkBarcode(stockitem) { /* * Display dialog to check multiple stock items in to a stock location. */ -function barcodeCheckIn(location_id, options={}) { +function barcodeCheckIn(location_id) { var modal = '#modal-form'; @@ -430,7 +452,9 @@ function barcodeCheckIn(location_id, options={}) { // Called when the 'check-in' button is pressed - var data = {location: location_id}; + var data = { + location: location_id + }; // Extract 'notes' field data.notes = $(modal + ' #notes').val(); @@ -447,7 +471,7 @@ function barcodeCheckIn(location_id, options={}) { data.items = entries; inventreePut( - "{% url 'api-stock-transfer' %}", + '{% url "api-stock-transfer" %}', data, { method: 'POST', @@ -467,7 +491,7 @@ function barcodeCheckIn(location_id, options={}) { }, onScan: function(response) { if ('stockitem' in response) { - stockitem = response.stockitem; + var stockitem = response.stockitem; var duplicate = false; @@ -478,7 +502,7 @@ function barcodeCheckIn(location_id, options={}) { }); if (duplicate) { - showBarcodeMessage(modal, '{% trans "Stock Item already scanned" %}', "warning"); + showBarcodeMessage(modal, '{% trans "Stock Item already scanned" %}', 'warning'); } else { if (stockitem.location == location_id) { @@ -489,14 +513,14 @@ function barcodeCheckIn(location_id, options={}) { // Add this stock item to the list items.push(stockitem); - showBarcodeMessage(modal, '{% trans "Added stock item" %}', "success"); + showBarcodeMessage(modal, '{% trans "Added stock item" %}', 'success'); reloadTable(); } } else { // Barcode does not match a stock item - showBarcodeMessage(modal, '{% trans "Barcode does not match Stock Item" %}', "warning"); + showBarcodeMessage(modal, '{% trans "Barcode does not match Stock Item" %}', 'warning'); } }, } @@ -525,12 +549,12 @@ function scanItemsIntoLocation(item_id_list, options={}) { function updateLocationInfo(location) { var div = $(modal + ' #header-div'); - if (stock_location && stock_location.pk) { + if (location && location.pk) { div.html(`
{% trans "Location" %}
- ${stock_location.name}
- ${stock_location.description} + ${location.name}
+ ${location.description}
`); } else { @@ -561,7 +585,7 @@ function scanItemsIntoLocation(item_id_list, options={}) { items.push({ pk: pk, }); - }) + }); var data = { location: stock_location.pk, @@ -587,7 +611,7 @@ function scanItemsIntoLocation(item_id_list, options={}) { } } } - ) + ); }, onScan: function(response) { updateLocationInfo(null); @@ -603,10 +627,10 @@ function scanItemsIntoLocation(item_id_list, options={}) { showBarcodeMessage( modal, '{% trans "Barcode does not match a valid location" %}', - "warning", + 'warning', ); } } } - ) -} \ No newline at end of file + ); +} diff --git a/InvenTree/templates/js/translated/bom.js b/InvenTree/templates/js/translated/bom.js index 37a3eb23b0..bcfa7ef5ff 100644 --- a/InvenTree/templates/js/translated/bom.js +++ b/InvenTree/templates/js/translated/bom.js @@ -1,5 +1,25 @@ {% load i18n %} +/* globals + constructForm, + imageHoverIcon, + inventreeGet, + inventreePut, + launchModalForm, + loadTableFilters, + makePartIcons, + renderLink, + setupFilterList, + yesNoLabel, +*/ + +/* exported + newPartFromBomWizard, + loadBomTable, + removeRowFromBomWizard, + removeColFromBomWizard, +*/ + /* BOM management functions. * Requires follwing files to be loaded first: * - api.js @@ -28,7 +48,7 @@ function bomItemFields() { } -function reloadBomTable(table, options) { +function reloadBomTable(table) { table.bootstrapTable('refresh'); } @@ -126,7 +146,7 @@ function loadBomTable(table, options) { var params = { part: options.parent_id, ordering: 'name', - } + }; if (options.part_detail) { params.part_detail = true; @@ -157,7 +177,7 @@ function loadBomTable(table, options) { checkbox: true, visible: true, switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { // Disable checkbox if the row is defined for a *different* part! if (row.part != options.parent_id) { return { @@ -182,7 +202,7 @@ function loadBomTable(table, options) { field: 'sub_part', title: '{% trans "Part" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.sub_part}/`; var html = imageHoverIcon(row.sub_part_detail.thumbnail) + renderLink(row.sub_part_detail.full_name, url); @@ -225,7 +245,7 @@ function loadBomTable(table, options) { title: '{% trans "Quantity" %}', searchable: false, sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var text = value; // The 'value' is a text string with (potentially) multiple trailing zeros @@ -244,13 +264,12 @@ function loadBomTable(table, options) { }, }); - cols.push( - { + cols.push({ field: 'sub_part_detail.stock', title: '{% trans "Available" %}', searchable: false, sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.sub_part_detail.pk}/?display=stock`; var text = value; @@ -263,32 +282,29 @@ function loadBomTable(table, options) { } }); - cols.push( - { + cols.push({ field: 'purchase_price_range', title: '{% trans "Purchase Price Range" %}', searchable: false, sortable: true, }); - cols.push( - { + cols.push({ field: 'purchase_price_avg', title: '{% trans "Purchase Price Average" %}', searchable: false, sortable: true, }); - cols.push( - { + cols.push({ field: 'price_range', title: '{% trans "Supplier Cost" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value) { if (value) { return value; } else { - return "{% trans 'No supplier pricing available' %}"; + return `{% trans 'No supplier pricing available' %}`; } } }); @@ -308,13 +324,13 @@ function loadBomTable(table, options) { formatter: function(value) { return yesNoLabel(value); } - }) + }); cols.push({ field: 'inherited', title: '{% trans "Inherited" %}', searchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { // This BOM item *is* inheritable, but is defined for this BOM if (!row.inherited) { return yesNoLabel(false); @@ -332,9 +348,9 @@ function loadBomTable(table, options) { cols.push( { - 'field': 'can_build', - 'title': '{% trans "Can Build" %}', - formatter: function(value, row, index, field) { + field: 'can_build', + title: '{% trans "Can Build" %}', + formatter: function(value, row) { var can_build = 0; if (row.quantity > 0) { @@ -360,7 +376,7 @@ function loadBomTable(table, options) { }, sortable: true, } - ) + ); // Part notes cols.push( @@ -379,7 +395,7 @@ function loadBomTable(table, options) { switchable: false, field: 'pk', visible: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (row.part == options.parent_id) { @@ -391,7 +407,7 @@ function loadBomTable(table, options) { var bDelt = ``; - var html = "
"; + var html = `
`; html += bEdit; html += bDelt; @@ -402,7 +418,7 @@ function loadBomTable(table, options) { html += bValid; } - html += "
"; + html += `
`; return html; } else { @@ -434,7 +450,7 @@ function loadBomTable(table, options) { response[idx].parentId = bom_pk; if (response[idx].sub_part_detail.assembly) { - requestSubItems(response[idx].pk, response[idx].sub_part) + requestSubItems(response[idx].pk, response[idx].sub_part); } } @@ -446,7 +462,7 @@ function loadBomTable(table, options) { console.log('Error requesting BOM for part=' + part_pk); } } - ) + ); } table.inventreeTable({ @@ -459,7 +475,7 @@ function loadBomTable(table, options) { name: 'bom', sortable: true, search: true, - rowStyle: function(row, index) { + rowStyle: function(row) { var classes = []; @@ -532,7 +548,6 @@ function loadBomTable(table, options) { table.on('click', '.bom-delete-button', function() { var pk = $(this).attr('pk'); - var url = `/part/bom/${pk}/delete/`; constructForm(`/api/bom/${pk}/`, { method: 'DELETE', @@ -546,7 +561,6 @@ function loadBomTable(table, options) { table.on('click', '.bom-edit-button', function() { var pk = $(this).attr('pk'); - var url = `/part/bom/${pk}/edit/`; var fields = bomItemFields(); diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js index 26f3876af3..d359d6cf4e 100644 --- a/InvenTree/templates/js/translated/build.js +++ b/InvenTree/templates/js/translated/build.js @@ -1,6 +1,33 @@ {% load i18n %} {% load inventree_extras %} +/* globals + buildStatusDisplay, + constructForm, + getFieldByName, + global_settings, + imageHoverIcon, + inventreeGet, + launchModalForm, + linkButtonsToSelection, + loadTableFilters, + makeIconBadge, + makeIconButton, + makePartIcons, + makeProgressBar, + renderLink, + setupFilterList, +*/ + +/* exported + editBuildOrder, + loadAllocationTable, + loadBuildOrderAllocationTable, + loadBuildOutputAllocationTable, + loadBuildPartsTable, + loadBuildTable, +*/ + function buildFormFields() { return { @@ -32,7 +59,7 @@ function buildFormFields() { } -function editBuildOrder(pk, options={}) { +function editBuildOrder(pk) { var fields = buildFormFields(); @@ -76,10 +103,10 @@ function makeBuildOutputActionButtons(output, buildInfo, lines) { var buildId = buildInfo.pk; + var outputId = 'untracked'; + if (output) { outputId = output.pk; - } else { - outputId = 'untracked'; } var panel = `#allocation-panel-${outputId}`; @@ -98,7 +125,7 @@ function makeBuildOutputActionButtons(output, buildInfo, lines) { html += makeIconButton( 'fa-magic icon-blue', 'button-output-auto', outputId, '{% trans "Auto-allocate stock items to this output" %}', - ); + ); } if (lines > 0) { @@ -106,7 +133,7 @@ function makeBuildOutputActionButtons(output, buildInfo, lines) { html += makeIconButton( 'fa-minus-circle icon-red', 'button-output-unallocate', outputId, '{% trans "Unallocate stock from build output" %}', - ); + ); } @@ -117,7 +144,7 @@ function makeBuildOutputActionButtons(output, buildInfo, lines) { 'fa-check icon-green', 'button-output-complete', outputId, '{% trans "Complete build output" %}', { - //disabled: true + // disabled: true } ); @@ -125,7 +152,7 @@ function makeBuildOutputActionButtons(output, buildInfo, lines) { html += makeIconButton( 'fa-trash-alt icon-red', 'button-output-delete', outputId, '{% trans "Delete build output" %}', - ); + ); // TODO - Add a button to "destroy" the particular build output (mark as damaged, scrap) } @@ -202,13 +229,13 @@ function loadBuildOrderAllocationTable(table, options={}) { options.params['build_detail'] = true; options.params['location_detail'] = true; - var filters = loadTableFilters("buildorderallocation"); + var filters = loadTableFilters('buildorderallocation'); for (var key in options.params) { filters[key] = options.params[key]; } - setupFilterList("buildorderallocation", $(table)); + setupFilterList('buildorderallocation', $(table)); $(table).inventreeTable({ url: '{% url "api-build-item-list" %}', @@ -219,7 +246,7 @@ function loadBuildOrderAllocationTable(table, options={}) { paginationVAlign: 'bottom', original: options.params, formatNoMatches: function() { - return '{% trans "No build order allocations found" %}' + return '{% trans "No build order allocations found" %}'; }, columns: [ { @@ -345,13 +372,13 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { // Register button callbacks once table data are loaded // Callback for 'allocate' button - $(table).find(".button-add").click(function() { + $(table).find('.button-add').click(function() { // Primary key of the 'sub_part' var pk = $(this).attr('pk'); // Launch form to allocate new stock against this output - launchModalForm("{% url 'build-item-create' %}", { + launchModalForm('{% url "build-item-create" %}', { success: reloadTable, data: { part: pk, @@ -391,7 +418,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { } } } - ) + ); } } ] @@ -400,10 +427,8 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { // Callback for 'buy' button $(table).find('.button-buy').click(function() { - var pk = $(this).attr('pk'); - var idx = $(this).closest('tr').attr('data-index'); - var row = $(table).bootstrapTable('getData')[idx]; + var pk = $(this).attr('pk'); launchModalForm('{% url "order-parts" %}', { data: { @@ -447,7 +472,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { // Load table of BOM items $(table).inventreeTable({ - url: "{% url 'api-bom-list' %}", + url: '{% url "api-bom-list" %}', queryParams: { part: partId, sub_part_detail: true, @@ -467,7 +492,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { build: buildId, part_detail: true, location_detail: true, - } + }; if (output) { params.sub_part_trackable = true; @@ -496,7 +521,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { var key = parseInt(part); if (!(key in allocations)) { - allocations[key] = new Array(); + allocations[key] = []; } allocations[key].push(item); @@ -573,8 +598,6 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { element.html(html); - var lineItem = row; - var subTable = $(`#${subTableId}`); subTable.bootstrapTable({ @@ -595,7 +618,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { width: '50%', field: 'quantity', title: '{% trans "Assigned Stock" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var text = ''; var url = ''; @@ -618,7 +641,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { { field: 'location', title: '{% trans "Location" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (row.stock_item_detail.location) { var text = row.stock_item_detail.location_name; var url = `/stock/location/${row.stock_item_detail.location}/`; @@ -631,7 +654,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { }, { field: 'actions', - formatter: function(value, row, index, field) { + formatter: function(value, row) { /* Actions available for a particular stock item allocation: * * - Edit the allocation quantity @@ -678,7 +701,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { field: 'sub_part_detail.full_name', title: '{% trans "Required Part" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.sub_part}/`; var thumb = row.sub_part_detail.thumbnail; var name = row.sub_part_detail.full_name; @@ -709,7 +732,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { field: 'allocated', title: '{% trans "Allocated" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var allocated = 0; if (row.allocations) { @@ -757,7 +780,7 @@ function loadBuildOutputAllocationTable(buildInfo, output, options={}) { { field: 'actions', title: '{% trans "Actions" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { // Generate action buttons for this build output var html = `
`; @@ -804,7 +827,7 @@ function loadBuildTable(table, options) { params['part_detail'] = true; if (!options.disableFilters) { - filters = loadTableFilters("build"); + filters = loadTableFilters('build'); } for (var key in params) { @@ -815,7 +838,7 @@ function loadBuildTable(table, options) { var filterTarget = options.filterTarget || null; - setupFilterList("build", table, filterTarget); + setupFilterList('build', table, filterTarget); $(table).inventreeTable({ method: 'get', @@ -846,7 +869,7 @@ function loadBuildTable(table, options) { title: '{% trans "Build" %}', sortable: true, switchable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX; @@ -873,7 +896,7 @@ function loadBuildTable(table, options) { title: '{% trans "Part" %}', sortable: true, sortName: 'part__name', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var html = imageHoverIcon(row.part_detail.thumbnail); @@ -887,12 +910,12 @@ function loadBuildTable(table, options) { field: 'quantity', title: '{% trans "Completed" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { return makeProgressBar( row.completed, row.quantity, { - //style: 'max', + // style: 'max', } ); } @@ -901,7 +924,7 @@ function loadBuildTable(table, options) { field: 'status', title: '{% trans "Status" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value) { return buildStatusDisplay(value); }, }, @@ -914,13 +937,10 @@ function loadBuildTable(table, options) { field: 'issued_by', title: '{% trans "Issued by" %}', sortable: true, - formatter: function(value, row, index, field) { - if (value) - { + formatter: function(value, row) { + if (value) { return row.issued_by_detail.username; - } - else - { + } else { return `{% trans "No user information" %}`; } } @@ -929,13 +949,10 @@ function loadBuildTable(table, options) { field: 'responsible', title: '{% trans "Responsible" %}', sortable: true, - formatter: function(value, row, index, field) { - if (value) - { + formatter: function(value, row) { + if (value) { return row.responsible_detail.name; - } - else - { + } else { return '{% trans "No information" %}'; } } @@ -968,7 +985,7 @@ function updateAllocationTotal(id, count, required) { $('#allocation-total-'+id).html(count); - var el = $("#allocation-panel-" + id); + var el = $('#allocation-panel-' + id); el.removeClass('part-allocation-pass part-allocation-underallocated part-allocation-overallocated'); if (count < required) { @@ -986,32 +1003,39 @@ function loadAllocationTable(table, part_id, part, url, required, button) { table.bootstrapTable({ url: url, sortable: false, - formatNoMatches: function() { return '{% trans "No parts allocated for" %} ' + part; }, + formatNoMatches: function() { + return '{% trans "No parts allocated for" %} ' + part; + }, columns: [ { field: 'stock_item_detail', title: '{% trans "Stock Item" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { return '' + parseFloat(value.quantity) + ' x ' + value.part_name + ' @ ' + value.location_name; } }, { field: 'stock_item_detail.quantity', title: '{% trans "Available" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { return parseFloat(value); } }, { field: 'quantity', title: '{% trans "Allocated" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var html = parseFloat(value); - var bEdit = ""; - var bDel = ""; + var bEdit = ``; + var bDel = ``; - html += "
" + bEdit + bDel + "
"; + html += ` +
+ ${bEdit} + ${bDel} +
+ `; return html; } @@ -1028,7 +1052,7 @@ function loadAllocationTable(table, part_id, part, url, required, button) { }); }); - table.on('load-success.bs.table', function(data) { + table.on('load-success.bs.table', function() { // Extract table data var results = table.bootstrapTable('getData'); @@ -1106,9 +1130,6 @@ function loadBuildPartsTable(table, options={}) { $(table).find('.button-buy').click(function() { var pk = $(this).attr('pk'); - var idx = $(this).closest('tr').attr('data-index'); - var row = $(table).bootstrapTable('getData')[idx]; - launchModalForm('{% url "order-parts" %}', { data: { parts: [ @@ -1122,10 +1143,6 @@ function loadBuildPartsTable(table, options={}) { $(table).find('.button-build').click(function() { var pk = $(this).attr('pk'); - // Extract row data from the table - var idx = $(this).closest('tr').attr('data-index'); - var row = $(table).bootstrapTable('getData')[idx]; - newBuildOrder({ part: pk, parent: options.build, @@ -1139,7 +1156,7 @@ function loadBuildPartsTable(table, options={}) { title: '{% trans "Part" %}', switchable: false, sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.sub_part}/`; var html = imageHoverIcon(row.sub_part_detail.thumbnail) + renderLink(row.sub_part_detail.full_name, url); @@ -1177,7 +1194,7 @@ function loadBuildPartsTable(table, options={}) { switchable: false, field: 'sub_part_detail.stock', title: '{% trans "Available" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return makeProgressBar( value, row.quantity * options.build_remaining, @@ -1201,7 +1218,7 @@ function loadBuildPartsTable(table, options={}) { field: 'actions', title: '{% trans "Actions" %}', switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { // Generate action buttons against the part var html = `
`; @@ -1228,7 +1245,7 @@ function loadBuildPartsTable(table, options={}) { sortable: true, search: true, onPostBody: setupTableCallbacks, - rowStyle: function(row, index) { + rowStyle: function(row) { var classes = []; // Shade rows differently if they are for different parent parts @@ -1254,4 +1271,4 @@ function loadBuildPartsTable(table, options={}) { original: params, columns: columns, }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/company.js b/InvenTree/templates/js/translated/company.js index 9c67e77db7..c014139e1b 100644 --- a/InvenTree/templates/js/translated/company.js +++ b/InvenTree/templates/js/translated/company.js @@ -1,6 +1,33 @@ {% load i18n %} +/* globals + constructForm, + imageHoverIcon, + inventreeDelete, + loadTableFilters, + makeIconButton, + renderLink, + setupFilterList, + showQuestionDialog, +*/ + +/* exported + createCompany, + createManufacturerPart, + createSupplierPart, + deleteManufacturerParts, + editCompany, + loadCompanyTable, + loadManufacturerPartTable, + loadManufacturerPartParameterTable, + loadSupplierPartTable, +*/ + +/** + * Construct a set of form fields for creating / editing a ManufacturerPart + * @returns + */ function manufacturerPartFields() { return { @@ -17,6 +44,10 @@ function manufacturerPartFields() { } +/** + * Launches a form to create a new ManufacturerPart + * @param {object} options + */ function createManufacturerPart(options={}) { var fields = manufacturerPartFields(); @@ -32,14 +63,14 @@ function createManufacturerPart(options={}) { fields.manufacturer.secondary = { title: '{% trans "Add Manufacturer" %}', - fields: function(data) { + fields: function() { var company_fields = companyFormFields(); company_fields.is_manufacturer.value = true; return company_fields; } - } + }; constructForm('{% url "api-manufacturer-part-list" %}', { fields: fields, @@ -50,6 +81,11 @@ function createManufacturerPart(options={}) { } +/** + * Launches a form to edit a ManufacturerPart + * @param {integer} part - ID of a ManufacturerPart + * @param {object} options + */ function editManufacturerPart(part, options={}) { var url = `/api/company/part/manufacturer/${part}/`; @@ -126,7 +162,7 @@ function createSupplierPart(options={}) { // Add a secondary modal for the supplier fields.supplier.secondary = { title: '{% trans "Add Supplier" %}', - fields: function(data) { + fields: function() { var company_fields = companyFormFields(); company_fields.is_supplier.value = true; @@ -185,7 +221,7 @@ function deleteSupplierPart(part, options={}) { // Returns a default form-set for creating / editing a Company object -function companyFormFields(options={}) { +function companyFormFields() { return { name: {}, @@ -228,7 +264,7 @@ function editCompany(pk, options={}) { title: '{% trans "Edit Company" %}', } ); -}; +} /* * Launches a form to create a new company. @@ -265,13 +301,13 @@ function loadCompanyTable(table, url, options={}) { // Query parameters var params = options.params || {}; - var filters = loadTableFilters("company"); + var filters = loadTableFilters('company'); for (var key in params) { filters[key] = params[key]; } - setupFilterList("company", $(table)); + setupFilterList('company', $(table)); var columns = [ { @@ -285,7 +321,7 @@ function loadCompanyTable(table, url, options={}) { title: '{% trans "Company" %}', sortable: true, switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var html = imageHoverIcon(row.image) + renderLink(value, row.url); if (row.is_customer) { @@ -310,7 +346,7 @@ function loadCompanyTable(table, url, options={}) { { field: 'website', title: '{% trans "Website" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { if (value) { return renderLink(value, value); } @@ -345,7 +381,9 @@ function loadCompanyTable(table, url, options={}) { queryParams: filters, groupBy: false, sidePagination: 'server', - formatNoMatches: function() { return "{% trans "No company information found" %}"; }, + formatNoMatches: function() { + return '{% trans "No company information found" %}'; + }, showColumns: true, name: options.pagetype || 'company', columns: columns, @@ -366,18 +404,18 @@ function deleteManufacturerParts(selections, options={}) {

{% trans "The following manufacturer parts will be deleted" %}:

-
`; +
  • +

    ${item.MPN} - ${item.part_detail.full_name}

    +
  • `; + }); + + text += ` + +
    `; showQuestionDialog( '{% trans "Delete Manufacturer Parts" %}', @@ -401,7 +439,7 @@ function deleteManufacturerParts(selections, options={}) { if (options.onSuccess) { options.onSuccess(); } - }) + }); } } ); @@ -418,13 +456,13 @@ function loadManufacturerPartTable(table, url, options) { var params = options.params || {}; // Load filters - var filters = loadTableFilters("manufacturer-part"); + var filters = loadTableFilters('manufacturer-part'); for (var key in params) { filters[key] = params[key]; } - setupFilterList("manufacturer-part", $(table)); + setupFilterList('manufacturer-part', $(table)); $(table).inventreeTable({ url: url, @@ -433,7 +471,9 @@ function loadManufacturerPartTable(table, url, options) { queryParams: filters, name: 'manufacturerparts', groupBy: false, - formatNoMatches: function() { return '{% trans "No manufacturer parts found" %}'; }, + formatNoMatches: function() { + return '{% trans "No manufacturer parts found" %}'; + }, columns: [ { checkbox: true, @@ -445,7 +485,7 @@ function loadManufacturerPartTable(table, url, options) { sortable: true, field: 'part_detail.full_name', title: '{% trans "Part" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.part}/`; @@ -470,7 +510,7 @@ function loadManufacturerPartTable(table, url, options) { sortable: true, field: 'manufacturer', title: '{% trans "Manufacturer" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (value && row.manufacturer_detail) { var name = row.manufacturer_detail.name; var url = `/company/${value}/`; @@ -478,7 +518,7 @@ function loadManufacturerPartTable(table, url, options) { return html; } else { - return "-"; + return '-'; } } }, @@ -486,14 +526,14 @@ function loadManufacturerPartTable(table, url, options) { sortable: true, field: 'MPN', title: '{% trans "MPN" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return renderLink(value, `/manufacturer-part/${row.pk}/`); } }, { field: 'link', title: '{% trans "Link" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { if (value) { return renderLink(value, value); } else { @@ -536,8 +576,9 @@ function loadManufacturerPartTable(table, url, options) { { onSuccess: function() { $(table).bootstrapTable('refresh'); + } } - }); + ); }); $(table).find('.button-manufacturer-part-delete').click(function() { @@ -548,9 +589,10 @@ function loadManufacturerPartTable(table, url, options) { { onSuccess: function() { $(table).bootstrapTable('refresh'); + } } - }); - }) + ); + }); } }); } @@ -564,7 +606,7 @@ function loadManufacturerPartParameterTable(table, url, options) { var params = options.params || {}; // Load filters - var filters = loadTableFilters("manufacturer-part-parameters"); + var filters = loadTableFilters('manufacturer-part-parameters'); // Overwrite explicit parameters for (var key in params) { @@ -580,7 +622,9 @@ function loadManufacturerPartParameterTable(table, url, options) { queryParams: filters, name: 'manufacturerpartparameters', groupBy: false, - formatNoMatches: function() { return '{% trans "No parameters found" %}'; }, + formatNoMatches: function() { + return '{% trans "No parameters found" %}'; + }, columns: [ { checkbox: true, @@ -668,13 +712,13 @@ function loadSupplierPartTable(table, url, options) { var params = options.params || {}; // Load filters - var filters = loadTableFilters("supplier-part"); + var filters = loadTableFilters('supplier-part'); for (var key in params) { filters[key] = params[key]; } - setupFilterList("supplier-part", $(table)); + setupFilterList('supplier-part', $(table)); $(table).inventreeTable({ url: url, @@ -683,7 +727,9 @@ function loadSupplierPartTable(table, url, options) { queryParams: filters, name: 'supplierparts', groupBy: false, - formatNoMatches: function() { return '{% trans "No supplier parts found" %}'; }, + formatNoMatches: function() { + return '{% trans "No supplier parts found" %}'; + }, columns: [ { checkbox: true, @@ -695,7 +741,7 @@ function loadSupplierPartTable(table, url, options) { sortable: true, field: 'part_detail.full_name', title: '{% trans "Part" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/part/${row.part}/`; @@ -720,7 +766,7 @@ function loadSupplierPartTable(table, url, options) { sortable: true, field: 'supplier', title: '{% trans "Supplier" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (value) { var name = row.supplier_detail.name; var url = `/company/${value}/`; @@ -728,7 +774,7 @@ function loadSupplierPartTable(table, url, options) { return html; } else { - return "-"; + return '-'; } }, }, @@ -736,7 +782,7 @@ function loadSupplierPartTable(table, url, options) { sortable: true, field: 'SKU', title: '{% trans "Supplier Part" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return renderLink(value, `/supplier-part/${row.pk}/`); } }, @@ -746,7 +792,7 @@ function loadSupplierPartTable(table, url, options) { sortable: true, field: 'manufacturer_detail.name', title: '{% trans "Manufacturer" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (value && row.manufacturer_detail) { var name = value; var url = `/company/${row.manufacturer_detail.pk}/`; @@ -754,7 +800,7 @@ function loadSupplierPartTable(table, url, options) { return html; } else { - return "-"; + return '-'; } } }, @@ -764,18 +810,18 @@ function loadSupplierPartTable(table, url, options) { sortable: true, field: 'manufacturer_part_detail.MPN', title: '{% trans "MPN" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (value && row.manufacturer_part) { return renderLink(value, `/manufacturer-part/${row.manufacturer_part}/`); } else { - return "-"; + return '-'; } } }, { field: 'link', title: '{% trans "Link" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { if (value) { return renderLink(value, value); } else { @@ -827,8 +873,9 @@ function loadSupplierPartTable(table, url, options) { { onSuccess: function() { $(table).bootstrapTable('refresh'); + } } - }); + ); }); $(table).find('.button-supplier-part-delete').click(function() { @@ -839,9 +886,10 @@ function loadSupplierPartTable(table, url, options) { { onSuccess: function() { $(table).bootstrapTable('refresh'); + } } - }); - }) + ); + }); } }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/filters.js b/InvenTree/templates/js/translated/filters.js index bc0dc1b958..d7e8f45ca5 100644 --- a/InvenTree/templates/js/translated/filters.js +++ b/InvenTree/templates/js/translated/filters.js @@ -1,5 +1,16 @@ {% load i18n %} +/* globals + getAvailableTableFilters, + inventreeLoad, + inventreeSave, + reloadTableFilters, +*/ + +/* exported + setupFilterList, +*/ + /** * Code for managing query filters / table options. * @@ -16,12 +27,12 @@ function defaultFilters() { return { - stock: "cascade=1&in_stock=1", - build: "", - parts: "cascade=1", - company: "", - salesorder: "", - purchaseorder: "", + stock: 'cascade=1&in_stock=1', + build: '', + parts: 'cascade=1', + company: '', + salesorder: '', + purchaseorder: '', }; } @@ -34,7 +45,7 @@ function defaultFilters() { */ function loadTableFilters(tableKey) { - var lookup = "table-filters-" + tableKey.toLowerCase(); + var lookup = 'table-filters-' + tableKey.toLowerCase(); var defaults = defaultFilters()[tableKey] || ''; @@ -42,7 +53,7 @@ function loadTableFilters(tableKey) { var filters = {}; - filterstring.split("&").forEach(function(item, index) { + filterstring.split('&').forEach(function(item) { item = item.trim(); if (item.length > 0) { @@ -67,7 +78,7 @@ function loadTableFilters(tableKey) { * @param {*} filters - object of string:string pairs */ function saveTableFilters(tableKey, filters) { - var lookup = "table-filters-" + tableKey.toLowerCase(); + var lookup = 'table-filters-' + tableKey.toLowerCase(); var strings = []; @@ -190,7 +201,7 @@ function generateAvailableFilterList(tableKey) { var html = ``; for (var key in options) { - option = options[key]; + var option = options[key]; html += ``; } @@ -295,15 +306,11 @@ function setupFilterList(tableKey, table, target) { var html = ''; - //`
    `; - html += generateAvailableFilterList(tableKey); html += generateFilterInput(tableKey); html += ``; - //html += '
    '; - element.append(html); // Add a callback for when the filter tag selection is changed @@ -346,7 +353,7 @@ function setupFilterList(tableKey, table, target) { }); // Add callback for deleting each filter - element.find(".close").click(function(event) { + element.find('.close').click(function() { var me = $(this); var filter = me.attr(`filter-tag-${tableKey}`); @@ -372,15 +379,6 @@ function getFilterTitle(tableKey, filterKey) { } -/** - * Return the pretty description for the given table and filter selection - */ -function getFilterDescription(tableKey, filterKey) { - var settings = getFilterSettings(tableKey, filterKey); - - return settings.title; -} - /* * Return a description for the given table and filter selection. */ diff --git a/InvenTree/templates/js/translated/forms.js b/InvenTree/templates/js/translated/forms.js index 904053a423..a3d1946beb 100644 --- a/InvenTree/templates/js/translated/forms.js +++ b/InvenTree/templates/js/translated/forms.js @@ -1,6 +1,34 @@ {% load i18n %} {% load inventree_extras %} +/* globals + attachToggle, + createNewModal, + inventreeFormDataUpload, + inventreeGet, + inventreePut, + modalEnable, + modalShowSubmitButton, + renderBuild, + renderCompany, + renderManufacturerPart, + renderOwner, + renderPart, + renderPartCategory, + renderPartParameterTemplate, + renderStockItem, + renderStockLocation, + renderSupplierPart, + renderUser, + showAlertDialog, + showAlertOrCache, + showApiError, +*/ + +/* exported + setFormGroupVisibility +*/ + /** * * This file contains code for rendering (and managing) HTML forms @@ -81,7 +109,7 @@ function canDelete(OPTIONS) { * Get the API endpoint options at the provided URL, * using a HTTP options request. */ -function getApiEndpointOptions(url, callback, options) { +function getApiEndpointOptions(url, callback) { // Return the ajax request object $.ajax({ @@ -93,7 +121,7 @@ function getApiEndpointOptions(url, callback, options) { json: 'application/json', }, success: callback, - error: function(request, status, error) { + error: function() { // TODO: Handle error console.log(`ERROR in getApiEndpointOptions at '${url}'`); } @@ -172,7 +200,7 @@ function constructChangeForm(fields, options) { constructFormBody(fields, options); }, - error: function(request, status, error) { + error: function() { // TODO: Handle error here console.log(`ERROR in constructChangeForm at '${options.url}'`); } @@ -211,7 +239,7 @@ function constructDeleteForm(fields, options) { constructFormBody(fields, options); }, - error: function(request, status, error) { + error: function() { // TODO: Handle error here console.log(`ERROR in constructDeleteForm at '${options.url}`); } @@ -284,58 +312,58 @@ function constructForm(url, options) { */ switch (options.method) { - case 'POST': - if (canCreate(OPTIONS)) { - constructCreateForm(OPTIONS.actions.POST, options); - } else { - // User does not have permission to POST to the endpoint - showAlertDialog( - '{% trans "Action Prohibited" %}', - '{% trans "Create operation not allowed" %}' - ); - console.log(`'POST action unavailable at ${url}`); - } - break; - case 'PUT': - case 'PATCH': - if (canChange(OPTIONS)) { - constructChangeForm(OPTIONS.actions.PUT, options); - } else { - // User does not have permission to PUT/PATCH to the endpoint - showAlertDialog( - '{% trans "Action Prohibited" %}', - '{% trans "Update operation not allowed" %}' - ); - console.log(`${options.method} action unavailable at ${url}`); - } - break; - case 'DELETE': - if (canDelete(OPTIONS)) { - constructDeleteForm(OPTIONS.actions.DELETE, options); - } else { - // User does not have permission to DELETE to the endpoint - showAlertDialog( - '{% trans "Action Prohibited" %}', - '{% trans "Delete operation not allowed" %}' - ); - console.log(`DELETE action unavailable at ${url}`); - } - break; - case 'GET': - if (canView(OPTIONS)) { - // TODO? - } else { - // User does not have permission to GET to the endpoint - showAlertDialog( - '{% trans "Action Prohibited" %}', - '{% trans "View operation not allowed" %}' - ); - console.log(`GET action unavailable at ${url}`); - } - break; - default: - console.log(`constructForm() called with invalid method '${options.method}'`); - break; + case 'POST': + if (canCreate(OPTIONS)) { + constructCreateForm(OPTIONS.actions.POST, options); + } else { + // User does not have permission to POST to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Create operation not allowed" %}' + ); + console.log(`'POST action unavailable at ${url}`); + } + break; + case 'PUT': + case 'PATCH': + if (canChange(OPTIONS)) { + constructChangeForm(OPTIONS.actions.PUT, options); + } else { + // User does not have permission to PUT/PATCH to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Update operation not allowed" %}' + ); + console.log(`${options.method} action unavailable at ${url}`); + } + break; + case 'DELETE': + if (canDelete(OPTIONS)) { + constructDeleteForm(OPTIONS.actions.DELETE, options); + } else { + // User does not have permission to DELETE to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "Delete operation not allowed" %}' + ); + console.log(`DELETE action unavailable at ${url}`); + } + break; + case 'GET': + if (canView(OPTIONS)) { + // TODO? + } else { + // User does not have permission to GET to the endpoint + showAlertDialog( + '{% trans "Action Prohibited" %}', + '{% trans "View operation not allowed" %}' + ); + console.log(`GET action unavailable at ${url}`); + } + break; + default: + console.log(`constructForm() called with invalid method '${options.method}'`); + break; } }); } @@ -374,7 +402,7 @@ function constructFormBody(fields, options) { } // Provide each field object with its own name - for(field in fields) { + for (field in fields) { fields[field].name = field; // If any "instance_filters" are defined for the endpoint, copy them across (overwrite) @@ -427,19 +455,19 @@ function constructFormBody(fields, options) { for (var idx = 0; idx < field_names.length; idx++) { - var name = field_names[idx]; + var field_name = field_names[idx]; - var field = fields[name]; + var field = fields[field_name]; switch (field.type) { - // Skip field types which are simply not supported - case 'nested object': - continue; - default: - break; + // Skip field types which are simply not supported + case 'nested object': + continue; + default: + break; } - html += constructField(name, field, options); + html += constructField(field_name, field, options); } if (options.current_group) { @@ -640,19 +668,19 @@ function submitFormData(fields, options) { data, { method: options.method, - success: function(response, status) { + success: function(response) { handleFormSuccess(response, options); }, - error: function(xhr, status, thrownError) { + error: function(xhr) { switch (xhr.status) { - case 400: // Bad request - handleFormErrors(xhr.responseJSON, fields, options); - break; - default: - $(options.modal).modal('hide'); - showApiError(xhr); - break; + case 400: + handleFormErrors(xhr.responseJSON, fields, options); + break; + default: + $(options.modal).modal('hide'); + showApiError(xhr); + break; } } } @@ -675,7 +703,9 @@ function updateFieldValues(fields, options) { var field = fields[name] || null; - if (field == null) { continue; } + if (field == null) { + continue; + } var value = field.value; @@ -683,7 +713,9 @@ function updateFieldValues(fields, options) { value = field.default; } - if (value == null) { continue; } + if (value == null) { + continue; + } updateFieldValue(name, value, field, options); } @@ -694,22 +726,22 @@ function updateFieldValue(name, value, field, options) { var el = $(options.modal).find(`#id_${name}`); switch (field.type) { - case 'boolean': - el.prop('checked', value); - break; - case 'related field': - // Clear? - if (value == null && !field.required) { - el.val(null).trigger('change'); - } - // TODO - Specify an actual value! - break; - case 'file upload': - case 'image upload': - break; - default: - el.val(value); - break; + case 'boolean': + el.prop('checked', value); + break; + case 'related field': + // Clear? + if (value == null && !field.required) { + el.val(null).trigger('change'); + } + // TODO - Specify an actual value! + break; + case 'file upload': + case 'image upload': + break; + default: + el.val(value); + break; } } @@ -734,21 +766,21 @@ function getFormFieldValue(name, field, options) { var value = null; switch (field.type) { - case 'boolean': - value = el.is(":checked"); - break; - case 'date': - case 'datetime': - value = el.val(); + case 'boolean': + value = el.is(':checked'); + break; + case 'date': + case 'datetime': + value = el.val(); - // Ensure empty values are sent as nulls - if (!value || value.length == 0) { - value = null; - } - break; - default: - value = el.val(); - break; + // Ensure empty values are sent as nulls + if (!value || value.length == 0) { + value = null; + } + break; + default: + value = el.val(); + break; } return value; @@ -776,19 +808,19 @@ function handleFormSuccess(response, options) { // Display any messages if (response && response.success) { - showAlertOrCache("alert-success", response.success, cache); + showAlertOrCache('alert-success', response.success, cache); } if (response && response.info) { - showAlertOrCache("alert-info", response.info, cache); + showAlertOrCache('alert-info', response.info, cache); } if (response && response.warning) { - showAlertOrCache("alert-warning", response.warning, cache); + showAlertOrCache('alert-warning', response.warning, cache); } if (response && response.danger) { - showAlertOrCache("alert-danger", response.danger, cache); + showAlertOrCache('alert-danger', response.danger, cache); } if (options.onSuccess) { @@ -872,7 +904,7 @@ function handleFormErrors(errors, fields, options) { var first_error_field = null; - for (field_name in errors) { + for (var field_name in errors) { // Add the 'has-error' class $(options.modal).find(`#div_id_${field_name}`).addClass('has-error'); @@ -886,16 +918,16 @@ function handleFormErrors(errors, fields, options) { } // Add an entry for each returned error message - for (var idx = field_errors.length-1; idx >= 0; idx--) { + for (var ii = field_errors.length-1; ii >= 0; ii--) { - var error_text = field_errors[idx]; + var error_text = field_errors[ii]; - var html = ` - + var error_html = ` + ${error_text} `; - field_dom.append(html); + field_dom.append(error_html); } } @@ -1009,9 +1041,9 @@ function initializeGroups(fields, options) { var group_options = options.groups[group]; if (group_options.collapsed) { - $(modal).find(`#form-panel-content-${group}`).collapse("hide"); + $(modal).find(`#form-panel-content-${group}`).collapse('hide'); } else { - $(modal).find(`#form-panel-content-${group}`).collapse("show"); + $(modal).find(`#form-panel-content-${group}`).collapse('show'); } if (group_options.hidden) { @@ -1052,12 +1084,14 @@ function initializeRelatedFields(fields, options) { if (!field || field.hidden) continue; switch (field.type) { - case 'related field': - initializeRelatedField(field, fields, options); - break; - case 'choice': - initializeChoiceField(field, fields, options); - break; + case 'related field': + initializeRelatedField(field, fields, options); + break; + case 'choice': + initializeChoiceField(field, fields, options); + break; + default: + break; } } } @@ -1096,14 +1130,14 @@ function addSecondaryModal(field, fields, options) { if (secondary.fields instanceof Function) { // Extract form values at time of button press - var data = extractFormData(fields, options) + var data = extractFormData(fields, options); secondary.fields = secondary.fields(data); } // If no onSuccess function is defined, provide a default one if (!secondary.onSuccess) { - secondary.onSuccess = function(data, opts) { + secondary.onSuccess = function(data) { // Force refresh from the API, to get full detail inventreeGet(`${url}${data.pk}/`, {}, { @@ -1169,6 +1203,8 @@ function initializeRelatedField(field, fields, options) { cache: true, data: function(params) { + var offset = 0; + if (!params.page) { offset = 0; } else { @@ -1222,7 +1258,7 @@ function initializeRelatedField(field, fields, options) { return results; }, }, - templateResult: function(item, container) { + templateResult: function(item) { // Extract 'instance' data passed through from an initial value // Or, use the raw 'item' data as a backup @@ -1247,7 +1283,7 @@ function initializeRelatedField(field, fields, options) { return `${name} - ${item.id}`; } }, - templateSelection: function(item, container) { + templateSelection: function(item) { // Extract 'instance' data passed through from an initial value // Or, use the raw 'item' data as a backup @@ -1259,7 +1295,6 @@ function initializeRelatedField(field, fields, options) { if (!data.pk) { return field.placeholder || ''; - return $(searching()); } // Custom formatting for selected item @@ -1362,41 +1397,41 @@ function renderModelData(name, model, data, parameters, options) { // Find a custom renderer switch (model) { - case 'company': - renderer = renderCompany; - break; - case 'stockitem': - renderer = renderStockItem; - break; - case 'stocklocation': - renderer = renderStockLocation; - break; - case 'part': - renderer = renderPart; - break; - case 'partcategory': - renderer = renderPartCategory; - break; - case 'partparametertemplate': - renderer = renderPartParameterTemplate; - break; - case 'manufacturerpart': - renderer = renderManufacturerPart; - break; - case 'supplierpart': - renderer = renderSupplierPart; - break; - case 'build': - renderer = renderBuild; - break; - case 'owner': - renderer = renderOwner; - break; - case 'user': - renderer = renderUser; - break; - default: - break; + case 'company': + renderer = renderCompany; + break; + case 'stockitem': + renderer = renderStockItem; + break; + case 'stocklocation': + renderer = renderStockLocation; + break; + case 'part': + renderer = renderPart; + break; + case 'partcategory': + renderer = renderPartCategory; + break; + case 'partparametertemplate': + renderer = renderPartParameterTemplate; + break; + case 'manufacturerpart': + renderer = renderManufacturerPart; + break; + case 'supplierpart': + renderer = renderSupplierPart; + break; + case 'build': + renderer = renderBuild; + break; + case 'owner': + renderer = renderOwner; + break; + case 'user': + renderer = renderUser; + break; + default: + break; } if (renderer != null) { @@ -1517,18 +1552,18 @@ function constructField(name, parameters, options) { // Some fields can have 'clear' inputs associated with them if (!parameters.required && !parameters.read_only) { switch (parameters.type) { - case 'string': - case 'url': - case 'email': - case 'integer': - case 'float': - case 'decimal': - case 'related field': - case 'date': - extra = true; - break; - default: - break; + case 'string': + case 'url': + case 'email': + case 'integer': + case 'float': + case 'decimal': + case 'related field': + case 'date': + extra = true; + break; + default: + break; } } @@ -1551,7 +1586,7 @@ function constructField(name, parameters, options) { `; } - html += ``; // input-group + html += ``; // input-group } if (parameters.help_text) { @@ -1562,8 +1597,8 @@ function constructField(name, parameters, options) { html += `
    `; - html += ``; // controls - html += ``; // form-group + html += ``; // controls + html += ``; // form-group if (parameters.after) { html += parameters.after; @@ -1621,39 +1656,39 @@ function constructInput(name, parameters, options) { var func = null; switch (parameters.type) { - case 'boolean': - func = constructCheckboxInput; - break; - case 'string': - case 'url': - case 'email': - func = constructTextInput; - break; - case 'integer': - case 'float': - case 'decimal': - func = constructNumberInput; - break; - case 'choice': - func = constructChoiceInput; - break; - case 'related field': - func = constructRelatedFieldInput; - break; - case 'image upload': - case 'file upload': - func = constructFileUploadInput; - break; - case 'date': - func = constructDateInput; - break; - case 'candy': - func = constructCandyInput; - break; - default: - // Unsupported field type! - break; - } + case 'boolean': + func = constructCheckboxInput; + break; + case 'string': + case 'url': + case 'email': + func = constructTextInput; + break; + case 'integer': + case 'float': + case 'decimal': + func = constructNumberInput; + break; + case 'choice': + func = constructChoiceInput; + break; + case 'related field': + func = constructRelatedFieldInput; + break; + case 'image upload': + case 'file upload': + func = constructFileUploadInput; + break; + case 'date': + func = constructDateInput; + break; + case 'candy': + func = constructCandyInput; + break; + default: + // Unsupported field type! + break; + } if (func != null) { html = func(name, parameters, options); @@ -1739,7 +1774,7 @@ function constructInputOptions(name, classes, type, parameters) { // Construct a "hidden" input -function constructHiddenInput(name, parameters, options) { +function constructHiddenInput(name, parameters) { return constructInputOptions( name, @@ -1751,7 +1786,7 @@ function constructHiddenInput(name, parameters, options) { // Construct a "checkbox" input -function constructCheckboxInput(name, parameters, options) { +function constructCheckboxInput(name, parameters) { return constructInputOptions( name, @@ -1763,24 +1798,24 @@ function constructCheckboxInput(name, parameters, options) { // Construct a "text" input -function constructTextInput(name, parameters, options) { +function constructTextInput(name, parameters) { var classes = ''; var type = ''; switch (parameters.type) { - default: - classes = 'textinput textInput form-control'; - type = 'text'; - break; - case 'url': - classes = 'urlinput form-control'; - type = 'url'; - break; - case 'email': - classes = 'emailinput form-control'; - type = 'email'; - break; + default: + classes = 'textinput textInput form-control'; + type = 'text'; + break; + case 'url': + classes = 'urlinput form-control'; + type = 'url'; + break; + case 'email': + classes = 'emailinput form-control'; + type = 'email'; + break; } return constructInputOptions( @@ -1793,7 +1828,7 @@ function constructTextInput(name, parameters, options) { // Construct a "number" field -function constructNumberInput(name, parameters, options) { +function constructNumberInput(name, parameters) { return constructInputOptions( name, @@ -1805,7 +1840,7 @@ function constructNumberInput(name, parameters, options) { // Construct a "choice" input -function constructChoiceInput(name, parameters, options) { +function constructChoiceInput(name, parameters) { var html = ``; @@ -1851,7 +1886,7 @@ function constructRelatedFieldInput(name, parameters, options) { /* * Construct a field for file upload */ -function constructFileUploadInput(name, parameters, options) { +function constructFileUploadInput(name, parameters) { var cls = 'clearablefileinput'; @@ -1871,7 +1906,7 @@ function constructFileUploadInput(name, parameters, options) { /* * Construct a field for a date input */ -function constructDateInput(name, parameters, options) { +function constructDateInput(name, parameters) { return constructInputOptions( name, @@ -1886,7 +1921,7 @@ function constructDateInput(name, parameters, options) { * Construct a "candy" field input * No actual field data! */ -function constructCandyInput(name, parameters, options) { +function constructCandyInput(name, parameters) { return parameters.html; @@ -1901,7 +1936,7 @@ function constructCandyInput(name, parameters, options) { * - parameters: Field parameters returned by the OPTIONS method * */ -function constructHelpText(name, parameters, options) { +function constructHelpText(name, parameters) { var style = ''; @@ -1912,4 +1947,4 @@ function constructHelpText(name, parameters, options) { var html = `
    ${parameters.help_text}
    `; return html; -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/helpers.js b/InvenTree/templates/js/translated/helpers.js new file mode 100644 index 0000000000..008c3efaca --- /dev/null +++ b/InvenTree/templates/js/translated/helpers.js @@ -0,0 +1,187 @@ +{% load i18n %} + +/* exported + blankImage, + deleteButton, + editButton, + imageHoverIcon, + makeIconBadge, + makeIconButton, + makeProgressBar, + renderLink, + select2Thumbnail, + yesNoLabel, +*/ + +function yesNoLabel(value) { + if (value) { + return `{% trans "YES" %}`; + } else { + return `{% trans "NO" %}`; + } +} + + +function editButton(url, text='{% trans "Edit" %}') { + return ``; +} + + +function deleteButton(url, text='{% trans "Delete" %}') { + return ``; +} + + +function blankImage() { + return `/static/img/blank_image.png`; +} + +/* Render a small thumbnail icon for an image. + * On mouseover, display a full-size version of the image + */ +function imageHoverIcon(url) { + + if (!url) { + url = blankImage(); + } + + var html = ` + + + + + `; + + return html; +} + + +// Render a select2 thumbnail image +function select2Thumbnail(image) { + if (!image) { + image = blankImage(); + } + + return ``; +} + + +function makeIconBadge(icon, title) { + // Construct an 'icon badge' which floats to the right of an object + + var html = ``; + + return html; +} + + +function makeIconButton(icon, cls, pk, title, options={}) { + // Construct an 'icon button' using the fontawesome set + + var classes = `btn btn-default btn-glyph ${cls}`; + + var id = `${cls}-${pk}`; + + var html = ''; + + var extraProps = ''; + + if (options.disabled) { + extraProps += `disabled='true' `; + } + + html += ``; + + return html; +} + + +/* + * Render a progessbar! + * + * @param value is the current value of the progress bar + * @param maximum is the maximum value of the progress bar + */ +function makeProgressBar(value, maximum, opts={}) { + + var options = opts || {}; + + value = parseFloat(value); + + var percent = 100; + + // Prevent div-by-zero or null value + if (maximum && maximum > 0) { + maximum = parseFloat(maximum); + percent = parseInt(value / maximum * 100); + } + + if (percent > 100) { + percent = 100; + } + + var extraclass = ''; + + if (value > maximum) { + extraclass='progress-bar-over'; + } else if (value < maximum) { + extraclass = 'progress-bar-under'; + } + + var style = options.style || ''; + + var text = ''; + + if (style == 'percent') { + // Display e.g. "50%" + + text = `${percent}%`; + } else if (style == 'max') { + // Display just the maximum value + text = `${maximum}`; + } else if (style == 'value') { + // Display just the current value + text = `${value}`; + } else if (style == 'blank') { + // No display! + text = ''; + } else { + /* Default style + * Display e.g. "5 / 10" + */ + + text = `${value} / ${maximum}`; + } + + var id = options.id || 'progress-bar'; + + return ` +
    +
    +
    ${text}
    +
    + `; +} + + +function renderLink(text, url, options={}) { + if (url === null || url === undefined || url === '') { + return text; + } + + var max_length = options.max_length || -1; + + // Shorten the displayed length if required + if ((max_length > 0) && (text.length > max_length)) { + var slice_length = (max_length - 3) / 2; + + var text_start = text.slice(0, slice_length); + var text_end = text.slice(-slice_length); + + text = `${text_start}...${text_end}`; + } + + return `${text}`; +} diff --git a/InvenTree/templates/js/translated/label.js b/InvenTree/templates/js/translated/label.js index dc9e8fa935..1c843917e6 100644 --- a/InvenTree/templates/js/translated/label.js +++ b/InvenTree/templates/js/translated/label.js @@ -1,6 +1,25 @@ {% load i18n %} -function printStockItemLabels(items, options={}) { +/* globals + attachSelect, + closeModal, + inventreeGet, + makeOptionsList, + modalEnable, + modalSetContent, + modalSetTitle, + modalSubmit, + openModal, + showAlertDialog, +*/ + +/* exported + printPartLabels, + printStockItemLabels, + printStockLocationLabels, +*/ + +function printStockItemLabels(items) { /** * Print stock item labels for the given stock items */ @@ -54,7 +73,7 @@ function printStockItemLabels(items, options={}) { ); } -function printStockLocationLabels(locations, options={}) { +function printStockLocationLabels(locations) { if (locations.length == 0) { showAlertDialog( @@ -101,11 +120,11 @@ function printStockLocationLabels(locations, options={}) { ); } } - ) + ); } -function printPartLabels(parts, options={}) { +function printPartLabels(parts) { /** * Print labels for the provided parts */ diff --git a/InvenTree/templates/js/translated/modals.js b/InvenTree/templates/js/translated/modals.js index 4bcc31fffa..5195c67b46 100644 --- a/InvenTree/templates/js/translated/modals.js +++ b/InvenTree/templates/js/translated/modals.js @@ -1,5 +1,22 @@ {% load i18n %} +/* globals + inventreeGet, + showAlertOrCache, +*/ + +/* exported + attachSecondaryModal, + clearField, + clearFieldOptions, + closeModal, + enableField, + getFieldValue, + reloadFieldOptions, + showModalImage, + removeRowFromModalForm, + showQuestionDialog, +*/ /* * Create and display a new modal dialog @@ -77,7 +94,7 @@ function createNewModal(options={}) { }); // Automatically remove the modal when it is deleted! - $(modal_name).on('hidden.bs.modal', function(e) { + $(modal_name).on('hidden.bs.modal', function() { $(modal_name).remove(); }); @@ -86,7 +103,7 @@ function createNewModal(options={}) { if (event.keyCode == 13) { event.preventDefault(); // Simulate a click on the 'Submit' button - $(modal_name).find("#modal-form-submit").click(); + $(modal_name).find('#modal-form-submit').click(); return false; } @@ -253,8 +270,8 @@ function reloadFieldOptions(fieldName, options) { // Update the target field with the new options setFieldOptions(fieldName, opts); }, - error: function(response) { - console.log("Error GETting field options"); + error: function() { + console.log('Error GETting field options'); } }); } @@ -273,7 +290,7 @@ function enableField(fieldName, enabled, options={}) { var field = getFieldByName(modal, fieldName); - field.prop("disabled", !enabled); + field.prop('disabled', !enabled); } function clearField(fieldName, options={}) { @@ -344,7 +361,7 @@ function attachToggle(modal) { * and also larger toggle style buttons are easier to press! */ - $(modal).find("input[type='checkbox']").each(function(x) { + $(modal).find(`input[type='checkbox']`).each(function() { $(this).bootstrapToggle({ size: 'small', onstyle: 'success', @@ -359,7 +376,7 @@ function attachSelect(modal) { * Provides search filtering for dropdown items */ - $(modal + ' .select').select2({ + $(modal + ' .select').select2({ dropdownParent: $(modal), // dropdownAutoWidth parameter is required to work properly with modal forms dropdownAutoWidth: false, @@ -377,7 +394,7 @@ function loadingMessageContent() { */ // TODO - This can be made a lot better - return " {% trans 'Waiting for server...' %}"; + return ` {% trans 'Waiting for server...' %}`; } @@ -392,36 +409,36 @@ function afterForm(response, options) { * - Reload the page */ - // Should we show alerts immediately or cache them? + // Should we show alerts immediately or cache them? var cache = (options.follow && response.url) || options.redirect || options.reload; // Display any messages if (response.success) { - showAlertOrCache("alert-success", response.success, cache); + showAlertOrCache('alert-success', response.success, cache); } + if (response.info) { - showAlertOrCache("alert-info", response.info, cache); + showAlertOrCache('alert-info', response.info, cache); } + if (response.warning) { - showAlertOrCache("alert-warning", response.warning, cache); + showAlertOrCache('alert-warning', response.warning, cache); } + if (response.danger) { - showAlertOrCache("alert-danger", response.danger, cache); + showAlertOrCache('alert-danger', response.danger, cache); } // Was a callback provided? if (options.success) { options.success(response); - } - else if (options.follow && response.url) { + } else if (options.follow && response.url) { window.location.href = response.url; - } - else if (options.redirect) { + } else if (options.redirect) { window.location.href = options.redirect; - } - else if (options.reload) { + } else if (options.reload) { location.reload(); } } @@ -554,7 +571,7 @@ function renderErrorMessage(xhr) { } -function showAlertDialog(title, content, options={}) { +function showAlertDialog(title, content) { /* Display a modal dialog message box. * * title - Title text @@ -595,7 +612,7 @@ function showQuestionDialog(title, content, options={}) { modalSetContent(modal, content); - $(modal).on('click', "#modal-form-submit", function() { + $(modal).on('click', '#modal-form-submit', function() { $(modal).modal('hide'); if (options.accept) { @@ -636,7 +653,7 @@ function openModal(options) { event.preventDefault(); // Simulate a click on the 'Submit' button - $(modal).find("#modal-form-submit").click(); + $(modal).find('#modal-form-submit').click(); return false; } @@ -698,17 +715,17 @@ function insertNewItemButton(modal, options) { * Inserts a button at the end of this lael element. */ - var html = ""; + var html = ``; - html += "
    " + options.label + "
    "; + html += ` id='btn-new-${options.field}'>${options.label}`; - html += "
    "; + html += '
    '; $(modal).find('label[for="id_'+ options.field + '"]').append(html); } @@ -733,7 +750,7 @@ function attachSecondaryModal(modal, options) { var data = options.data || {}; // Add a callback to the button - $(modal).find("#btn-new-" + options.field).on('click', function() { + $(modal).find('#btn-new-' + options.field).on('click', function() { // Launch the secondary modal launchModalForm( @@ -762,24 +779,26 @@ function attachSecondaryModal(modal, options) { } +// eslint-disable-next-line no-unused-vars function attachSecondaries(modal, secondaries) { /* Attach a provided list of secondary modals */ // 2021-07-18 - Secondary modals will be disabled for now, until they are re-implemented in the "API forms" architecture - return; - for (var i = 0; i < secondaries.length; i++) { - attachSecondaryModal(modal, secondaries[i]); - } + // for (var i = 0; i < secondaries.length; i++) { + // attachSecondaryModal(modal, secondaries[i]); + // } } function insertActionButton(modal, options) { - /* Insert a custom submition button */ + /* Insert a custom submission button */ - var html = ""; - html += ""; - html += ""; + var html = ` + + + `; $(modal).find('#modal-footer-buttons').append(html); } @@ -802,8 +821,8 @@ function attachFieldCallback(modal, callback) { * - action: A function to perform */ - // Find the field input in the form - var field = getFieldByName(modal, callback.field); + // Find the field input in the form + var field = getFieldByName(modal, callback.field); field.change(function() { @@ -838,8 +857,6 @@ function handleModalForm(url, options) { var form = $(modal).find('.js-modal-form'); - var _form = $(modal).find(".js-modal-form"); - form.ajaxForm({ url: url, dataType: 'json', @@ -860,7 +877,7 @@ function handleModalForm(url, options) { modalEnable(modal, false); }, // POST was successful - success: function(response, status, xhr, f) { + success: function(response) { // Re-enable the modal modalEnable(modal, true); if ('form_valid' in response) { @@ -868,9 +885,8 @@ function handleModalForm(url, options) { if (response.form_valid) { $(modal).modal('hide'); afterForm(response, options); - } - // Form was returned, invalid! - else { + } else { + // Form was returned, invalid! // Disable error message with option or response if (!options.hideErrorMessage && !response.hideErrorMessage) { @@ -901,26 +917,24 @@ function handleModalForm(url, options) { if (response.buttons) { attachButtons(modal, response.buttons); } - } - else { + } else { $(modal).modal('hide'); showAlertDialog('{% trans "Invalid response from server" %}', '{% trans "Form data missing from server response" %}'); } } - } - else { + } else { $(modal).modal('hide'); afterForm(response, options); } }, - error: function(xhr, ajaxOptions, thrownError) { + error: function(xhr) { // There was an error submitting form data via POST $(modal).modal('hide'); showAlertDialog('{% trans "Error posting form data" %}', renderErrorMessage(xhr)); }, - complete: function(xhr) { - //TODO + complete: function() { + // TODO } }); }); @@ -960,11 +974,11 @@ function launchModalForm(url, options = {}) { $(modal).find('#modal-footer-buttons').html(''); // Form the ajax request to retrieve the django form data - ajax_data = { + var ajax_data = { url: url, type: 'get', dataType: 'json', - beforeSend: function () { + beforeSend: function() { openModal({ modal: modal, submit_text: submit_text, @@ -1017,7 +1031,7 @@ function launchModalForm(url, options = {}) { showAlertDialog('{% trans "Invalid server response" %}', '{% trans "JSON response missing form data" %}'); } }, - error: function (xhr, ajaxOptions, thrownError) { + error: function(xhr) { $(modal).modal('hide'); @@ -1056,8 +1070,8 @@ function launchModalForm(url, options = {}) { showAlertDialog('{% trans "Error requesting form data" %}', renderErrorMessage(xhr)); } - console.log("Modal form error: " + xhr.status); - console.log("Message: " + xhr.responseText); + console.log('Modal form error: ' + xhr.status); + console.log('Message: ' + xhr.responseText); } }; @@ -1106,4 +1120,4 @@ function showModalImage(image_url) { modal.click(function() { hideModalImage(); }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/model_renderers.js b/InvenTree/templates/js/translated/model_renderers.js index 12e00cab2c..389d5a650f 100644 --- a/InvenTree/templates/js/translated/model_renderers.js +++ b/InvenTree/templates/js/translated/model_renderers.js @@ -1,18 +1,19 @@ {% load i18n %} +/* globals + blankImage, + select2Thumbnail +*/ -function blankImage() { - return `/static/img/blank_image.png`; -} - -// Render a select2 thumbnail image -function select2Thumbnail(image) { - if (!image) { - image = blankImage(); - } - - return ``; -} +/* exported + renderBuild, + renderCompany, + renderManufacturerPart, + renderOwner, + renderPartCategory, + renderStockLocation, + renderSupplierPart, +*/ /* @@ -29,6 +30,7 @@ function select2Thumbnail(image) { // Renderer for "Company" model +// eslint-disable-next-line no-unused-vars function renderCompany(name, data, parameters, options) { var html = select2Thumbnail(data.image); @@ -42,6 +44,7 @@ function renderCompany(name, data, parameters, options) { // Renderer for "StockItem" model +// eslint-disable-next-line no-unused-vars function renderStockItem(name, data, parameters, options) { var image = data.part_detail.thumbnail || data.part_detail.image || blankImage(); @@ -65,6 +68,7 @@ function renderStockItem(name, data, parameters, options) { // Renderer for "StockLocation" model +// eslint-disable-next-line no-unused-vars function renderStockLocation(name, data, parameters, options) { var level = '- '.repeat(data.level); @@ -80,7 +84,7 @@ function renderStockLocation(name, data, parameters, options) { return html; } - +// eslint-disable-next-line no-unused-vars function renderBuild(name, data, parameters, options) { var image = null; @@ -101,6 +105,7 @@ function renderBuild(name, data, parameters, options) { // Renderer for "Part" model +// eslint-disable-next-line no-unused-vars function renderPart(name, data, parameters, options) { var html = select2Thumbnail(data.image); @@ -117,6 +122,7 @@ function renderPart(name, data, parameters, options) { } // Renderer for "User" model +// eslint-disable-next-line no-unused-vars function renderUser(name, data, parameters, options) { var html = `${data.username}`; @@ -130,19 +136,20 @@ function renderUser(name, data, parameters, options) { // Renderer for "Owner" model +// eslint-disable-next-line no-unused-vars function renderOwner(name, data, parameters, options) { var html = `${data.name}`; switch (data.label) { - case 'user': - html += ``; - break; - case 'group': - html += ``; - break; - default: - break; + case 'user': + html += ``; + break; + case 'group': + html += ``; + break; + default: + break; } return html; @@ -150,6 +157,7 @@ function renderOwner(name, data, parameters, options) { // Renderer for "PartCategory" model +// eslint-disable-next-line no-unused-vars function renderPartCategory(name, data, parameters, options) { var level = '- '.repeat(data.level); @@ -165,7 +173,7 @@ function renderPartCategory(name, data, parameters, options) { return html; } - +// eslint-disable-next-line no-unused-vars function renderPartParameterTemplate(name, data, parameters, options) { var html = `${data.name} - [${data.units}]`; @@ -175,6 +183,7 @@ function renderPartParameterTemplate(name, data, parameters, options) { // Renderer for "ManufacturerPart" model +// eslint-disable-next-line no-unused-vars function renderManufacturerPart(name, data, parameters, options) { var manufacturer_image = null; @@ -203,6 +212,7 @@ function renderManufacturerPart(name, data, parameters, options) { // Renderer for "SupplierPart" model +// eslint-disable-next-line no-unused-vars function renderSupplierPart(name, data, parameters, options) { var supplier_image = null; diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js index c6dd773373..7ebe000f64 100644 --- a/InvenTree/templates/js/translated/order.js +++ b/InvenTree/templates/js/translated/order.js @@ -1,6 +1,33 @@ {% load i18n %} {% load inventree_extras %} +/* globals + companyFormFields, + constructForm, + createSupplierPart, + global_settings, + imageHoverIcon, + inventreeGet, + launchModalForm, + loadTableFilters, + makeIconBadge, + purchaseOrderStatusDisplay, + renderLink, + salesOrderStatusDisplay, + setupFilterList, +*/ + +/* exported + createSalesOrder, + editPurchaseOrderLineItem, + loadPurchaseOrderTable, + loadSalesOrderAllocationTable, + loadSalesOrderTable, + newPurchaseOrderFromOrderWizard, + newSupplierPartFromOrderWizard, + removeOrderRowFromOrderWizard, + removePurchaseOrderLineItem, +*/ // Create a new SalesOrder function createSalesOrder(options={}) { @@ -15,7 +42,7 @@ function createSalesOrder(options={}) { value: options.customer, secondary: { title: '{% trans "Add Customer" %}', - fields: function(data) { + fields: function() { var fields = companyFormFields(); fields.is_customer.value = true; @@ -56,7 +83,7 @@ function createPurchaseOrder(options={}) { value: options.supplier, secondary: { title: '{% trans "Add Supplier" %}', - fields: function(data) { + fields: function() { var fields = companyFormFields(); fields.is_supplier.value = true; @@ -143,7 +170,7 @@ function newSupplierPartFromOrderWizard(e) { if (response.supplier_detail) { text += response.supplier_detail.name; - text += " | "; + text += ' | '; } text += response.SKU; @@ -153,8 +180,7 @@ function newSupplierPartFromOrderWizard(e) { $('#modal-form').find(dropdown).append(option).trigger('change'); } } - ) - + ); } }); } @@ -203,7 +229,7 @@ function newPurchaseOrderFromOrderWizard(e) { $('#modal-form').find(dropdown).append(option).trigger('change'); } } - ) + ); } }); } @@ -248,7 +274,7 @@ function loadPurchaseOrderTable(table, options) { options.params['supplier_detail'] = true; - var filters = loadTableFilters("purchaseorder"); + var filters = loadTableFilters('purchaseorder'); for (var key in options.params) { filters[key] = options.params[key]; @@ -256,7 +282,7 @@ function loadPurchaseOrderTable(table, options) { options.url = options.url || '{% url "api-po-list" %}'; - setupFilterList("purchaseorder", $(table)); + setupFilterList('purchaseorder', $(table)); $(table).inventreeTable({ url: options.url, @@ -265,7 +291,9 @@ function loadPurchaseOrderTable(table, options) { groupBy: false, sidePagination: 'server', original: options.params, - formatNoMatches: function() { return '{% trans "No purchase orders found" %}'; }, + formatNoMatches: function() { + return '{% trans "No purchase orders found" %}'; + }, columns: [ { title: '', @@ -278,7 +306,7 @@ function loadPurchaseOrderTable(table, options) { title: '{% trans "Purchase Order" %}', sortable: true, switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX; @@ -300,7 +328,7 @@ function loadPurchaseOrderTable(table, options) { title: '{% trans "Supplier" %}', sortable: true, sortName: 'supplier__name', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return imageHoverIcon(row.supplier_detail.image) + renderLink(row.supplier_detail.name, `/company/${row.supplier}/purchase-orders/`); } }, @@ -316,7 +344,7 @@ function loadPurchaseOrderTable(table, options) { field: 'status', title: '{% trans "Status" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value, row) { return purchaseOrderStatusDisplay(row.status, row.status_text); } }, @@ -344,7 +372,7 @@ function loadSalesOrderTable(table, options) { options.params = options.params || {}; options.params['customer_detail'] = true; - var filters = loadTableFilters("salesorder"); + var filters = loadTableFilters('salesorder'); for (var key in options.params) { filters[key] = options.params[key]; @@ -352,7 +380,7 @@ function loadSalesOrderTable(table, options) { options.url = options.url || '{% url "api-so-list" %}'; - setupFilterList("salesorder", $(table)); + setupFilterList('salesorder', $(table)); $(table).inventreeTable({ url: options.url, @@ -361,7 +389,9 @@ function loadSalesOrderTable(table, options) { groupBy: false, sidePagination: 'server', original: options.params, - formatNoMatches: function() { return '{% trans "No sales orders found" %}'; }, + formatNoMatches: function() { + return '{% trans "No sales orders found" %}'; + }, columns: [ { title: '', @@ -373,7 +403,7 @@ function loadSalesOrderTable(table, options) { sortable: true, field: 'reference', title: '{% trans "Sales Order" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var prefix = global_settings.SALESORDER_REFERENCE_PREFIX; @@ -395,7 +425,7 @@ function loadSalesOrderTable(table, options) { sortName: 'customer__name', field: 'customer_detail', title: '{% trans "Customer" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (!row.customer_detail) { return '{% trans "Invalid Customer" %}'; @@ -418,7 +448,7 @@ function loadSalesOrderTable(table, options) { sortable: true, field: 'status', title: '{% trans "Status" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return salesOrderStatusDisplay(row.status, row.status_text); } }, @@ -459,13 +489,13 @@ function loadSalesOrderAllocationTable(table, options={}) { options.params['item_detail'] = true; options.params['order_detail'] = true; - var filters = loadTableFilters("salesorderallocation"); + var filters = loadTableFilters('salesorderallocation'); for (var key in options.params) { filters[key] = options.params[key]; } - setupFilterList("salesorderallocation", $(table)); + setupFilterList('salesorderallocation', $(table)); $(table).inventreeTable({ url: '{% url "api-so-allocation-list" %}', @@ -475,7 +505,9 @@ function loadSalesOrderAllocationTable(table, options={}) { search: false, paginationVAlign: 'bottom', original: options.params, - formatNoMatches: function() { return '{% trans "No sales order allocations found" %}'; }, + formatNoMatches: function() { + return '{% trans "No sales order allocations found" %}'; + }, columns: [ { field: 'pk', @@ -486,7 +518,6 @@ function loadSalesOrderAllocationTable(table, options={}) { field: 'order', switchable: false, title: '{% trans "Order" %}', - switchable: false, formatter: function(value, row) { var prefix = global_settings.SALESORDER_REFERENCE_PREFIX; @@ -530,4 +561,4 @@ function loadSalesOrderAllocationTable(table, options={}) { } ] }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/part.js b/InvenTree/templates/js/translated/part.js index 052a33ec5c..1ccf8157b6 100644 --- a/InvenTree/templates/js/translated/part.js +++ b/InvenTree/templates/js/translated/part.js @@ -1,20 +1,48 @@ {% load i18n %} {% load inventree_extras %} +/* globals + Chart, + constructForm, + global_settings, + imageHoverIcon, + inventreeGet, + inventreePut, + launchModalForm, + linkButtonsToSelection, + loadTableFilters, + makeIconBadge, + makeIconButton, + printPartLabels, + renderLink, + setFormGroupVisibility, + setupFilterList, + yesNoLabel, +*/ + +/* exported + duplicatePart, + editCategory, + editPart, + initPriceBreakSet, + loadBomChart, + loadParametricPartTable, + loadPartCategoryTable, + loadPartParameterTable, + loadPartTable, + loadPartTestTemplateTable, + loadPartVariantTable, + loadSellPricingChart, + loadSimplePartTable, + loadStockPricingChart, + toggleStar, +*/ + /* Part API functions * Requires api.js to be loaded first */ -function yesNoLabel(value) { - if (value) { - return `{% trans "YES" %}`; - } else { - return `{% trans "NO" %}`; - } -} - - -function partGroups(options={}) { +function partGroups() { return { attributes: { @@ -34,10 +62,10 @@ function partGroups(options={}) { collapsible: true, hidden: !global_settings.PART_PURCHASEABLE, } - } - + }; } + // Construct fieldset for part forms function partFields(options={}) { @@ -45,7 +73,7 @@ function partFields(options={}) { category: { secondary: { title: '{% trans "Add Part Category" %}', - fields: function(data) { + fields: function() { var fields = categoryFields(); return fields; @@ -115,14 +143,14 @@ function partFields(options={}) { // Pop expiry field if (!global_settings.STOCK_ENABLE_EXPIRY) { - delete fields["default_expiry"]; + delete fields['default_expiry']; } // Additional fields when "creating" a new part if (options.create) { // No supplier parts available yet - delete fields["default_supplier"]; + delete fields['default_supplier']; if (global_settings.PART_CREATE_INITIAL) { @@ -264,7 +292,7 @@ function categoryFields() { // Edit a PartCategory via the API -function editCategory(pk, options={}) { +function editCategory(pk) { var url = `/api/part/category/${pk}/`; @@ -279,7 +307,7 @@ function editCategory(pk, options={}) { } -function editPart(pk, options={}) { +function editPart(pk) { var url = `/api/part/${pk}/`; @@ -291,7 +319,7 @@ function editPart(pk, options={}) { constructForm(url, { fields: fields, - groups: partGroups(), + groups: groups, title: '{% trans "Edit Part" %}', reload: true, }); @@ -370,7 +398,7 @@ function toggleStar(options) { } -function makePartIcons(part, options={}) { +function makePartIcons(part) { /* Render a set of icons for the given part. */ @@ -397,7 +425,7 @@ function makePartIcons(part, options={}) { } if (part.salable) { - html += makeIconBadge('fa-dollar-sign', title='{% trans "Salable part" %}'); + html += makeIconBadge('fa-dollar-sign', '{% trans "Salable part" %}'); } if (!part.active) { @@ -418,13 +446,13 @@ function loadPartVariantTable(table, partId, options={}) { params.ancestor = partId; // Load filters - var filters = loadTableFilters("variants"); + var filters = loadTableFilters('variants'); for (var key in params) { filters[key] = params[key]; } - setupFilterList("variants", $(table)); + setupFilterList('variants', $(table)); var cols = [ { @@ -437,7 +465,7 @@ function loadPartVariantTable(table, partId, options={}) { field: 'name', title: '{% trans "Name" %}', switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var html = ''; var name = ''; @@ -506,12 +534,14 @@ function loadPartVariantTable(table, partId, options={}) { ]; table.inventreeTable({ - url: "{% url 'api-part-list' %}", + url: '{% url "api-part-list" %}', name: 'partvariants', showColumns: true, original: params, queryParams: filters, - formatNoMatches: function() { return '{% trans "No variants found" %}'; }, + formatNoMatches: function() { + return '{% trans "No variants found" %}'; + }, columns: cols, treeEnable: true, rootParentId: partId, @@ -545,7 +575,7 @@ function loadPartParameterTable(table, url, options) { var params = options.params || {}; // Load filters - var filters = loadTableFilters("part-parameters"); + var filters = loadTableFilters('part-parameters'); for (var key in params) { filters[key] = params[key]; @@ -559,7 +589,9 @@ function loadPartParameterTable(table, url, options) { queryParams: filters, name: 'partparameters', groupBy: false, - formatNoMatches: function() { return '{% trans "No parameters found" %}'; }, + formatNoMatches: function() { + return '{% trans "No parameters found" %}'; + }, columns: [ { checkbox: true, @@ -650,19 +682,19 @@ function loadParametricPartTable(table, options={}) { * - table_data: Parameters data */ - var table_headers = options.headers - var table_data = options.data + var table_headers = options.headers; + var table_data = options.data; var columns = []; - for (header of table_headers) { + for (var header of table_headers) { if (header === 'part') { columns.push({ field: header, title: '{% trans "Part" %}', sortable: true, sortName: 'name', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var name = ''; @@ -687,8 +719,6 @@ function loadParametricPartTable(table, options={}) { title: header, sortable: true, filterControl: 'input', - /* TODO: Search icons are not displayed */ - /*clear: 'fa-times icon-red',*/ }); } } @@ -698,7 +728,9 @@ function loadParametricPartTable(table, options={}) { queryParams: table_headers, groupBy: false, name: options.name || 'parametric', - formatNoMatches: function() { return '{% trans "No parts found" %}'; }, + formatNoMatches: function() { + return '{% trans "No parts found" %}'; + }, columns: columns, showColumns: true, data: table_data, @@ -785,15 +817,17 @@ function loadPartTable(table, url, options={}) { var filters = {}; + var col = null; + if (!options.disableFilters) { - filters = loadTableFilters("parts"); + filters = loadTableFilters('parts'); } for (var key in params) { filters[key] = params[key]; } - setupFilterList("parts", $(table), options.filterTarget || null); + setupFilterList('parts', $(table), options.filterTarget || null); var columns = [ { @@ -818,16 +852,18 @@ function loadPartTable(table, url, options={}) { field: 'IPN', title: 'IPN', }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'name', title: '{% trans "Part" %}', switchable: false, - formatter: function(value, row, index, field) { + formatter: function(value, row) { var name = ''; @@ -854,18 +890,20 @@ function loadPartTable(table, url, options={}) { return display; } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); columns.push({ field: 'description', title: '{% trans "Description" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (row.is_template) { - value = '' + value + ''; + value = `${value}`; } return value; @@ -876,60 +914,63 @@ function loadPartTable(table, url, options={}) { sortName: 'category', field: 'category_detail', title: '{% trans "Category" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { if (row.category) { - return renderLink(value.pathstring, "/part/category/" + row.category + "/"); - } - else { + return renderLink(value.pathstring, `/part/category/${row.category}/`); + } else { return '{% trans "No category" %}'; } } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'in_stock', title: '{% trans "Stock" %}', searchable: false, - formatter: function(value, row, index, field) { - var link = "stock"; + formatter: function(value, row) { + var link = 'stock'; if (value) { // There IS stock available for this part // Is stock "low" (below the 'minimum_stock' quantity)? if (row.minimum_stock && row.minimum_stock > value) { - value += "{% trans "Low stock" %}"; + value += `{% trans "Low stock" %}`; } } else if (row.on_order) { // There is no stock available, but stock is on order - value = "0{% trans "On Order" %}: " + row.on_order + ""; - link = "orders"; + value = `0{% trans "On Order" %}: ${row.on_order}`; + link = 'orders'; } else if (row.building) { // There is no stock available, but stock is being built - value = "0{% trans "Building" %}: " + row.building + ""; - link = "builds"; + value = `0{% trans "Building" %}: ${row.building}`; + link = 'builds'; } else { // There is no stock available - value = "0{% trans "No Stock" %}"; + value = `0{% trans "No Stock" %}`; } - return renderLink(value, '/part/' + row.pk + "/" + link + "/"); + return renderLink(value, `/part/${row.pk}/${link}/`); } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); columns.push({ field: 'link', title: '{% trans "Link" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { return renderLink( value, value, { @@ -949,7 +990,9 @@ function loadPartTable(table, url, options={}) { original: params, sidePagination: 'server', pagination: 'true', - formatNoMatches: function() { return '{% trans "No parts found" %}'; }, + formatNoMatches: function() { + return '{% trans "No parts found" %}'; + }, columns: columns, showColumns: true, showCustomView: false, @@ -982,8 +1025,8 @@ function loadPartTable(table, url, options={}) { /* Button callbacks for part table buttons */ - $("#multi-part-order").click(function() { - var selections = $(table).bootstrapTable("getSelections"); + $('#multi-part-order').click(function() { + var selections = $(table).bootstrapTable('getSelections'); var parts = []; @@ -991,15 +1034,15 @@ function loadPartTable(table, url, options={}) { parts.push(item.pk); }); - launchModalForm("/order/purchase-order/order-parts/", { + launchModalForm('/order/purchase-order/order-parts/', { data: { parts: parts, }, }); }); - $("#multi-part-category").click(function() { - var selections = $(table).bootstrapTable("getSelections"); + $('#multi-part-category').click(function() { + var selections = $(table).bootstrapTable('getSelections'); var parts = []; @@ -1007,7 +1050,7 @@ function loadPartTable(table, url, options={}) { parts.push(item.pk); }); - launchModalForm("/part/set-category/", { + launchModalForm('/part/set-category/', { data: { parts: parts, }, @@ -1028,7 +1071,7 @@ function loadPartTable(table, url, options={}) { }); $('#multi-part-export').click(function() { - var selections = $(table).bootstrapTable("getSelections"); + var selections = $(table).bootstrapTable('getSelections'); var parts = ''; @@ -1127,15 +1170,15 @@ function loadPartTestTemplateTable(table, options) { var filterListElement = options.filterList || '#filter-list-parttests'; - var filters = loadTableFilters("parttests"); + var filters = loadTableFilters('parttests'); var original = {}; - for (var key in params) { - original[key] = params[key]; + for (var k in params) { + original[k] = params[k]; } - setupFilterList("parttests", table, filterListElement); + setupFilterList('parttests', table, filterListElement); // Override the default values, or add new ones for (var key in params) { @@ -1147,7 +1190,7 @@ function loadPartTestTemplateTable(table, options) { formatNoMatches: function() { return '{% trans "No test templates matching query" %}'; }, - url: "{% url 'api-part-test-template-list' %}", + url: '{% url "api-part-test-template-list" %}', queryParams: filters, name: 'testtemplate', original: original, @@ -1168,7 +1211,7 @@ function loadPartTestTemplateTable(table, options) { }, { field: 'required', - title: "{% trans 'Required' %}", + title: '{% trans "Required" %}', sortable: true, formatter: function(value) { return yesNoLabel(value); @@ -1235,28 +1278,29 @@ function loadPriceBreakTable(table, options) { onLoadSuccess: function(tableData) { if (linkedGraph) { // sort array - tableData = tableData.sort((a,b)=>a.quantity-b.quantity); + tableData = tableData.sort((a, b) => (a.quantity - b.quantity)); // split up for graph definition - var graphLabels = Array.from(tableData, x => x.quantity); - var graphData = Array.from(tableData, x => x.price); + var graphLabels = Array.from(tableData, (x) => (x.quantity)); + var graphData = Array.from(tableData, (x) => (x.price)); // destroy chart if exists - if (chart){ + if (chart) { chart.destroy(); } chart = loadLineChart(linkedGraph, { labels: graphLabels, - datasets: [ - { - label: '{% trans "Unit Price" %}', - data: graphData, - backgroundColor: 'rgba(255, 206, 86, 0.2)', - borderColor: 'rgb(255, 206, 86)', - stepped: true, - fill: true, - },] + datasets: [ + { + label: '{% trans "Unit Price" %}', + data: graphData, + backgroundColor: 'rgba(255, 206, 86, 0.2)', + borderColor: 'rgb(255, 206, 86)', + stepped: true, + fill: true, + }, + ], } ); } @@ -1277,10 +1321,10 @@ function loadPriceBreakTable(table, options) { field: 'price', title: '{% trans "Price" %}', sortable: true, - formatter: function(value, row, index) { + formatter: function(value, row) { var html = value; - html += `
    ` + html += `
    `; html += makeIconButton('fa-edit icon-blue', `button-${name}-edit`, row.pk, `{% trans "Edit ${human_name}" %}`); html += makeIconButton('fa-trash-alt icon-red', `button-${name}-delete`, row.pk, `{% trans "Delete ${human_name}" %}`); @@ -1330,8 +1374,8 @@ function initPriceBreakSet(table, options) { } ); - function reloadPriceBreakTable(){ - table.bootstrapTable("refresh"); + function reloadPriceBreakTable() { + table.bootstrapTable('refresh'); } pb_new_btn.click(function() { @@ -1419,12 +1463,26 @@ function loadBomChart(context, data) { options: { responsive: true, maintainAspectRatio: false, - plugins: {legend: {position: 'bottom'}, - scales: {xAxes: [{beginAtZero: true, ticks: {autoSkip: false}}]}} + plugins: { + legend: { + position: 'bottom', + }, + scales: { + xAxes: [ + { + beginAtZero: true, + ticks: { + autoSkip: false, + } + } + ] + } + } } }); } + function loadSellPricingChart(context, data) { return new Chart(context, { type: 'line', @@ -1432,21 +1490,29 @@ function loadSellPricingChart(context, data) { options: { responsive: true, maintainAspectRatio: false, - plugins: {legend: {position: 'bottom'}}, + plugins: { + legend: { + position: 'bottom' + } + }, scales: { y: { type: 'linear', position: 'left', - grid: {display: false}, + grid: { + display: false + }, title: { display: true, - text: '{% trans "Unit Price" %}' + text: '{% trans "Unit Price" %}', } }, y1: { type: 'linear', position: 'right', - grid: {display: false}, + grid: { + display: false + }, titel: { display: true, text: '{% trans "Quantity" %}', diff --git a/InvenTree/templates/js/translated/report.js b/InvenTree/templates/js/translated/report.js index 370978be04..4f887f2275 100644 --- a/InvenTree/templates/js/translated/report.js +++ b/InvenTree/templates/js/translated/report.js @@ -1,5 +1,25 @@ {% load i18n %} +/* globals + attachSelect, + closeModal, + inventreeGet, + openModal, + makeOptionsList, + modalEnable, + modalSetContent, + modalSetTitle, + modalSubmit, + showAlertDialog, +*/ + +/* exported + printBomReports, + printBuildReports, + printPurchaseOrderReports, + printSalesOrderReports, + printTestReports, +*/ function selectReport(reports, items, options={}) { /** @@ -88,7 +108,7 @@ function selectReport(reports, items, options={}) { } -function printTestReports(items, options={}) { +function printTestReports(items) { /** * Print test reports for the provided stock item(s) */ @@ -142,7 +162,7 @@ function printTestReports(items, options={}) { } -function printBuildReports(builds, options={}) { +function printBuildReports(builds) { /** * Print Build report for the provided build(s) */ @@ -188,14 +208,14 @@ function printBuildReports(builds, options={}) { window.location.href = href; } } - ) + ); } } - ) + ); } -function printBomReports(parts, options={}) { +function printBomReports(parts) { /** * Print BOM reports for the provided part(s) */ @@ -245,11 +265,11 @@ function printBomReports(parts, options={}) { ); } } - ) + ); } -function printPurchaseOrderReports(orders, options={}) { +function printPurchaseOrderReports(orders) { /** * Print PO reports for the provided purchase order(s) */ @@ -296,14 +316,14 @@ function printPurchaseOrderReports(orders, options={}) { window.location.href = href; } } - ) + ); } } - ) + ); } -function printSalesOrderReports(orders, options={}) { +function printSalesOrderReports(orders) { /** * Print SO reports for the provided purchase order(s) */ @@ -350,8 +370,8 @@ function printSalesOrderReports(orders, options={}) { window.location.href = href; } } - ) + ); } } - ) + ); } diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index 99c3824cac..e35831624e 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -2,6 +2,63 @@ {% load inventree_extras %} {% load status_codes %} +/* globals + attachSelect, + attachToggle, + blankImage, + enableField, + clearField, + clearFieldOptions, + closeModal, + constructFormBody, + constructNumberInput, + createNewModal, + getFormFieldValue, + global_settings, + handleFormErrors, + imageHoverIcon, + inventreeDelete, + inventreeGet, + inventreePut, + launchModalForm, + linkButtonsToSelection, + loadTableFilters, + makeIconBadge, + makeIconButton, + makeOptionsList, + makePartIcons, + modalEnable, + modalSetContent, + modalSetTitle, + modalSubmit, + moment, + openModal, + printStockItemLabels, + printTestReports, + renderLink, + reloadFieldOptions, + scanItemsIntoLocation, + showAlertDialog, + setFieldValue, + setupFilterList, + showApiError, + stockStatusDisplay, +*/ + +/* exported + createNewStockItem, + exportStock, + loadInstalledInTable, + loadStockLocationTable, + loadStockTable, + loadStockTestResultsTable, + loadStockTrackingTable, + loadTableFilters, + locationFields, + removeStockRow, + stockStatusCodes, +*/ + function locationFields() { return { @@ -23,7 +80,7 @@ function stockStatusCodes() { {% for code in StockStatus.list %} { key: {{ code.key }}, - text: "{{ code.value }}", + text: '{{ code.value }}', }, {% endfor %} ]; @@ -45,11 +102,23 @@ function exportStock(params={}) { type: 'choice', value: 'csv', choices: [ - { value: 'csv', display_name: 'CSV' }, - { value: 'tsv', display_name: 'TSV' }, - { value: 'xls', display_name: 'XLS' }, - { value: 'xlsx', display_name: 'XLSX' }, - ] + { + value: 'csv', + display_name: 'CSV', + }, + { + value: 'tsv', + display_name: 'TSV', + }, + { + value: 'xls', + display_name: 'XLS', + }, + { + value: 'xlsx', + display_name: 'XLSX', + }, + ], }, sublocations: { label: '{% trans "Include Sublocations" %}', @@ -94,34 +163,34 @@ function adjustStock(action, items, options={}) { var allowSerializedStock = false; switch (action) { - case 'move': - formTitle = '{% trans "Transfer Stock" %}'; - actionTitle = '{% trans "Move" %}'; - specifyLocation = true; - allowSerializedStock = true; - url = '{% url "api-stock-transfer" %}'; - break; - case 'count': - formTitle = '{% trans "Count Stock" %}'; - actionTitle = '{% trans "Count" %}'; - url = '{% url "api-stock-count" %}'; - break; - case 'take': - formTitle = '{% trans "Remove Stock" %}'; - actionTitle = '{% trans "Take" %}'; - url = '{% url "api-stock-remove" %}'; - break; - case 'add': - formTitle = '{% trans "Add Stock" %}'; - actionTitle = '{% trans "Add" %}'; - url = '{% url "api-stock-add" %}'; - break; - case 'delete': - formTitle = '{% trans "Delete Stock" %}'; - allowSerializedStock = true; - break; - default: - break; + case 'move': + formTitle = '{% trans "Transfer Stock" %}'; + actionTitle = '{% trans "Move" %}'; + specifyLocation = true; + allowSerializedStock = true; + url = '{% url "api-stock-transfer" %}'; + break; + case 'count': + formTitle = '{% trans "Count Stock" %}'; + actionTitle = '{% trans "Count" %}'; + url = '{% url "api-stock-count" %}'; + break; + case 'take': + formTitle = '{% trans "Remove Stock" %}'; + actionTitle = '{% trans "Take" %}'; + url = '{% url "api-stock-remove" %}'; + break; + case 'add': + formTitle = '{% trans "Add Stock" %}'; + actionTitle = '{% trans "Add" %}'; + url = '{% url "api-stock-add" %}'; + break; + case 'delete': + formTitle = '{% trans "Delete Stock" %}'; + allowSerializedStock = true; + break; + default: + break; } // Generate modal HTML content @@ -157,25 +226,25 @@ function adjustStock(action, items, options={}) { var value = null; switch (action) { - case 'move': - minValue = 0; - maxValue = item.quantity; - value = item.quantity; - break; - case 'add': - minValue = 0; - value = 0; - break; - case 'take': - minValue = 0; - value = 0; - break; - case 'count': - minValue = 0; - value = item.quantity; - break; - default: - break; + case 'move': + minValue = 0; + maxValue = item.quantity; + value = item.quantity; + break; + case 'add': + minValue = 0; + value = 0; + break; + case 'take': + minValue = 0; + value = 0; + break; + case 'count': + minValue = 0; + value = item.quantity; + break; + default: + break; } var image = item.part_detail.thumbnail || item.part_detail.image || blankImage(); @@ -208,8 +277,8 @@ function adjustStock(action, items, options={}) { read_only: readonly, title: readonly ? '{% trans "Quantity cannot be adjusted for serialized stock" %}' : '{% trans "Specify stock quantity" %}', } - ) - }; + ); + } var buttons = `
    `; @@ -283,7 +352,7 @@ function adjustStock(action, items, options={}) { confirm: true, confirmMessage: '{% trans "Confirm stock adjustment" %}', modal: modal, - onSubmit: function(fields, opts) { + onSubmit: function(fields) { // "Delete" action gets handled differently if (action == 'delete') { @@ -295,7 +364,7 @@ function adjustStock(action, items, options={}) { inventreeDelete( `/api/stock/${item.pk}/`, ) - ) + ); }); // Wait for *all* the requests to complete @@ -327,7 +396,7 @@ function adjustStock(action, items, options={}) { }); // Add in extra field data - for (field_name in extraFields) { + for (var field_name in extraFields) { data[field_name] = getFormFieldValue( field_name, fields[field_name], @@ -342,7 +411,7 @@ function adjustStock(action, items, options={}) { data, { method: 'POST', - success: function(response, status) { + success: function() { // Destroy the modal window $(modal).modal('hide'); @@ -353,22 +422,22 @@ function adjustStock(action, items, options={}) { }, error: function(xhr) { switch (xhr.status) { - case 400: + case 400: - // Handle errors for standard fields - handleFormErrors( - xhr.responseJSON, - extraFields, - { - modal: modal, - } - ) + // Handle errors for standard fields + handleFormErrors( + xhr.responseJSON, + extraFields, + { + modal: modal, + } + ); - break; - default: - $(modal).modal('hide'); - showApiError(xhr); - break; + break; + default: + $(modal).modal('hide'); + showApiError(xhr); + break; } } } @@ -446,15 +515,15 @@ function loadStockTestResultsTable(table, options) { html += makeIconButton('fa-trash-alt icon-red', 'button-test-delete', pk, '{% trans "Delete test result" %}'); } - html += "
    "; + html += '
    '; return html; } - var parent_node = "parent node"; + var parent_node = 'parent node'; table.inventreeTable({ - url: "{% url 'api-part-test-template-list' %}", + url: '{% url "api-part-test-template-list" %}', method: 'get', name: 'testresult', treeEnable: true, @@ -473,7 +542,7 @@ function loadStockTestResultsTable(table, options) { table.treegrid({ treeColumn: 0, }); - table.treegrid("collapseAll"); + table.treegrid('collapseAll'); }, columns: [ { @@ -539,12 +608,12 @@ function loadStockTestResultsTable(table, options) { stock_item: options.stock_item, user_detail: true, attachment_detail: true, - ordering: "-date", + ordering: '-date', }, { success: function(data) { // Iterate through the returned test data - data.forEach(function(item, index) { + data.forEach(function(item) { var match = false; var override = false; @@ -589,13 +658,12 @@ function loadStockTestResultsTable(table, options) { }); // Push data back into the table - table.bootstrapTable("load", tableData); + table.bootstrapTable('load', tableData); } } - ) + ); } }); - } @@ -671,11 +739,11 @@ function loadStockTable(table, options) { var params = options.params || {}; - var filterListElement = options.filterList || "#filter-list-stock"; + var filterListElement = options.filterList || '#filter-list-stock'; var filters = {}; - var filterKey = options.filterKey || options.name || "stock"; + var filterKey = options.filterKey || options.name || 'stock'; if (!options.disableFilters) { filters = loadTableFilters(filterKey); @@ -683,8 +751,8 @@ function loadStockTable(table, options) { var original = {}; - for (var key in params) { - original[key] = params[key]; + for (var k in params) { + original[k] = params[k]; } setupFilterList(filterKey, table, filterListElement); @@ -700,10 +768,13 @@ function loadStockTable(table, options) { grouping = options.grouping; } + var col = null; + // Explicitly disable part grouping functionality // Might be able to add this in later on, // but there is a bug which makes this crash if paginating on the server side. // Ref: https://github.com/wenzhixin/bootstrap-table/issues/3250 + // eslint-disable-next-line no-unused-vars grouping = false; var columns = [ @@ -727,22 +798,24 @@ function loadStockTable(table, options) { sortName: 'part__name', visible: params['part_detail'], switchable: params['part_detail'], - formatter: function(value, row, index, field) { + formatter: function(value, row) { var url = `/stock/item/${row.pk}/`; var thumb = row.part_detail.thumbnail; var name = row.part_detail.full_name; - html = imageHoverIcon(thumb) + renderLink(name, url); + var html = imageHoverIcon(thumb) + renderLink(name, url); html += makePartIcons(row.part_detail); return html; } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { @@ -751,13 +824,15 @@ function loadStockTable(table, options) { sortName: 'part__IPN', visible: params['part_detail'], switchable: params['part_detail'], - formatter: function(value, row, index, field) { + formatter: function(value, row) { return row.part_detail.IPN; }, }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); columns.push({ @@ -765,7 +840,7 @@ function loadStockTable(table, options) { title: '{% trans "Description" %}', visible: params['part_detail'], switchable: params['part_detail'], - formatter: function(value, row, index, field) { + formatter: function(value, row) { return row.part_detail.description; } }); @@ -773,7 +848,7 @@ function loadStockTable(table, options) { col = { field: 'quantity', title: '{% trans "Stock" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { var val = parseFloat(value); @@ -817,13 +892,9 @@ function loadStockTable(table, options) { // REJECTED if (row.status == {{ StockStatus.REJECTED }}) { html += makeIconBadge('fa-times-circle icon-red', '{% trans "Stock item has been rejected" %}'); - } - - // LOST - else if (row.status == {{ StockStatus.LOST }}) { - html += makeIconBadge('fa-question-circle','{% trans "Stock item is lost" %}'); - } - else if (row.status == {{ StockStatus.DESTROYED }}) { + } else if (row.status == {{ StockStatus.LOST }}) { + html += makeIconBadge('fa-question-circle', '{% trans "Stock item is lost" %}'); + } else if (row.status == {{ StockStatus.DESTROYED }}) { html += makeIconBadge('fa-skull-crossbones', '{% trans "Stock item is destroyed" %}'); } @@ -834,51 +905,61 @@ function loadStockTable(table, options) { return html; } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'status', title: '{% trans "Status" %}', - formatter: function(value, row, index, field) { + formatter: function(value) { return stockStatusDisplay(value); }, }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'batch', title: '{% trans "Batch" %}', }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'location_detail.pathstring', title: '{% trans "Location" %}', - formatter: function(value, row, index, field) { + formatter: function(value, row) { return locationDetail(row); } }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'stocktake_date', title: '{% trans "Stocktake" %}', }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { @@ -887,18 +968,22 @@ function loadStockTable(table, options) { visible: global_settings.STOCK_ENABLE_EXPIRY, switchable: global_settings.STOCK_ENABLE_EXPIRY, }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); col = { field: 'updated', title: '{% trans "Last Updated" %}', }; + if (!options.params.ordering) { col['sortable'] = true; - }; + } + columns.push(col); columns.push({ @@ -963,7 +1048,7 @@ function loadStockTable(table, options) { if (!options.params.ordering) { col.sortable = true; col.sortName = 'purchase_price'; - }; + } columns.push(col); @@ -981,7 +1066,7 @@ function loadStockTable(table, options) { formatNoMatches: function() { return '{% trans "No stock items matching query" %}'; }, - url: options.url || "{% url 'api-stock-list' %}", + url: options.url || '{% url "api-stock-list" %}', queryParams: filters, sidePagination: 'server', name: 'stock', @@ -1048,7 +1133,7 @@ function loadStockTable(table, options) { stock = +stock.toFixed(5); - return stock + " (" + items + " items)"; + return `${stock} (${items} {% trans "items" %})`; } else if (field == 'status') { var statii = []; @@ -1170,7 +1255,7 @@ function loadStockTable(table, options) { function stockAdjustment(action) { - var items = $(table).bootstrapTable("getSelections"); + var items = $(table).bootstrapTable('getSelections'); adjustStock(action, items, { onSuccess: function() { @@ -1203,7 +1288,7 @@ function loadStockTable(table, options) { }); printTestReports(items); - }) + }); if (global_settings.BARCODE_ENABLE) { $('#multi-item-barcode-scan-into-location').click(function() { @@ -1213,7 +1298,7 @@ function loadStockTable(table, options) { selections.forEach(function(item) { items.push(item.pk); - }) + }); scanItemsIntoLocation(items); }); @@ -1231,12 +1316,12 @@ function loadStockTable(table, options) { stockAdjustment('add'); }); - $("#multi-item-move").click(function() { + $('#multi-item-move').click(function() { stockAdjustment('move'); }); - $("#multi-item-order").click(function() { - var selections = $(table).bootstrapTable("getSelections"); + $('#multi-item-order').click(function() { + var selections = $(table).bootstrapTable('getSelections'); var stock = []; @@ -1244,14 +1329,14 @@ function loadStockTable(table, options) { stock.push(item.pk); }); - launchModalForm("/order/purchase-order/order-parts/", { + launchModalForm('/order/purchase-order/order-parts/', { data: { stock: stock, }, }); }); - $("#multi-item-set-status").click(function() { + $('#multi-item-set-status').click(function() { // Select and set the STATUS field for selected stock items var selections = $(table).bootstrapTable('getSelections'); @@ -1263,7 +1348,7 @@ function loadStockTable(table, options) { function(item) { return item.text; }, - function (item) { + function(item) { return item.key; } ); @@ -1335,11 +1420,11 @@ function loadStockTable(table, options) { $.when.apply($, requests).done(function() { $(table).bootstrapTable('refresh'); }); - }) + }); }); - $("#multi-item-delete").click(function() { - var selections = $(table).bootstrapTable("getSelections"); + $('#multi-item-delete').click(function() { + var selections = $(table).bootstrapTable('getSelections'); var stock = []; @@ -1368,8 +1453,8 @@ function loadStockLocationTable(table, options) { var original = {}; - for (var key in params) { - original[key] = params[key]; + for (var k in params) { + original[k] = params[k]; } setupFilterList(filterKey, table, filterListElement); @@ -1437,7 +1522,7 @@ function loadStockTrackingTable(table, options) { field: 'date', title: '{% trans "Date" %}', sortable: true, - formatter: function(value, row, index, field) { + formatter: function(value) { var m = moment(value); if (m.isValid()) { @@ -1453,11 +1538,11 @@ function loadStockTrackingTable(table, options) { cols.push({ field: 'label', title: '{% trans "Description" %}', - formatter: function(value, row, index, field) { - var html = "" + value + ""; + formatter: function(value, row) { + var html = '' + value + ''; if (row.notes) { - html += "
    " + row.notes + ""; + html += '
    ' + row.notes + ''; } return html; @@ -1468,7 +1553,7 @@ function loadStockTrackingTable(table, options) { cols.push({ field: 'deltas', title: '{% trans "Details" %}', - formatter: function(details, row, index, field) { + formatter: function(details, row) { var html = ``; if (!details) { @@ -1603,14 +1688,11 @@ function loadStockTrackingTable(table, options) { cols.push({ field: 'user', title: '{% trans "User" %}', - formatter: function(value, row, index, field) { - if (value) - { + formatter: function(value, row) { + if (value) { // TODO - Format the user's first and last names return row.user_detail.username; - } - else - { + } else { return `{% trans "No user information" %}`; } } @@ -1692,7 +1774,7 @@ function createNewStockItem(options) { reloadFieldOptions( 'supplier_part', { - url: "{% url 'api-supplier-part-list' %}", + url: '{% url "api-supplier-part-list" %}', params: { part: value, pretty: true, @@ -1723,7 +1805,7 @@ function createNewStockItem(options) { } else { var expiry = moment().add(response.default_expiry, 'days'); - setFieldValue('expiry_date', expiry.format("YYYY-MM-DD")); + setFieldValue('expiry_date', expiry.format('YYYY-MM-DD')); } } } @@ -1732,7 +1814,7 @@ function createNewStockItem(options) { }, ]; - launchModalForm("{% url 'stock-item-create' %}", options); + launchModalForm('{% url "stock-item-create" %}', options); } @@ -1741,28 +1823,8 @@ function loadInstalledInTable(table, options) { * Display a table showing the stock items which are installed in this stock item. */ - function updateCallbacks() { - // Setup callback functions when buttons are pressed - table.find('.button-install').click(function() { - var pk = $(this).attr('pk'); - - launchModalForm( - `/stock/item/${options.stock_item}/install/`, - { - data: { - part: pk, - }, - success: function() { - // Refresh entire table! - table.bootstrapTable('refresh'); - } - } - ); - }); - } - table.inventreeTable({ - url: "{% url 'api-stock-list' %}", + url: '{% url "api-stock-list" %}', queryParams: { installed_in: options.stock_item, part_detail: true, @@ -1802,7 +1864,7 @@ function loadInstalledInTable(table, options) { { field: 'status', title: '{% trans "Status" %}', - formatter: function(value, row) { + formatter: function(value) { return stockStatusDisplay(value); } }, @@ -1841,8 +1903,8 @@ function loadInstalledInTable(table, options) { table.bootstrapTable('refresh'); } } - ) + ); }); } }); -} \ No newline at end of file +} diff --git a/InvenTree/templates/js/translated/table_filters.js b/InvenTree/templates/js/translated/table_filters.js index 9e173a7b37..b94bc324c7 100644 --- a/InvenTree/templates/js/translated/table_filters.js +++ b/InvenTree/templates/js/translated/table_filters.js @@ -8,13 +8,26 @@ {% include "status_codes.html" with label='purchaseOrder' options=PurchaseOrderStatus.list %} {% include "status_codes.html" with label='salesOrder' options=SalesOrderStatus.list %} +/* globals + global_settings +*/ + +/* exported + buildStatusDisplay, + getAvailableTableFilters, + purchaseOrderStatusDisplay, + salesOrderStatusDisplay, + stockHistoryStatusDisplay, + stockStatusDisplay, +*/ + function getAvailableTableFilters(tableKey) { tableKey = tableKey.toLowerCase(); // Filters for "variant" table - if (tableKey == "variants") { + if (tableKey == 'variants') { return { active: { type: 'bool', @@ -36,11 +49,11 @@ function getAvailableTableFilters(tableKey) { } // Filters for Bill of Materials table - if (tableKey == "bom") { + if (tableKey == 'bom') { return { sub_part_trackable: { type: 'bool', - title: '{% trans "Trackable Part" %}' + title: '{% trans "Trackable Part" %}', }, sub_part_assembly: { type: 'bool', @@ -57,7 +70,7 @@ function getAvailableTableFilters(tableKey) { allow_variants: { type: 'bool', title: '{% trans "Allow Variant Stock" %}', - } + }, }; } @@ -72,29 +85,29 @@ function getAvailableTableFilters(tableKey) { } // Filters for "stock location" table - if (tableKey == "location") { + if (tableKey == 'location') { return { cascade: { type: 'bool', title: '{% trans "Include sublocations" %}', description: '{% trans "Include locations" %}', - } + }, }; } // Filters for "part category" table - if (tableKey == "category") { + if (tableKey == 'category') { return { cascade: { type: 'bool', title: '{% trans "Include subcategories" %}', description: '{% trans "Include subcategories" %}', - } + }, }; } // Filters for the "customer stock" table (really a subset of "stock") - if (tableKey == "customerstock") { + if (tableKey == 'customerstock') { return { serialized: { type: 'bool', @@ -102,7 +115,7 @@ function getAvailableTableFilters(tableKey) { }, serial_gte: { title: '{% trans "Serial number GTE" %}', - description: '{% trans "Serial number greater than or equal to" %}' + description: '{% trans "Serial number greater than or equal to" %}', }, serial_lte: { title: '{% trans "Serial number LTE" %}', @@ -110,7 +123,7 @@ function getAvailableTableFilters(tableKey) { }, serial: { title: '{% trans "Serial number" %}', - description: '{% trans "Serial number" %}' + description: '{% trans "Serial number" %}', }, batch: { title: '{% trans "Batch" %}', @@ -179,11 +192,11 @@ function getAvailableTableFilters(tableKey) { }, serial: { title: '{% trans "Serial number" %}', - description: '{% trans "Serial number" %}' + description: '{% trans "Serial number" %}', }, serial_gte: { title: '{% trans "Serial number GTE" %}', - description: '{% trans "Serial number greater than or equal to" %}' + description: '{% trans "Serial number greater than or equal to" %}', }, serial_lte: { title: '{% trans "Serial number LTE" %}', @@ -239,7 +252,7 @@ function getAvailableTableFilters(tableKey) { required: { type: 'bool', title: '{% trans "Required" %}', - } + }, }; } @@ -262,7 +275,7 @@ function getAvailableTableFilters(tableKey) { } // Filters for the "Order" table - if (tableKey == "purchaseorder") { + if (tableKey == 'purchaseorder') { return { status: { @@ -280,7 +293,7 @@ function getAvailableTableFilters(tableKey) { }; } - if (tableKey == "salesorder") { + if (tableKey == 'salesorder') { return { status: { title: '{% trans "Order status" %}', @@ -302,12 +315,12 @@ function getAvailableTableFilters(tableKey) { active: { type: 'bool', title: '{% trans "Active parts" %}', - } + }, }; } // Filters for the "Parts" table - if (tableKey == "parts") { + if (tableKey == 'parts') { return { cascade: { type: 'bool', @@ -330,7 +343,7 @@ function getAvailableTableFilters(tableKey) { }, has_stock: { type: 'bool', - title: '{% trans "Stock available" %}' + title: '{% trans "Stock available" %}', }, low_stock: { type: 'bool', diff --git a/InvenTree/templates/js/translated/tables.js b/InvenTree/templates/js/translated/tables.js index 88d9a5f99a..6e719563ae 100644 --- a/InvenTree/templates/js/translated/tables.js +++ b/InvenTree/templates/js/translated/tables.js @@ -1,21 +1,33 @@ {% load i18n %} +/* global + inventreeLoad, + inventreeSave, +*/ +/* exported + customGroupSorter, + reloadtable, + renderLink, + reloadTableFilters, +*/ + +/** + * Reload a named table + * @param table + */ function reloadtable(table) { $(table).bootstrapTable('refresh'); } -function editButton(url, text='Edit') { - return ""; -} - - -function deleteButton(url, text='Delete') { - return ""; -} - - +/** + * Render a URL for display + * @param {String} text + * @param {String} url + * @param {object} options + * @returns link text + */ function renderLink(text, url, options={}) { if (url === null || url === undefined || url === '') { return text; @@ -23,8 +35,6 @@ function renderLink(text, url, options={}) { var max_length = options.max_length || -1; - var remove_http = options.remove_http || false; - // Shorten the displayed length if required if ((max_length > 0) && (text.length > max_length)) { var slice_length = (max_length - 3) / 2; @@ -59,12 +69,17 @@ function linkButtonsToSelection(table, buttons) { enableButtons(buttons, table.bootstrapTable('getSelections').length > 0); // Add a callback - table.on('check.bs.table uncheck.bs.table check-some.bs.table uncheck-some.bs.table check-all.bs.table uncheck-all.bs.table', function(row) { + table.on('check.bs.table uncheck.bs.table check-some.bs.table uncheck-some.bs.table check-all.bs.table uncheck-all.bs.table', function() { enableButtons(buttons, table.bootstrapTable('getSelections').length > 0); }); } +/** + * Returns true if the input looks like a valid number + * @param {String} n + * @returns + */ function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } @@ -88,8 +103,8 @@ function reloadTableFilters(table, filters) { // Construct a new list of filters to use for the query var params = {}; - for (var key in filters) { - params[key] = filters[key]; + for (var k in filters) { + params[k] = filters[k]; } // Original query params will override @@ -136,7 +151,6 @@ function convertQueryParameters(params, filters) { var ordering = params['sort'] || null; if (ordering) { - if (order == 'desc') { ordering = `-${ordering}`; } @@ -220,7 +234,7 @@ $.fn.inventreeTable = function(options) { }; // Callback when a column is changed - options.onColumnSwitch = function(field, checked) { + options.onColumnSwitch = function() { var columns = table.bootstrapTable('getVisibleColumns'); @@ -239,7 +253,7 @@ $.fn.inventreeTable = function(options) { // If a set of visible columns has been saved, load! if (visibleColumns) { - var columns = visibleColumns.split(","); + var columns = visibleColumns.split(','); // Which columns are currently visible? var visible = table.bootstrapTable('getVisibleColumns'); @@ -253,7 +267,7 @@ $.fn.inventreeTable = function(options) { } }); } else { - console.log('Could not get list of visible columns!'); + console.log(`Could not get list of visible columns for column '${tableName}'`); } } @@ -261,7 +275,8 @@ $.fn.inventreeTable = function(options) { if (options.buttons) { linkButtonsToSelection(table, options.buttons); } -} +}; + function customGroupSorter(sortName, sortOrder, sortData) { @@ -334,42 +349,42 @@ function customGroupSorter(sortName, sortOrder, sortData) { } // Expose default bootstrap table string literals to translation layer -(function ($) { +(function($) { 'use strict'; $.fn.bootstrapTable.locales['en-US-custom'] = { - formatLoadingMessage: function () { + formatLoadingMessage: function() { return '{% trans "Loading data" %}'; }, - formatRecordsPerPage: function (pageNumber) { + formatRecordsPerPage: function(pageNumber) { return `${pageNumber} {% trans "rows per page" %}`; }, - formatShowingRows: function (pageFrom, pageTo, totalRows) { + formatShowingRows: function(pageFrom, pageTo, totalRows) { return `{% trans "Showing" %} ${pageFrom} {% trans "to" %} ${pageTo} {% trans "of" %} ${totalRows} {% trans "rows" %}`; }, - formatSearch: function () { + formatSearch: function() { return '{% trans "Search" %}'; }, - formatNoMatches: function () { + formatNoMatches: function() { return '{% trans "No matching results" %}'; }, - formatPaginationSwitch: function () { + formatPaginationSwitch: function() { return '{% trans "Hide/Show pagination" %}'; }, - formatRefresh: function () { + formatRefresh: function() { return '{% trans "Refresh" %}'; }, - formatToggle: function () { + formatToggle: function() { return '{% trans "Toggle" %}'; }, - formatColumns: function () { + formatColumns: function() { return '{% trans "Columns" %}'; }, - formatAllRows: function () { + formatAllRows: function() { return '{% trans "All" %}'; - } + }, }; $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales['en-US-custom']); -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/InvenTree/templates/status_codes.html b/InvenTree/templates/status_codes.html index e7bc2e951c..453a7914e2 100644 --- a/InvenTree/templates/status_codes.html +++ b/InvenTree/templates/status_codes.html @@ -1,12 +1,13 @@ /* * Status codes for the {{ label }} model. */ -var {{ label }}Codes = { +const {{ label }}Codes = { {% for opt in options %}'{{ opt.key }}': { key: '{{ opt.key }}', value: '{{ opt.value }}',{% if opt.color %} label: 'label-{{ opt.color }}',{% endif %} - },{% endfor %} + }, + {% endfor %} }; /* diff --git a/tasks.py b/tasks.py index 3de0241c07..1abbf23bc6 100644 --- a/tasks.py +++ b/tasks.py @@ -457,3 +457,12 @@ def server(c, address="127.0.0.1:8000"): """ manage(c, "runserver {address}".format(address=address), pty=True) + + +@task +def render_js_files(c): + """ + Render templated javascript files (used for static testing). + """ + + manage(c, "test InvenTree.ci_render_js")