Complete refactor of the test-result table for stock item

This commit is contained in:
Oliver Walters 2020-05-17 21:09:49 +10:00
parent b9799e1824
commit 8ace71ef56
4 changed files with 151 additions and 65 deletions

View File

@ -22,7 +22,7 @@ from .settings import MEDIA_URL, STATIC_URL
def generateTestKey(test_name): def generateTestKey(test_name):
""" """
Generate a test 'key' for a given test name. Generate a test 'key' for a given test name.
This must not have spaces as it will be used for dict lookup in a template. This must not have illegal chars as it will be used for dict lookup in a template.
Tests must be named such that they will have unique keys. Tests must be named such that they will have unique keys.
""" """
@ -30,6 +30,9 @@ def generateTestKey(test_name):
key = test_name.strip().lower() key = test_name.strip().lower()
key = key.replace(" ", "") key = key.replace(" ", "")
# Remove any characters that cannot be used to represent a variable
key = re.sub(r'[^a-zA-Z0-9]', '', key)
return key return key

View File

@ -7,7 +7,7 @@
{% include "stock/tabs.html" with tab='tests' %} {% include "stock/tabs.html" with tab='tests' %}
<h4>{% trans "Test Results" %}</h4> <h4>{% trans "Test Data" %}</h4>
<hr> <hr>
<div id='button-toolbar'> <div id='button-toolbar'>
@ -30,11 +30,8 @@
loadStockTestResultsTable( loadStockTestResultsTable(
$("#test-result-table"), { $("#test-result-table"), {
params: { part: {{ item.part.id }},
stock_item: {{ item.id }}, stock_item: {{ item.id }},
user_detail: true,
attachment_detail: true,
},
} }
); );
@ -53,6 +50,21 @@ $("#add-test-result").click(function() {
); );
}); });
$("#test-result-table").on('click', '.button-test-add', function() {
var button = $(this);
var test_name = button.attr('pk');
launchModalForm(
"{% url 'stock-item-test-create' %}", {
data: {
stock_item: {{ item.id }},
test: test_name
},
}
);
});
$("#test-result-table").on('click', '.button-test-edit', function() { $("#test-result-table").on('click', '.button-test-edit', function() {
var button = $(this); var button = $(this);

View File

@ -254,6 +254,8 @@ class StockItemTestResultCreate(AjaxCreateView):
except (ValueError, StockItem.DoesNotExist): except (ValueError, StockItem.DoesNotExist):
pass pass
initials['test'] = self.request.GET.get('test', '')
return initials return initials
def get_form(self): def get_form(self):

View File

@ -22,79 +22,98 @@ function removeStockRow(e) {
function passFailBadge(result) { function passFailBadge(result) {
if (result) { if (result) {
return `<span class='label label-green'>{% trans "PASS" %}</span>`; return `<span class='label label-green float-right'>{% trans "PASS" %}</span>`;
} else { } else {
return `<span class='label label-red'>{% trans "FAIL" %}</span>`; return `<span class='label label-red float-right'>{% trans "FAIL" %}</span>`;
} }
} }
function noResultBadge() {
return `<span class='label label-blue float-right'>{% trans "NO RESULT" %}</span>`;
}
function testKey(test_name) {
// Convert test name to a unique key without any illegal chars
test_name = test_name.trim().toLowerCase();
test_name = test_name.replace(' ', '');
test_name = test_name.replace(/[^0-9a-z]/gi, '');
return test_name;
}
function loadStockTestResultsTable(table, options) { function loadStockTestResultsTable(table, options) {
/* /*
* Load StockItemTestResult table * Load StockItemTestResult table
*/ */
var params = options.params || {}; function formatDate(row) {
// Function for formatting date field
var html = row.date;
// HTML element to setup the filtering if (row.user_detail) {
var filterListElement = options.filterList || '#filter-list-stocktests'; html += `<span class='badge'>${row.user_detail.username}</span>`;
var filters = {};
filters = loadTableFilters("stocktests");
var original = {};
for (var key in params) {
original[key] = params[key];
} }
setupFilterList("stocktests", table, filterListElement);
// Override the default values, or add new ones
for (var key in params) {
filters[key] = params[key];
}
table.inventreeTable({
method: 'get',
formatNoMatches: function() {
return '{% trans "No test results matching query" %}';
},
url: "{% url 'api-stock-test-result-list' %}",
queryParams: filters,
original: original,
columns: [
{
field: 'pk',
title: 'ID',
visible: false
},
{
field: 'test',
title: '{% trans "Test" %}',
sortable: true,
formatter: function(value, row) {
var html = value;
if (row.attachment_detail) { if (row.attachment_detail) {
html += `<a href='${row.attachment_detail.attachment}'><span class='fas fa-file-alt label-right'></span></a>`; html += `<a href='${row.attachment_detail.attachment}'><span class='fas fa-file-alt label-right'></span></a>`;
} }
return html; return html;
}
function makeButtons(row, grouped) {
var html = `<div class='btn-group float-right' role='group'>`;
html += makeIconButton('fa-plus icon-green', 'button-test-add', row.test_name, '{% trans "Add test result" %}');
if (!grouped) {
var pk = row.pk;
html += makeIconButton('fa-edit icon-blue', 'button-test-edit', pk, '{% trans "Edit test result" %}');
html += makeIconButton('fa-trash-alt icon-red', 'button-test-delete', pk, '{% trans "Delete test result" %}');
}
html += "</div>";
return html;
}
// First, load all the test templates
table.inventreeTable({
url: "{% url 'api-part-test-template-list' %}",
method: 'get',
formatNoMatches: function() {
return "{% trans 'No test results found' %}";
}, },
queryParams: {
part: options.part,
},
columns: [
{
field: 'pk',
title: 'ID',
visible: false,
}, },
{ {
field: 'result', field: 'test_name',
title: "{% trans "Result" %}", title: "{% trans "Test Name" %}",
sortable: true, sortable: true,
formatter: function(value) { formatter: function(value, row) {
return passFailBadge(value); var html = value;
if (row.result == null) {
html += noResultBadge();
} else {
html += passFailBadge(row.result);
}
return html;
} }
}, },
{ {
field: 'value', field: 'value',
title: "{% trans "Value" %}", title: '{% trans "Value" %}',
sortable: true,
}, },
{ {
field: 'notes', field: 'notes',
@ -102,35 +121,85 @@ function loadStockTestResultsTable(table, options) {
}, },
{ {
field: 'date', field: 'date',
title: '{% trans "Uploaded" %}', title: '{% trans "Test Date" %}',
sortable: true,
formatter: function(value, row) { formatter: function(value, row) {
var html = value; return formatDate(row);
if (row.user_detail) {
html += `<span class='badge'>${row.user_detail.username}</span>`;
}
return html;
} }
}, },
{ {
field: 'buttons', field: 'buttons',
formatter: function(value, row) { formatter: function(value, row) {
return makeButtons(row, false);
var pk = row.pk;
var html = `<div class='btn-group float-right' role='group'>`;
html += makeIconButton('fa-edit icon-blue', 'button-test-edit', pk, '{% trans "Edit test result" %}');
html += makeIconButton('fa-trash-alt icon-red', 'button-test-delete', pk, '{% trans "Delete test result" %}');
html += `</div>`;
return html;
} }
}, },
] ],
groupBy: true,
groupByField: 'test_name',
groupByFormatter: function(field, id, data) {
// Extract the "latest" row (data are returned in date order from the server)
var latest = data[data.length-1];
switch (field) {
case 'test_name':
return latest.test_name + ` <i>(${data.length})</i>` + passFailBadge(latest.result);
case 'value':
return latest.value;
case 'notes':
return latest.notes;
case 'date':
return formatDate(latest);
case 'buttons':
// Buttons are done differently for grouped rows
return makeButtons(latest, true);
default:
return "---";
}
},
onLoadSuccess: function(tableData) {
// Once the test template data are loaded, query for results
inventreeGet(
"{% url 'api-stock-test-result-list' %}",
{
stock_item: options.stock_item,
user_detail: true,
attachment_detail: true,
},
{
success: function(data) {
// Iterate through the returned test result data, and group by test
data.forEach(function(item) {
var match = false;
var key = testKey(item.test);
// Try to associate this result with a test row
tableData.forEach(function(row) {
// The result matches the test template row
if (key == testKey(row.test_name)) {
// Force the names to be the same!
item.test_name = row.test_name;
match = true;
}
});
// No match could be found (this is a new test!)
if (!match) {
item.test_name = item.test;
}
tableData.push(item);
});
// Finally, push the data back into the table!
table.bootstrapTable("load", tableData);
}
},
);
}
}); });
} }