mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 21:15:41 +00:00
Merge branch 'master' of https://github.com/inventree/InvenTree into plugin-2037
This commit is contained in:
@ -12,12 +12,15 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block actions %}
|
||||
{% inventree_demo_mode as demo %}
|
||||
{% if not demo %}
|
||||
<div class='btn btn-primary' type='button' id='edit-user' title='{% trans "Edit User Information" %}'>
|
||||
<span class='fas fa-user-cog'></span> {% trans "Edit" %}
|
||||
</div>
|
||||
<div class='btn btn-primary' type='button' id='edit-password' title='{% trans "Change Password" %}'>
|
||||
<span class='fas fa-key'></span> {% trans "Set Password" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -1,5 +1,6 @@
|
||||
{% extends "account/base.html" %}
|
||||
|
||||
{% load inventree_extras %}
|
||||
{% load i18n account socialaccount crispy_forms_tags inventree_extras %}
|
||||
|
||||
{% block head_title %}{% trans "Sign In" %}{% endblock %}
|
||||
@ -10,6 +11,7 @@
|
||||
{% settings_value 'LOGIN_ENABLE_PWD_FORGOT' as enable_pwd_forgot %}
|
||||
{% settings_value 'LOGIN_ENABLE_SSO' as enable_sso %}
|
||||
{% mail_configured as mail_conf %}
|
||||
{% inventree_demo_mode as demo %}
|
||||
|
||||
<h1>{% trans "Sign In" %}</h1>
|
||||
|
||||
@ -36,9 +38,16 @@ for a account and sign in below:{% endblocktrans %}</p>
|
||||
<div class="btn-group float-right" role="group">
|
||||
<button class="btn btn-success" type="submit">{% trans "Sign In" %}</button>
|
||||
</div>
|
||||
{% if mail_conf and enable_pwd_forgot %}
|
||||
{% if mail_conf and enable_pwd_forgot and not demo %}
|
||||
<a class="" href="{% url 'account_reset_password' %}"><small>{% trans "Forgot Password?" %}</small></a>
|
||||
{% endif %}
|
||||
{% if demo %}
|
||||
<p>
|
||||
<h6>
|
||||
{% trans "InvenTree demo instance" %} - <a href='https://inventree.readthedocs.io/en/latest/demo/'>{% trans "Click here for login details" %}</a>
|
||||
</h6>
|
||||
</p>
|
||||
{% endif %}
|
||||
</form>
|
||||
|
||||
{% if enable_sso %}
|
||||
|
@ -86,25 +86,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<main class='col ps-md-2 pt-2 pe-2'>
|
||||
|
||||
{% if server_restart_required %}
|
||||
<div class='notification-area' id='restart-required'>
|
||||
|
||||
{% block alerts %}
|
||||
<div class='notification-area' id='alerts'>
|
||||
<!-- Div for displayed alerts -->
|
||||
{% if server_restart_required %}
|
||||
<div id='alert-restart-server' class='alert alert-danger' role='alert'>
|
||||
<span class='fas fa-server'></span>
|
||||
<b>{% trans "Server Restart Required" %}</b>
|
||||
<small>
|
||||
<br>
|
||||
{% trans "A configuration option has been changed which requires a server restart" %}.
|
||||
<br>
|
||||
{% trans "Contact your system administrator for further information" %}
|
||||
{% trans "A configuration option has been changed which requires a server restart" %}. {% trans "Contact your system administrator for further information" %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block alerts %}
|
||||
<div class='notification-area' id='alerts'>
|
||||
<!-- Div for displayed alerts -->
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -217,8 +217,10 @@ function showApiError(xhr, url) {
|
||||
break;
|
||||
}
|
||||
|
||||
message += '<hr>';
|
||||
message += `URL: ${url}`;
|
||||
if (url) {
|
||||
message += '<hr>';
|
||||
message += `URL: ${url}`;
|
||||
}
|
||||
|
||||
showMessage(title, {
|
||||
style: 'danger',
|
||||
|
@ -16,6 +16,7 @@
|
||||
/* exported
|
||||
newPartFromBomWizard,
|
||||
loadBomTable,
|
||||
loadUsedInTable,
|
||||
removeRowFromBomWizard,
|
||||
removeColFromBomWizard,
|
||||
*/
|
||||
@ -311,7 +312,7 @@ function bomSubstitutesDialog(bom_item_id, substitutes, options={}) {
|
||||
}
|
||||
|
||||
|
||||
function loadBomTable(table, options) {
|
||||
function loadBomTable(table, options={}) {
|
||||
/* Load a BOM table with some configurable options.
|
||||
*
|
||||
* Following options are available:
|
||||
@ -395,7 +396,7 @@ function loadBomTable(table, options) {
|
||||
|
||||
var sub_part = row.sub_part_detail;
|
||||
|
||||
html += makePartIcons(row.sub_part_detail);
|
||||
html += makePartIcons(sub_part);
|
||||
|
||||
if (row.substitutes && row.substitutes.length > 0) {
|
||||
html += makeIconBadge('fa-exchange-alt', '{% trans "Substitutes Available" %}');
|
||||
@ -672,8 +673,9 @@ function loadBomTable(table, options) {
|
||||
|
||||
table.treegrid('collapseAll');
|
||||
},
|
||||
error: function() {
|
||||
error: function(xhr) {
|
||||
console.log('Error requesting BOM for part=' + part_pk);
|
||||
showApiError(xhr);
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -835,3 +837,166 @@ function loadBomTable(table, options) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load a table which shows the assemblies which "require" a certain part.
|
||||
*
|
||||
* Arguments:
|
||||
* - table: The ID string of the table element e.g. '#used-in-table'
|
||||
* - part_id: The ID (PK) of the part we are interested in
|
||||
*
|
||||
* Options:
|
||||
* -
|
||||
*
|
||||
* The following "options" are available.
|
||||
*/
|
||||
function loadUsedInTable(table, part_id, options={}) {
|
||||
|
||||
var params = options.params || {};
|
||||
|
||||
params.uses = part_id;
|
||||
params.part_detail = true;
|
||||
params.sub_part_detail = true,
|
||||
params.show_pricing = global_settings.PART_SHOW_PRICE_IN_BOM;
|
||||
|
||||
var filters = {};
|
||||
|
||||
if (!options.disableFilters) {
|
||||
filters = loadTableFilters('usedin');
|
||||
}
|
||||
|
||||
for (var key in params) {
|
||||
filters[key] = params[key];
|
||||
}
|
||||
|
||||
setupFilterList('usedin', $(table), options.filterTarget || '#filter-list-usedin');
|
||||
|
||||
function loadVariantData(row) {
|
||||
// Load variants information for inherited BOM rows
|
||||
|
||||
inventreeGet(
|
||||
'{% url "api-part-list" %}',
|
||||
{
|
||||
assembly: true,
|
||||
ancestor: row.part,
|
||||
},
|
||||
{
|
||||
success: function(variantData) {
|
||||
// Iterate through each variant item
|
||||
for (var jj = 0; jj < variantData.length; jj++) {
|
||||
variantData[jj].parent = row.pk;
|
||||
|
||||
var variant = variantData[jj];
|
||||
|
||||
// Add this variant to the table, augmented
|
||||
$(table).bootstrapTable('append', [{
|
||||
// Point the parent to the "master" assembly row
|
||||
parent: row.pk,
|
||||
part: variant.pk,
|
||||
part_detail: variant,
|
||||
sub_part: row.sub_part,
|
||||
sub_part_detail: row.sub_part_detail,
|
||||
quantity: row.quantity,
|
||||
}]);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
showApiError(xhr);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: options.url || '{% url "api-bom-list" %}',
|
||||
name: options.table_name || 'usedin',
|
||||
sortable: true,
|
||||
search: true,
|
||||
showColumns: true,
|
||||
queryParams: filters,
|
||||
original: params,
|
||||
rootParentId: 'top-level-item',
|
||||
idField: 'pk',
|
||||
uniqueId: 'pk',
|
||||
parentIdField: 'parent',
|
||||
treeShowField: 'part',
|
||||
onLoadSuccess: function(tableData) {
|
||||
// Once the initial data are loaded, check if there are any "inherited" BOM lines
|
||||
for (var ii = 0; ii < tableData.length; ii++) {
|
||||
var row = tableData[ii];
|
||||
|
||||
// This is a "top level" item in the table
|
||||
row.parent = 'top-level-item';
|
||||
|
||||
// Ignore this row as it is not "inherited" by variant parts
|
||||
if (!row.inherited) {
|
||||
continue;
|
||||
}
|
||||
|
||||
loadVariantData(row);
|
||||
}
|
||||
},
|
||||
onPostBody: function() {
|
||||
$(table).treegrid({
|
||||
treeColumn: 0,
|
||||
});
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'part',
|
||||
title: '{% trans "Assembly" %}',
|
||||
switchable: false,
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
var url = `/part/${value}/?display=bom`;
|
||||
var html = '';
|
||||
|
||||
var part = row.part_detail;
|
||||
|
||||
html += imageHoverIcon(part.thumbnail);
|
||||
html += renderLink(part.full_name, url);
|
||||
html += makePartIcons(part);
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'sub_part',
|
||||
title: '{% trans "Required Part" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
var url = `/part/${value}/`;
|
||||
var html = '';
|
||||
|
||||
var sub_part = row.sub_part_detail;
|
||||
|
||||
html += imageHoverIcon(sub_part.thumbnail);
|
||||
html += renderLink(sub_part.full_name, url);
|
||||
html += makePartIcons(sub_part);
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '{% trans "Required Quantity" %}',
|
||||
formatter: function(value, row) {
|
||||
var html = value;
|
||||
|
||||
if (row.parent && row.parent != 'top-level-item') {
|
||||
html += ` <em>({% trans "Inherited from parent BOM" %})</em>`;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
@ -281,23 +281,24 @@ function setupFilterList(tableKey, table, target) {
|
||||
// One blank slate, please
|
||||
element.empty();
|
||||
|
||||
element.append(`<button id='reload-${tableKey}' title='{% trans "Reload data" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-redo-alt'></span></button>`);
|
||||
var buttons = '';
|
||||
|
||||
// Callback for reloading the table
|
||||
element.find(`#reload-${tableKey}`).click(function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
});
|
||||
buttons += `<button id='reload-${tableKey}' title='{% trans "Reload data" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-redo-alt'></span></button>`;
|
||||
|
||||
// If there are no filters defined for this table, exit now
|
||||
if (jQuery.isEmptyObject(getAvailableTableFilters(tableKey))) {
|
||||
return;
|
||||
// If there are filters defined for this table, add more buttons
|
||||
if (!jQuery.isEmptyObject(getAvailableTableFilters(tableKey))) {
|
||||
buttons += `<button id='${add}' title='{% trans "Add new filter" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-filter'></span></button>`;
|
||||
|
||||
if (Object.keys(filters).length > 0) {
|
||||
buttons += `<button id='${clear}' title='{% trans "Clear all filters" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-backspace icon-red'></span></button>`;
|
||||
}
|
||||
}
|
||||
|
||||
element.append(`<button id='${add}' title='{% trans "Add new filter" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-filter'></span></button>`);
|
||||
|
||||
if (Object.keys(filters).length > 0) {
|
||||
element.append(`<button id='${clear}' title='{% trans "Clear all filters" %}' class='btn btn-outline-secondary filter-button'><span class='fas fa-backspace icon-red'></span></button>`);
|
||||
}
|
||||
element.html(`
|
||||
<div class='btn-group' role='group'>
|
||||
${buttons}
|
||||
</div>
|
||||
`);
|
||||
|
||||
for (var key in filters) {
|
||||
var value = getFilterOptionValue(tableKey, key, filters[key]);
|
||||
@ -307,6 +308,11 @@ function setupFilterList(tableKey, table, target) {
|
||||
element.append(`<div title='${description}' class='filter-tag'>${title} = ${value}<span ${tag}='${key}' class='close'>x</span></div>`);
|
||||
}
|
||||
|
||||
// Callback for reloading the table
|
||||
element.find(`#reload-${tableKey}`).click(function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
});
|
||||
|
||||
// Add a callback for adding a new filter
|
||||
element.find(`#${add}`).click(function clicked() {
|
||||
|
||||
@ -316,10 +322,12 @@ function setupFilterList(tableKey, table, target) {
|
||||
|
||||
var html = '';
|
||||
|
||||
html += `<div class='input-group'>`;
|
||||
html += generateAvailableFilterList(tableKey);
|
||||
html += generateFilterInput(tableKey);
|
||||
|
||||
html += `<button title='{% trans "Create filter" %}' class='btn btn-outline-secondary filter-button' id='${make}'><span class='fas fa-plus'></span></button>`;
|
||||
html += `</div>`;
|
||||
|
||||
element.append(html);
|
||||
|
||||
|
@ -924,8 +924,8 @@ function handleFormSuccess(response, options) {
|
||||
var cache = (options.follow && response.url) || options.redirect || options.reload;
|
||||
|
||||
// Display any messages
|
||||
if (response && response.success) {
|
||||
showAlertOrCache(response.success, cache, {style: 'success'});
|
||||
if (response && (response.success || options.successMessage)) {
|
||||
showAlertOrCache(response.success || options.successMessage, cache, {style: 'success'});
|
||||
}
|
||||
|
||||
if (response && response.info) {
|
||||
|
@ -331,6 +331,7 @@ function editPart(pk) {
|
||||
groups: groups,
|
||||
title: '{% trans "Edit Part" %}',
|
||||
reload: true,
|
||||
successMessage: '{% trans "Part edited" %}',
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -77,10 +77,22 @@ function getAvailableTableFilters(tableKey) {
|
||||
// Filters for the "used in" table
|
||||
if (tableKey == 'usedin') {
|
||||
return {
|
||||
'inherited': {
|
||||
type: 'bool',
|
||||
title: '{% trans "Inherited" %}',
|
||||
},
|
||||
'optional': {
|
||||
type: 'bool',
|
||||
title: '{% trans "Optional" %}',
|
||||
},
|
||||
'part_active': {
|
||||
type: 'bool',
|
||||
title: '{% trans "Active" %}',
|
||||
},
|
||||
'part_trackable': {
|
||||
type: 'bool',
|
||||
title: '{% trans "Trackable" %}',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
{% settings_value 'BARCODE_ENABLE' as barcodes %}
|
||||
{% settings_value 'STICKY_HEADER' user=request.user as sticky %}
|
||||
{% navigation_enabled as plugin_nav %}
|
||||
{% inventree_demo_mode as demo %}
|
||||
|
||||
<nav class="navbar {% if sticky %}fixed-top{% endif %} navbar-expand-lg navbar-light">
|
||||
<div class="container-fluid">
|
||||
@ -83,6 +84,9 @@
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
{% if demo %}
|
||||
{% include "navbar_demo.html" %}
|
||||
{% endif %}
|
||||
{% include "search_form.html" %}
|
||||
<ul class='navbar-nav flex-row'>
|
||||
{% if barcodes %}
|
||||
@ -103,7 +107,7 @@
|
||||
</a>
|
||||
<ul class='dropdown-menu dropdown-menu-end inventree-navbar-menu'>
|
||||
{% if user.is_authenticated %}
|
||||
{% if user.is_staff %}
|
||||
{% if user.is_staff and not demo %}
|
||||
<li><a class='dropdown-item' href="/admin/"><span class="fas fa-user"></span> {% trans "Admin" %}</a></li>
|
||||
{% endif %}
|
||||
<li><a class='dropdown-item' href="{% url 'account_logout' %}"><span class="fas fa-sign-out-alt"></span> {% trans "Logout" %}</a></li>
|
||||
|
12
InvenTree/templates/navbar_demo.html
Normal file
12
InvenTree/templates/navbar_demo.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% load i18n %}
|
||||
{% include "spacer.html" %}
|
||||
<div class='flex'>
|
||||
<h6>
|
||||
{% trans "InvenTree demo mode" %}
|
||||
<a href='https://inventree.readthedocs.io/en/latest/demo/'>
|
||||
<span class='fas fa-info-circle'></span>
|
||||
</a>
|
||||
</h6>
|
||||
</div>
|
||||
{% include "spacer.html" %}
|
||||
{% include "spacer.html" %}
|
@ -2,8 +2,10 @@
|
||||
|
||||
<form class="d-flex" action="{% url 'search' %}" method='post'>
|
||||
{% csrf_token %}
|
||||
<input type="text" name='search' class="form-control" aria-label='{% trans "Search" %}' id="search-bar" placeholder="{% trans 'Search' %}"{% if query_text %} value="{{ query }}"{% endif %}>
|
||||
<button type="submit" id='search-submit' class="btn btn-secondary" title='{% trans "Search" %}'>
|
||||
<span class='fas fa-search'></span>
|
||||
</button>
|
||||
<div class='input-group'>
|
||||
<input type="text" name='search' class="form-control" aria-label='{% trans "Search" %}' id="search-bar" placeholder="{% trans 'Search' %}"{% if query_text %} value="{{ query }}"{% endif %}>
|
||||
<button type="submit" id='search-submit' class="btn btn-secondary" title='{% trans "Search" %}'>
|
||||
<span class='fas fa-search'></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -27,6 +27,9 @@ function {{ label }}StatusDisplay(key, options={}) {
|
||||
label = {{ label }}Codes[key].label;
|
||||
}
|
||||
|
||||
// Fallback option for label
|
||||
label = label || 'bg-dark';
|
||||
|
||||
if (value == null || value.length == 0) {
|
||||
value = key;
|
||||
label = '';
|
||||
|
Reference in New Issue
Block a user