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

Merge branch 'master' of https://github.com/inventree/InvenTree into price-history

This commit is contained in:
2021-04-14 21:18:21 +02:00
127 changed files with 6565 additions and 2780 deletions

View File

@ -131,6 +131,7 @@ addHeaderAction('stock-to-build', '{% trans "Required for Build Orders" %}', 'fa
loadStockTable($('#table-recently-updated-stock'), {
params: {
part_detail: true,
ordering: "-updated",
max_results: {% settings_value "STOCK_RECENT_COUNT" %},
},

View File

@ -133,14 +133,14 @@ InvenTree | {% trans "Search Results" %}
columns: [
{
field: 'name',
title: 'Name',
title: '{% trans "Name" %}',
formatter: function(value, row, index, field) {
return renderLink(value, '/part/category/' + row.pk + '/');
},
},
{
field: 'description',
title: 'Description',
title: '{% trans "Description" %}',
},
],
});
@ -270,14 +270,14 @@ InvenTree | {% trans "Search Results" %}
columns: [
{
field: 'name',
title: 'Name',
title: '{% trans "Name" %}',
formatter: function(value, row, index, field) {
return renderLink(row.pathstring, '/stock/location/' + row.pk + '/');
},
},
{
field: 'description',
title: 'Description',
title: '{% trans "Description" %}',
},
],
});

View File

@ -8,7 +8,7 @@
<span class='fas {{ icon }}'></span>
{% endif %}
</td>
<td><b>{{ setting.name }}</b></td>
<td><b>{% trans setting.name %}</b></td>
<td>
{% if setting.is_bool %}
<div>
@ -24,7 +24,7 @@
{% endif %}
{% endif %}
<td>
{{ setting.description }}
{% trans setting.description %}
</td>
<td>
<div class='btn-group float-right'>

View File

@ -19,20 +19,35 @@
<col width='25'>
<tr>
<td><span class='fas fa-hashtag'></span></td>
<td>{% trans "InvenTree Version" %}</td><td><a href="https://github.com/inventree/InvenTree/releases">{% inventree_version %}</a></td>
<td>{% trans "InvenTree Version" %}</td>
<td>
<a href="https://github.com/inventree/InvenTree/releases">{% inventree_version %}</a>
{% if up_to_date %}
<span class='label label-green float-right'>{% trans "Up to Date" %}</span>
{% else %}
<span class='label label-red float-right'>{% trans "Update Available" %}</span>
{% endif %}
</td>
</tr>
<tr>
<td><span class='fas fa-hashtag'></span></td>
<td>{% trans "Django Version" %}</td><td><a href="https://www.djangoproject.com/">{% django_version %}</a></td>
<td>{% trans "Django Version" %}</td>
<td><a href="https://www.djangoproject.com/">{% django_version %}</a></td>
</tr>
{% inventree_commit_hash as hash %}
{% if hash %}
<tr>
<td><span class='fas fa-code-branch'></span></td>
<td>{% trans "Commit Hash" %}</td><td><a href="https://github.com/inventree/InvenTree/commit/{% inventree_commit_hash %}">{% inventree_commit_hash %}</a></td>
<td>{% trans "Commit Hash" %}</td><td>{{ hash }}</td>
</tr>
{% endif %}
{% inventree_commit_date as commit_date %}
{% if commit_date %}
<tr>
<td><span class='fas fa-calendar-alt'></span></td>
<td>{% trans "Commit Date" %}</td><td>{% inventree_commit_date %}</td>
<td>{% trans "Commit Date" %}</td><td>{{ commit_date }}</td>
</tr>
{% endif %}
<tr>
<td><span class='fas fa-book'></span></td>
<td>{% trans "InvenTree Documentation" %}</td>
@ -63,4 +78,4 @@
</div>
</div>
</div>
</div>
</div>

View File

@ -134,13 +134,13 @@ InvenTree
<script type='text/javascript' src='{% static "bootstrap-table/extensions/treegrid/bootstrap-table-treegrid.js" %}'></script>
<script type="text/javascript" src="{% static 'fullcalendar/main.js' %}"></script>
<script type="text/javascript" src="{% static 'fullcalendar/locales-all.js' %}"></script>
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
<script type='text/javascript' src="{% static 'script/moment.js' %}"></script>
<script type='text/javascript' src="{% static 'script/chart.min.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/inventree.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/api.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/filters.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/notification.js' %}"></script>
<script type='text/javascript' src="{% static 'script/inventree/sidenav.js' %}"></script>
@ -157,6 +157,7 @@ InvenTree
<script type='text/javascript' src="{% url 'calendar.js' %}"></script>
<script type='text/javascript' src="{% url 'tables.js' %}"></script>
<script type='text/javascript' src="{% url 'table_filters.js' %}"></script>
<script type='text/javascript' src="{% url 'filters.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
@ -181,6 +182,7 @@ $(document).ready(function () {
});
{% endif %}
moment.locale('{{request.LANGUAGE_CODE}}');
});
</script>

View File

@ -0,0 +1,419 @@
{% load i18n %}
/**
* Code for managing query filters / table options.
*
* Optional query filters are available to the user for various
* tables display in the web interface.
* These filters are saved to the web session, and should be
* persistent for a given table type.
*
* This makes use of the 'inventreeSave' and 'inventreeLoad' functions
* for writing to and reading from session storage.
*
*/
function defaultFilters() {
return {
stock: "cascade=1&in_stock=1",
build: "",
parts: "cascade=1",
company: "",
salesorder: "",
purchaseorder: "",
};
}
/**
* Load table filters for the given table from session storage
*
* @param tableKey - String key for the particular table
* @param defaults - Default filters for this table e.g. 'cascade=1&location=5'
*/
function loadTableFilters(tableKey) {
var lookup = "table-filters-" + tableKey.toLowerCase();
var defaults = defaultFilters()[tableKey] || '';
var filterstring = inventreeLoad(lookup, defaults);
var filters = {};
filterstring.split("&").forEach(function(item, index) {
item = item.trim();
if (item.length > 0) {
var f = item.split('=');
if (f.length == 2) {
filters[f[0]] = f[1];
} else {
console.log(`Improperly formatted filter: ${item}`);
}
}
});
return filters;
}
/**
* Save table filters to session storage
*
* @param {*} tableKey - string key for the given table
* @param {*} filters - object of string:string pairs
*/
function saveTableFilters(tableKey, filters) {
var lookup = "table-filters-" + tableKey.toLowerCase();
var strings = [];
for (var key in filters) {
strings.push(`${key.trim()}=${String(filters[key]).trim()}`);
}
var filterstring = strings.join('&');
inventreeSave(lookup, filterstring);
}
/*
* Remove a named filter parameter
*/
function removeTableFilter(tableKey, filterKey) {
var filters = loadTableFilters(tableKey);
delete filters[filterKey];
saveTableFilters(tableKey, filters);
// Return a copy of the updated filters
return filters;
}
function addTableFilter(tableKey, filterKey, filterValue) {
var filters = loadTableFilters(tableKey);
filters[filterKey] = filterValue;
saveTableFilters(tableKey, filters);
// Return a copy of the updated filters
return filters;
}
/*
* Clear all the custom filters for a given table
*/
function clearTableFilters(tableKey) {
saveTableFilters(tableKey, {});
return {};
}
/*
* Return a list of the "available" filters for a given table key.
* A filter is "available" if it is not already being used to filter the table.
* Once a filter is selected, it will not be returned here.
*/
function getRemainingTableFilters(tableKey) {
var filters = loadTableFilters(tableKey);
var remaining = getAvailableTableFilters(tableKey);
for (var key in filters) {
// Delete the filter if it is already in use
delete remaining[key];
}
return remaining;
}
/*
* Return the filter settings for a given table and key combination.
* Return empty object if the combination does not exist.
*/
function getFilterSettings(tableKey, filterKey) {
return getAvailableTableFilters(tableKey)[filterKey] || {};
}
/*
* Return a set of key:value options for the given filter.
* If no options are specified (e.g. for a number field),
* then a null object is returned.
*/
function getFilterOptionList(tableKey, filterKey) {
var settings = getFilterSettings(tableKey, filterKey);
if (settings.type == 'bool') {
return {
'1': {
key: '1',
value: 'true',
},
'0': {
key: '0',
value: 'false',
},
};
} else if ('options' in settings) {
return settings.options;
}
return null;
}
/*
* Generate a list of <option> tags for the given table.
*/
function generateAvailableFilterList(tableKey) {
var remaining = getRemainingTableFilters(tableKey);
var id = 'filter-tag-' + tableKey.toLowerCase();
var html = `<select class='form-control filter-input' id='${id}' name='tag'>`;
html += "<option value=''>{% trans 'Select filter' %}</option>";
for (var opt in remaining) {
var title = getFilterTitle(tableKey, opt);
html += `<option value='${opt}'>${title}</option>`;
}
html += `</select>`;
return html;
}
/*
* Generate an input for setting the value of a given filter.
*/
function generateFilterInput(tableKey, filterKey) {
var id = 'filter-value-' + tableKey.toLowerCase();
if (filterKey == null || filterKey.length == 0) {
// Return an 'empty' element
return `<div class='filter-input' id='${id}'></div>`;
}
var options = getFilterOptionList(tableKey, filterKey);
var html = '';
// A 'null' options list means that a simple text-input dialog should be used
if (options == null) {
html = `<input class='form-control filter-input' id='${id}' name='value'></input>`;
} else {
// Return a 'select' input with the available values
html = `<select class='form-control filter-input' id='${id}' name='value'>`;
for (var key in options) {
option = options[key];
html += `<option value='${key}'>${option.value}</option>`;
}
html += `</select>`;
}
return html;
}
/**
* Configure a filter list for a given table
*
* @param {*} tableKey - string lookup key for filter settings
* @param {*} table - bootstrapTable element to update
* @param {*} target - name of target element on page
*/
function setupFilterList(tableKey, table, target) {
var addClicked = false;
if (target == null || target.length == 0) {
target = `#filter-list-${tableKey}`;
}
var tag = `filter-tag-${tableKey}`;
var add = `filter-add-${tableKey}`;
var clear = `filter-clear-${tableKey}`;
var make = `filter-make-${tableKey}`;
var filters = loadTableFilters(tableKey);
var element = $(target);
// One blank slate, please
element.empty();
element.append(`<button id='${add}' title='{% trans "Add new filter" %}' class='btn btn-default filter-tag'><span class='fas fa-filter'></span></button>`);
if (Object.keys(filters).length > 0) {
element.append(`<button id='${clear}' title='{% trans "Clear all filters" %}' class='btn btn-default filter-tag'><span class='fas fa-trash-alt'></span></button>`);
}
for (var key in filters) {
var value = getFilterOptionValue(tableKey, key, filters[key]);
var title = getFilterTitle(tableKey, key);
var description = getFilterDescription(tableKey, key);
element.append(`<div title='${description}' class='filter-tag'>${title} = ${value}<span ${tag}='${key}' class='close'>x</span></div>`);
}
// Add a callback for adding a new filter
element.find(`#${add}`).click(function clicked() {
if (!addClicked) {
addClicked = true;
var html = '';
//`<div class='filter-input'>`;
html += generateAvailableFilterList(tableKey);
html += generateFilterInput(tableKey);
html += `<button title='{% trans "Create filter" %}' class='btn btn-default filter-tag' id='${make}'><span class='fas fa-plus'></span></button>`;
//html += '</div>';
element.append(html);
// Add a callback for when the filter tag selection is changed
element.find(`#filter-tag-${tableKey}`).on('change', function() {
var list = element.find(`#filter-value-${tableKey}`);
list.replaceWith(generateFilterInput(tableKey, this.value));
});
// Add a callback for when the new filter is created
element.find(`#filter-make-${tableKey}`).click(function() {
var tag = element.find(`#filter-tag-${tableKey}`).val();
var val = element.find(`#filter-value-${tableKey}`).val();
// Only add the new filter if it is not empty!
if (tag && tag.length > 0) {
var filters = addTableFilter(tableKey, tag, val);
reloadTable(table, filters);
// Run this function again
setupFilterList(tableKey, table, target);
}
});
} else {
addClicked = false;
setupFilterList(tableKey, table, target);
}
});
// Add a callback for clearing all the filters
element.find(`#${clear}`).click(function() {
var filters = clearTableFilters(tableKey);
reloadTable(table, filters);
setupFilterList(tableKey, table, target);
});
// Add callback for deleting each filter
element.find(".close").click(function(event) {
var me = $(this);
var filter = me.attr(`filter-tag-${tableKey}`);
var filters = removeTableFilter(tableKey, filter);
reloadTable(table, filters);
// Run this function again!
setupFilterList(tableKey, table, target);
});
}
/**
* Return the pretty title for the given table and filter selection.
* If no title is provided, default to the key value.
*
*/
function getFilterTitle(tableKey, filterKey) {
var settings = getFilterSettings(tableKey, filterKey);
return settings.title || 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.
*/
function getFilterDescription(tableKey, filterKey) {
var settings = getFilterSettings(tableKey, filterKey);
return settings.description || filterKey;
}
/*
* Return the display value for a particular option
*/
function getFilterOptionValue(tableKey, filterKey, valueKey) {
var filter = getFilterSettings(tableKey, filterKey);
var value = String(valueKey);
// Lookup for boolean options
if (filter.type == 'bool') {
if (value == '1') return 'true';
if (value == '0') return 'false';
return value;
}
// Iterate through a list of options
if ('options' in filter) {
for (var key in filter.options) {
if (key == valueKey) {
return filter.options[key].value;
}
}
// Could not find a match
return value;
}
// Cannot map to a display string - return the original text
return value;
}

View File

@ -253,7 +253,7 @@ function loadingMessageContent() {
*/
// TODO - This can be made a lot better
return "<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> Waiting for server...";
return "<span class='glyphicon glyphicon-refresh glyphicon-refresh-animate'></span> {% trans 'Waiting for server...' %}";
}

View File

@ -241,7 +241,6 @@ function loadStockTable(table, options) {
// List of user-params which override the default filters
options.params['part_detail'] = true;
options.params['location_detail'] = true;
var params = options.params || {};
@ -524,7 +523,8 @@ function loadStockTable(table, options) {
title: '{% trans "Part" %}',
sortName: 'part__name',
sortable: true,
switchable: false,
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
var url = `/stock/item/${row.pk}/`;
@ -543,6 +543,8 @@ function loadStockTable(table, options) {
title: 'IPN',
sortName: 'part__IPN',
sortable: true,
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
return row.part_detail.IPN;
},
@ -550,6 +552,8 @@ function loadStockTable(table, options) {
{
field: 'part_detail.description',
title: '{% trans "Description" %}',
visible: params['part_detail'],
switchable: params['part_detail'],
formatter: function(value, row, index, field) {
return row.part_detail.description;
}
@ -976,8 +980,8 @@ function loadStockTrackingTable(table, options) {
formatter: function(value, row, index, field) {
// Manually created entries can be edited or deleted
if (!row.system) {
var bEdit = "<button title='Edit tracking entry' class='btn btn-entry-edit btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
var bDel = "<button title='Delete tracking entry' class='btn btn-entry-delete btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
var bEdit = "<button title='{% trans 'Edit tracking entry' %}' class='btn btn-entry-edit btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
var bDel = "<button title='{% trans 'Delete tracking entry' %}' class='btn btn-entry-delete btn-default btn-glyph' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
return "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
} else {

View File

@ -60,7 +60,9 @@
<li class='dropdown'>
<a class='dropdown-toggle' data-toggle='dropdown' href="#">
{% if not system_healthy %}
<span title='{% trans "InvenTree server issues detected" %}' class='fas fa-exclamation-triangle icon-red'></span>
<span class='fas fa-exclamation-triangle icon-red'></span>
{% elif not up_to_date %}
<span class='fas fa-info-circle icon-green'></span>
{% endif %}
<span class="fas fa-user"></span> <b>{{ user.get_username }}</b></a>
<ul class='dropdown-menu'>
@ -78,11 +80,20 @@
{% if system_healthy %}
<span class='fas fa-server'>
{% else %}
<span class='fas fa-exclamation-triangle icon-red'>
<span class='fas fa-server icon-red'>
{% endif %}
</span> {% trans "System Information" %}
</a></li>
<li id='launch-about'><a href='#'><span class="fas fa-info-circle"></span> {% trans "About InvenTree" %}</a></li>
<li id='launch-about'>
<a href='#'>
{% if up_to_date %}
<span class="fas fa-info-circle">
{% else %}
<span class='fas fa-info-circle icon-red'>
{% endif %}
</span> {% trans "About InvenTree" %}
</a>
</li>
</ul>
</li>
</ul>

View File

@ -1 +1 @@
<button type='button' class='btn btn-default' id='show-qr-code' title='Show QR code'><span class='fas fa-qrcode'></span></button>
<button type='button' class='btn btn-default' id='show-qr-code' title='{% trans "Show QR Code" %}'><span class='fas fa-qrcode'></span></button>

View File

@ -0,0 +1,59 @@
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<style>
.login-error {
color: #F88;
}
</style>
<title>
InvenTree
</title>
</head>
<body class='login-screen'>
<div class='main body-wrapper login-screen'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>InvenTree</h3></span>
</div>
<hr>
<div class='container-fluid'>
<p>{% trans "You have been logged out" %}</p>
<p><a href='{% url "login" %}'>{% trans "Return to login screen" %}</a></p>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -89,7 +89,12 @@
<button class='pull-right btn btn-primary login-button' type="submit">{% trans "Login" %}</button>
</form>
{% if email_configured %}
<hr><br>
<p>{% trans "Forgotten your password?" %} - <a href='{% url "password_reset" %}'>{% trans "Click here to reset" %}</a></p>
</div>
{% endif %}
</div>
</div>
</div>

View File

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h4>{% trans "Logout" %}</h4>
<p>{% trans "You have been logged out" %}</p>
<p>{% trans 'Click' %} <a href="{% url 'login' %}"> {% trans 'here</a> to log in</p>' %}
{% endblock %}

View File

@ -0,0 +1,59 @@
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<style>
.login-error {
color: #F88;
}
</style>
<title>
InvenTree
</title>
</head>
<body class='login-screen'>
<div class='main body-wrapper login-screen'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>InvenTree</h3></span>
</div>
<hr>
<div class='container-fluid'>
<p>{% trans "Password reset complete" %}</p>
<p><a href='{% url "login" %}'>{% trans "Return to login screen" %}</a></p>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,69 @@
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<style>
.login-error {
color: #F88;
}
</style>
<title>
InvenTree
</title>
</head>
<body class='login-screen'>
<div class='main body-wrapper login-screen'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>InvenTree</h3></span>
</div>
<hr>
<div class='container-fluid'>
{% if validlink %}
<h3>{% trans "Change password" %}</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit">{% trans "Change password" %}</button>
</form>
{% else %}
<p>
{% trans "The password reset link was invalid, possibly because it has already been used. Please request a new password reset." %}
</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,65 @@
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<style>
.login-error {
color: #F88;
}
</style>
<title>
InvenTree
</title>
</head>
<body class='login-screen'>
<div class='main body-wrapper login-screen'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>InvenTree</h3></span>
</div>
<hr>
<div class='container-fluid'>
<p>
{% trans "We've emailed you instructions for setting your password, if an account exists with the email you entered. You should receive them shortly." %}
</p>
<p>
{% trans "If you don't receive an email, please make sure you've entered the address you registered with, and check your spam folder." %}
</p>
<hr>
<a href='{% url "login" %}'>{% trans "Return to login screen" %}</a>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,68 @@
{% load static %}
{% load i18n %}
{% load crispy_forms_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/bootstrap_3.3.7_css_bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'css/select2.css' %}">
<link rel="stylesheet" href="{% static 'css/bootstrap-table.css' %}">
<link rel="stylesheet" href="{% static 'css/inventree.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/brands.css' %}">
<link rel="stylesheet" href="{% static 'fontawesome/css/solid.css' %}">
<script type='text/javascript' src="{% static 'fontawesome/js/solid.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/brands.js' %}"></script>
<script type='text/javascript' src="{% static 'fontawesome/js/fontawesome.js' %}"></script>
<style>
.login-error {
color: #F88;
}
</style>
<title>
InvenTree
</title>
</head>
<body class='login-screen'>
<div class='main body-wrapper login-screen'>
<div class='login-container'>
<div class="row">
<div class='container-fluid'>
<div class='clearfix content-heading login-header'>
<img class="pull-left" src="{% static 'img/inventree.png' %}" width="60" height="60"/>
<span><h3>InvenTree</h3></span>
</div>
<hr>
<div class='container-fluid'>
<p>{% trans "Forgotten your password?" %}</p>
<p>{% trans "Enter your email address below." %}</p>
<p>{% trans "An email will be sent with password reset instructions." %}</p>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-primary" type="submit">{% trans "Send email" %}</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>

View File

@ -13,8 +13,9 @@
<td>{% trans "Instance Name" %}</td>
<td>{% inventree_instance_name %}</td>
</tr>
{% if user.is_staff %}
<tr>
<td><span class='fas fa-exclamation-triangle'></span></td>
<td><span class='fas fa-server'></span></td>
<td>{% trans "Server status" %}</td>
<td>
{% if system_healthy %}
@ -24,6 +25,29 @@
{% endif %}
</td>
</tr>
{% if not django_q_running %}
<tr>
<td><span class='fas fa-tasks'></span></td>
<td>{% trans "Background Worker" %}</td>
<td>
<a href='https://inventree.readthedocs.io/en/latest/admin/tasks'>
<span class='label label-red'>{% trans "Background worker not running" %}</span>
</a>
</td>
</tr>
{% endif %}
{% if not email_configured %}
<tr>
<td><span class='fas fa-envelope'></span></td>
<td>{% trans "Email Settings" %}</td>
<td>
<a href='https://inventree.readthedocs.io/en/latest/admin/email'>
<span class='label label-red'>{% trans "Email settings not configured" %}</span>
</a>
</td>
</tr>
{% endif %}
{% endif %}
{% if not system_healthy %}
{% for issue in system_issues %}