2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 13:05:42 +00:00

Merge branch 'inventree:master' into matmair/issue2279

This commit is contained in:
Matthias Mair
2021-12-15 00:20:48 +01:00
committed by GitHub
25 changed files with 716 additions and 242 deletions

View File

@ -16,6 +16,7 @@
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_SSO" icon="fa-info-circle" %}
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENABLE_PWD_FORGOT" icon="fa-info-circle" %}
{% include "InvenTree/settings/setting.html" with key="LOGIN_MAIL_REQUIRED" icon="fa-info-circle" %}
{% include "InvenTree/settings/setting.html" with key="LOGIN_ENFORCE_MFA" %}
<tr>
<th><h5>{% trans 'Signup' %}</h5></th>
<td colspan='4'></td>

View File

@ -42,193 +42,317 @@
</tr>
</table>
<div class='panel-heading'>
<div class='d-flex flex-span'>
<div class="row">
<div class='panel-heading'>
<div class='d-flex flex-span'>
<h4>{% trans "Email" %}</h4>
{% include "spacer.html" %}
</div>
</div>
</div>
<div class='row'>
<div class='col-sm-6'>
{% if user.emailaddress_set.all %}
<p>{% trans 'The following email addresses are associated with your account:' %}</p>
<div class="col-sm-6">
{% if user.emailaddress_set.all %}
<p>{% trans 'The following email addresses are associated with your account:' %}</p>
<form action="{% url 'account_email' %}" class="email_list" method="post">
<form action="{% url 'account_email' %}" class="email_list" method="post">
{% csrf_token %}
<fieldset class="blockLabels">
<fieldset class="blockLabels">
{% for emailaddress in user.emailaddress_set.all %}
<div>
<div class="ctrlHolder">
<label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked"{%endif %} value="{{emailaddress.email}}"/>
{% if emailaddress.primary %}
<b>{{ emailaddress.email }}</b>
{% else %}
{{ emailaddress.email }}
{% endif %}
</label>
{% if emailaddress.verified %}
<span class='badge badge-right rounded-pill bg-success'>{% trans "Verified" %}</span>
<div class="ctrlHolder">
<label for="email_radio_{{forloop.counter}}" class="{% if emailaddress.primary %}primary_email{%endif%}">
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked" {%endif %} value="{{emailaddress.email}}" />
{% if emailaddress.primary %}
<b>{{ emailaddress.email }}</b>
{% else %}
<span class='badge badge-right rounded-pill bg-warning'>{% trans "Unverified" %}</span>
{{ emailaddress.email }}
{% endif %}
{% if emailaddress.primary %}<span class='badge badge-right rounded-pill bg-primary'>{% trans "Primary" %}</span>{% endif %}
</div>
</label>
{% if emailaddress.verified %}
<span class='badge badge-right rounded-pill bg-success'>{% trans "Verified" %}</span>
{% else %}
<span class='badge badge-right rounded-pill bg-warning'>{% trans "Unverified" %}</span>
{% endif %}
{% if emailaddress.primary %}<span class='badge badge-right rounded-pill bg-primary'>{% trans "Primary" %}</span>{% endif %}
</div>
</div>
{% endfor %}
<div class="buttonHolder">
<button class="btn btn-primary secondaryAction" type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button class="btn btn-primary secondaryAction" type="submit" name="action_primary">{% trans 'Make Primary' %}</button>
<button class="btn btn-primary secondaryAction" type="submit" name="action_send" {% if not mail_conf %}disabled{% endif %}>{% trans 'Re-send Verification' %}</button>
<button class="btn btn-primary primaryAction" type="submit" name="action_remove" >{% trans 'Remove' %}</button>
<button class="btn btn-primary primaryAction" type="submit" name="action_remove">{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<div class='alert alert-block alert-danger'>
<strong>{% trans 'Warning:'%}</strong>
{% trans "You currently do not have any email address set up. You should really add an email address so you can receive notifications, reset your password, etc." %}
</div>
{% endif %}
</div>
{% if can_add_email %}
<div class="col-sm-6">
<h5>{% trans "Add Email Address" %}</h5>
<form method="post" action="{% url 'account_email' %}" class="add_email">
{% csrf_token %}
{{ add_email_form|crispy }}
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add Email" %}</button>
</form>
</div>
{% endif %}
</div>
<div class="row">
<div class='panel-heading'>
<h4>{% trans "Social Accounts" %}</h4>
</div>
<div class="col-md-6">
{% if social_form.accounts %}
<p>{% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}</p>
<form method="post" action="{% url 'socialaccount_connections' %}">
{% csrf_token %}
<fieldset>
{% if social_form.non_field_errors %}
<div id="errorMsg">{{ social_form.non_field_errors }}</div>
{% endif %}
{% for base_account in social_form.accounts %}
{% with base_account.get_provider_account as account %}
<div>
<label for="id_account_{{ base_account.id }}">
<input id="id_account_{{ base_account.id }}" type="radio" name="account"
value="{{ base_account.id }}" />
<span class="socialaccount_provider {{ base_account.provider }} {{ account.get_brand.id }}">
<span class='brand-icon'
brand_name='{{account.get_brand.id}}'></span>{{account.get_brand.name}}</span>
{{ account }}
</label>
</div>
{% endwith %}
{% endfor %}
<div>
<button class="btn btn-primary" type="submit">{% trans 'Remove' %}</button>
</div>
</fieldset>
</form>
{% else %}
<p><strong>{% trans 'Warning:'%}</strong>
{% trans "You currently do not have any email address set up. You should really add an email address so you can receive notifications, reset your password, etc." %}
</p>
<p>{% trans 'You currently have no social network accounts connected to this account.' %}</p>
{% endif %}
</div>
<div class="col-md-6">
<h5>{% trans 'Add a 3rd Party Account' %}</h5>
<div>
{% include "socialaccount/snippets/provider_list.html" with process="connect" %}
</div>
{% include "socialaccount/snippets/login_extra.html" %}
</div>
</div>
<div class="row">
<div class='panel-heading'>
<h4>{% trans "Multifactor" %}</h4>
</div>
<div class="col-md-6">
{% if user.staticdevice_set.all or user.totpdevice_set.all %}
<p>{% trans 'You have these factors available:' %}</p>
<table class="table table-striped">
<thead>
<th>Type</th>
<th>Name</th>
</thead>
<tbody>
{% for token in user.totpdevice_set.all %}
<tr>
<td>{% trans 'TOTP' %}</td>
<td>{{ token.name }}</td>
</tr>
{% endfor %}
{% for token in user.staticdevice_set.all %}
<tr>
<td>{% trans 'Static' %}</td>
<td>{{ token.name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p><strong>{% trans 'Warning:'%}</strong>
{% trans "You currently do not have any factors set up." %}
</p>
{% endif %}
</div>
<div class="col-md-6">
<h5>{% trans "Change factors" %}</h5>
<a href="{% url 'two-factor-setup' %}" class="btn btn-primary {% if user.staticdevice_set.all and user.totpdevice_set.all %}disabled{% endif %}" role="button">{% trans "Setup multifactor" %}</a>
{% if user.staticdevice_set.all or user.totpdevice_set.all %}
<a href="{% url 'two-factor-remove' %}" class="btn btn-primary" role="button">{% trans "Remove multifactor" %}</a>
{% endif %}
</div>
</div>
<div class='row'>
<div class='panel-heading'>
<h4>{% trans "Theme Settings" %}</h4>
</div>
<div class='col-sm-6'>
{% if can_add_email %}
<h5>{% trans "Add Email Address" %}</h5>
<form method="post" action="{% url 'account_email' %}" class="add_email">
<form action='{% url "settings-appearance" %}' method='post'>
{% csrf_token %}
<label for="id_email" class=" requiredField">
E-mail<span class="asteriskField">*</span>
<input name='next' type='hidden' value='{% url "settings" %}'>
<label for='theme' class=' requiredField'>
{% trans "Select theme" %}
</label>
<div id="div_id_email" class="form-group input-group mb-3">
<div class='input-group-prepend'><span class='input-group-text'>@</span></div>
<input type="email" name="email" placeholder='{% trans "Enter e-mail address" %}' class="textinput textInput form-control" required="" id="id_email">
<div class='form-group input-group mb-3'>
<select id='theme' name='theme' class='select form-control'>
{% get_available_themes as themes %}
{% for theme in themes %}
<option value='{{ theme.key }}'>{{ theme.name }}</option>
{% endfor %}
</select>
<div class='input-group-append'>
<button class="btn btn-primary" name="action_add" type="submit">{% trans "Add Email" %}</button>
<input type="submit" value="{% trans 'Set Theme' %}" class="btn btn-primary">
</div>
</div>
</form>
{% endif %}
</div>
</div>
<div class='panel-heading'>
<h4>{% trans "Social Accounts" %}</h4>
</div>
<div>
{% if social_form.accounts %}
<p>{% blocktrans %}You can sign in to your account using any of the following third party accounts:{% endblocktrans %}</p>
<form method="post" action="{% url 'socialaccount_connections' %}">
{% csrf_token %}
<fieldset>
{% if social_form.non_field_errors %}
<div id="errorMsg">{{ social_form.non_field_errors }}</div>
{% endif %}
{% for base_account in social_form.accounts %}
{% with base_account.get_provider_account as account %}
<div>
<label for="id_account_{{ base_account.id }}">
<input id="id_account_{{ base_account.id }}" type="radio" name="account" value="{{ base_account.id }}"/>
<span class="socialaccount_provider {{ base_account.provider }} {{ account.get_brand.id }}">
<span class='brand-icon' brand_name='{{account.get_brand.id}}'></span>{{account.get_brand.name}}</span>
{{ account }}
</label>
<div class="row">
<div class='panel-heading'>
<h4>{% trans "Language Settings" %}</h4>
</div>
{% endwith %}
{% endfor %}
<div>
<button class="btn btn-primary" type="submit">{% trans 'Remove' %}</button>
</div>
</fieldset>
<div class="col">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{% url 'settings' %}">
<label for='language' class=' requiredField'>
{% trans "Select language" %}
</label>
<div class='form-group input-group mb-3'>
<select name="language" class="select form-control w-25">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% if 'alllang' in request.GET %}{% define True as ALL_LANG %}{% endif %}
{% for language in languages %}
{% define language.code as lang_code %}
{% define locale_stats|keyvalue:lang_code as lang_translated %}
{% if lang_translated > 10 or lang_code == 'en' or lang_code == LANGUAGE_CODE %}{% define True as use_lang %}{% else %}{% define False as use_lang %}{% endif %}
{% if ALL_LANG or use_lang %}
<option value="{{ lang_code }}"{% if lang_code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ lang_code }})
{% if lang_translated %}
{% blocktrans %}{{ lang_translated }}% translated{% endblocktrans %}
{% else %}
{% if lang_code == 'en' %}-{% else %}{% trans 'No translations available' %}{% endif %}
{% endif %}
</option>
{% endif %}
{% endfor %}
</select>
<div class='input-group-append'>
<input type="submit" value="{% trans 'Set Language' %}" class="btn btn btn-primary">
</div>
<p>{% trans "Some languages are not complete" %}
{% if ALL_LANG %}
. <a href="{% url 'settings' %}">{% trans "Show only sufficent" %}</a>
{% else %}
and hidden. <a href="?alllang">{% trans "Show them too" %}</a>
{% endif %}
</p>
</div>
</form>
{% else %}
<div class='alert alert-block alert-warning'>
{% trans "There are no social network accounts connected to your InvenTree account" %}
</div>
{% endif %}
<br>
<h4>{% trans 'Add a 3rd Party Account' %}</h4>
<div>
{% include "socialaccount/snippets/provider_list.html" with process="connect" %}
<div class="col-sm-6">
<h4>{% trans "Help the translation efforts!" %}</h4>
<p>{% blocktrans with link="https://crowdin.com/project/inventree" %}Native language translation of the
InvenTree web application is <a href="{{link}}">community contributed via crowdin</a>. Contributions are
welcomed and encouraged.{% endblocktrans %}</p>
</div>
{% include "socialaccount/snippets/login_extra.html" %}
<br>
</div>
<div class='panel-heading'>
<div class='d-flex flex-wrap'>
<h4>{% trans "Active Sessions" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% if session_list.count > 1 %}
<form method="post" action="{% url 'session_delete_other' %}">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-default btn-danger" title='{% trans "Log out active sessions (except this one)" %}'>
{% trans "Log Out Active Sessions" %}
</button>
</form>
{% endif %}
<div class="row">
<div class='panel-heading'>
<div class='d-flex flex-wrap'>
<h4>{% trans "Active Sessions" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% if session_list.count > 1 %}
<form method="post" action="{% url 'session_delete_other' %}">
{% csrf_token %}
<button type="submit" class="btn btn-sm btn-default btn-danger" title='{% trans "Log out active sessions (except this one)" %}'>
{% trans "Log Out Active Sessions" %}
</button>
</form>
{% endif %}
</div>
</div>
</div>
</div>
<div>
{% trans "<em>unknown on unknown</em>" as unknown_on_unknown %}
{% trans "<em>unknown</em>" as unknown %}
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans "IP Address" %}</th>
<th>{% trans "Device" %}</th>
<th>{% trans "Last Activity" %}</th>
</tr>
</thead>
{% for object in session_list %}
<tr {% if object.session_key == session_key %}class="active"{% endif %}>
<td>{{ object.ip }}</td>
<td>{{ object.user_agent|device|default_if_none:unknown_on_unknown|safe }}</td>
<td>
{% if object.session_key == session_key %}
{% blocktrans with time=object.last_activity|timesince %}{{ time }} ago (this session){% endblocktrans %}
{% else %}
{% blocktrans with time=object.last_activity|timesince %}{{ time }} ago{% endblocktrans %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<div>
{% trans "<em>unknown on unknown</em>" as unknown_on_unknown %}
{% trans "<em>unknown</em>" as unknown %}
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>{% trans "IP Address" %}</th>
<th>{% trans "Device" %}</th>
<th>{% trans "Last Activity" %}</th>
</tr>
</thead>
{% for object in session_list %}
<tr {% if object.session_key == session_key %}class="active"{% endif %}>
<td>{{ object.ip }}</td>
<td>{{ object.user_agent|device|default_if_none:unknown_on_unknown|safe }}</td>
<td>
{% if object.session_key == session_key %}
{% blocktrans with time=object.last_activity|timesince %}{{ time }} ago (this session){% endblocktrans %}
{% else %}
{% blocktrans with time=object.last_activity|timesince %}{{ time }} ago{% endblocktrans %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}
{% block js_ready %}
(function() {
var message = "{% trans 'Do you really want to remove the selected email address?' %}";
var actions = document.getElementsByName('action_remove');
if (actions.length) {
actions[0].addEventListener("click", function(e) {
if (! confirm(message)) {
e.preventDefault();
}
});
}
var message = "{% trans 'Do you really want to remove the selected email address?' %}";
var actions = document.getElementsByName('action_remove');
if (actions.length) {
actions[0].addEventListener("click", function(e) {
if (! confirm(message)) {
e.preventDefault();
}
});
}
})();
{% endblock %}

View File

@ -0,0 +1,15 @@
{% extends "account/base.html" %}
{% load i18n crispy_forms_tags %}
{% block content %}
<h1>{% trans "Two-Factor Authentication" %}</h1>
<form method="post" class="login">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">
{% trans 'Authenticate' %}
</button>
</form>
{% endblock %}

View File

@ -0,0 +1,33 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block content %}
<h3>
{% trans "Two-Factor Authentication Backup Tokens" %}
</h3>
{% if backup_tokens %}
{% if reveal_tokens %}
<ul>
{% for token in backup_tokens %}
<li>{{ token.token }}</li>
{% endfor %}
</ul>
{% else %}
{% trans 'Backup tokens have been generated, but are not revealed here for security reasons. Press the button below to generate new ones.' %}
{% endif %}
{% else %}
{% trans 'No tokens. Press the button below to generate some.' %}
{% endif %}
<br>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-primary w-100">
{% trans 'Generate backup tokens' %}
</button>
</form>
<br>
<a href="{% url 'settings' %}" class="btn btn-secondary w-100 btn-sm">{% trans "back to settings" %}</a>
{% endblock %}

View File

@ -0,0 +1,18 @@
{% extends "account/base.html" %}
{% load i18n %}
{% block content %}
<h3>
{% trans "Disable Two-Factor Authentication" %}
</h3>
<p>{% trans "Are you sure?" %}</p>
<form method="post">
{% csrf_token %}
<button type="submit" class="btn btn-danger w-100">
{% trans 'Disable Two-Factor' %}
</button>
</form>
{% endblock %}

View File

@ -0,0 +1,42 @@
{% extends "account/base.html" %}
{% load i18n crispy_forms_tags %}
{% block content %}
<h3>
{% trans "Setup Two-Factor Authentication" %}
</h3>
<h4>
{% trans 'Step 1' %}:
</h4>
<p>
{% trans 'Scan the QR code below with a token generator of your choice (for instance Google Authenticator).' %}
</p>
<div class="bg-light rounded">
<img src="{{ qr_code_url }}" class="mx-auto d-block"/>
</div>
<br>
<h4>
{% trans 'Step 2' %}:
</h4>
<p>
{% trans 'Input a token generated by the app:' %}
</p>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary btn-block w-100">
{% trans 'Verify' %}
</button>
</form>
<div>
<a href="{% url 'settings' %}" class="btn btn-secondary w-100 btn-sm mt-3">{% trans "back to settings" %}</a>
</div>
{% endblock %}

View File

@ -175,7 +175,6 @@ function enableBreadcrumbTree(options) {
for (var i = 0; i < data.length; i++) {
node = data[i];
node.nodes = [];
nodes[node.pk] = node;
node.selectable = false;
@ -193,10 +192,17 @@ function enableBreadcrumbTree(options) {
node = data[i];
if (node.parent != null) {
nodes[node.parent].nodes.push(node);
if (nodes[node.parent].nodes) {
nodes[node.parent].nodes.push(node);
} else {
nodes[node.parent].nodes = [node];
}
if (node.state.expanded) {
nodes[node.parent].state.expanded = true;
while (node.parent != null) {
nodes[node.parent].state.expanded = true;
node = nodes[node.parent];
}
}
} else {
@ -212,7 +218,6 @@ function enableBreadcrumbTree(options) {
collapseIcon: 'fa fa-chevron-down',
});
setBreadcrumbTreeState(label, state);
}
}
);
@ -220,26 +225,11 @@ function enableBreadcrumbTree(options) {
$('#breadcrumb-tree-toggle').click(function() {
// Add callback to "collapse" and "expand" the sidebar
// By default, the menu is "expanded"
var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded';
// Toggle treeview visibilty
$('#breadcrumb-tree-collapse').toggle();
// We wish to "toggle" the state!
setBreadcrumbTreeState(label, state == 'expanded' ? 'collapsed' : 'expanded');
});
// Set the initial state (default = expanded)
var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded';
function setBreadcrumbTreeState(label, state) {
if (state == 'collapsed') {
$('#breadcrumb-tree-collapse').hide(100);
} else {
$('#breadcrumb-tree-collapse').show(100);
}
localStorage.setItem(`inventree-tree-state-${label}`, state);
}
}
/*

View File

@ -2,6 +2,7 @@
/* globals
constructForm,
exportFormatOptions,
imageHoverIcon,
inventreeGet,
inventreePut,
@ -14,6 +15,8 @@
*/
/* exported
downloadBomTemplate,
exportBom,
newPartFromBomWizard,
loadBomTable,
loadUsedInTable,
@ -21,12 +24,121 @@
removeColFromBomWizard,
*/
/* BOM management functions.
* Requires follwing files to be loaded first:
* - api.js
* - part.js
* - modals.js
function downloadBomTemplate(options={}) {
var format = options.format;
if (!format) {
format = inventreeLoad('bom-export-format', 'csv');
}
constructFormBody({}, {
title: '{% trans "Download BOM Template" %}',
fields: {
format: {
label: '{% trans "Format" %}',
help_text: '{% trans "Select file format" %}',
required: true,
type: 'choice',
value: format,
choices: exportFormatOptions(),
}
},
onSubmit: function(fields, opts) {
var format = getFormFieldValue('format', fields['format'], opts);
// Save the format for next time
inventreeSave('bom-export-format', format);
// Hide the modal
$(opts.modal).modal('hide');
// Download the file
location.href = `{% url "bom-upload-template" %}?format=${format}`;
}
});
}
/**
* Export BOM (Bill of Materials) for the specified Part instance
*/
function exportBom(part_id, options={}) {
constructFormBody({}, {
title: '{% trans "Export BOM" %}',
fields: {
format: {
label: '{% trans "Format" %}',
help_text: '{% trans "Select file format" %}',
required: true,
type: 'choice',
value: inventreeLoad('bom-export-format', 'csv'),
choices: exportFormatOptions(),
},
cascading: {
label: '{% trans "Cascading" %}',
help_text: '{% trans "Download cascading / multi-level BOM" %}',
type: 'boolean',
value: inventreeLoad('bom-export-cascading', true),
},
levels: {
label: '{% trans "Levels" %}',
help_text: '{% trans "Select maximum number of BOM levels to export (0 = all levels)" %}',
type: 'integer',
value: 0,
min_value: 0,
},
parameter_data: {
label: '{% trans "Include Parameter Data" %}',
help_text: '{% trans "Include part parameter data in exported BOM" %}',
type: 'boolean',
value: inventreeLoad('bom-export-parameter_data', false),
},
stock_data: {
label: '{% trans "Include Stock Data" %}',
help_text: '{% trans "Include part stock data in exported BOM" %}',
type: 'boolean',
value: inventreeLoad('bom-export-stock_data', false),
},
manufacturer_data: {
label: '{% trans "Include Manufacturer Data" %}',
help_text: '{% trans "Include part manufacturer data in exported BOM" %}',
type: 'boolean',
value: inventreeLoad('bom-export-manufacturer_data', false),
},
supplier_data: {
label: '{% trans "Include Supplier Data" %}',
help_text: '{% trans "Include part supplier data in exported BOM" %}',
type: 'boolean',
value: inventreeLoad('bom-export-supplier_data', false),
}
},
onSubmit: function(fields, opts) {
// Extract values from the form
var field_names = ['format', 'cascading', 'levels', 'parameter_data', 'stock_data', 'manufacturer_data', 'supplier_data'];
var url = `/part/${part_id}/bom-download/?`;
field_names.forEach(function(fn) {
var val = getFormFieldValue(fn, fields[fn], opts);
// Update user preferences
inventreeSave(`bom-export-${fn}`, val);
url += `${fn}=${val}&`;
});
$(opts.modal).modal('hide');
// Redirect to the BOM file download
location.href = url;
}
});
}
function bomItemFields() {

View File

@ -811,7 +811,9 @@ function updateFieldValue(name, value, field, options) {
switch (field.type) {
case 'boolean':
el.prop('checked', value);
if (value == true || value.toString().toLowerCase() == 'true') {
el.prop('checked');
}
break;
case 'related field':
// Clear?
@ -2034,8 +2036,15 @@ function constructInputOptions(name, classes, type, parameters) {
}
if (parameters.value != null) {
// Existing value?
opts.push(`value='${parameters.value}'`);
if (parameters.type == 'boolean') {
// Special consideration of a boolean (checkbox) value
if (parameters.value == true || parameters.value.toString().toLowerCase() == 'true') {
opts.push('checked');
}
} else {
// Existing value?
opts.push(`value='${parameters.value}'`);
}
} else if (parameters.default != null) {
// Otherwise, a defualt value?
opts.push(`value='${parameters.default}'`);