2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 11:10:54 +00:00

[WIP] Test result table (#6430)

* Add basic table for stock item test results

* Improve custom data formatter callback

* Custom data formatter for returned results

* Update YesNoButton functionality

- Add PassFailButton with custom text

* Enhancements for stock item test result table

- Render all data

* Add placeholder row actions

* Fix table link

* Add option to filter parttesttemplate table by "inherited"

* Navigate through to parent part

* Update PartTestTemplate model

- Save 'key' value to database
- Update whenever model is saved
- Custom data migration

* Custom migration step in tasks.py

- Add custom management command
- Wraps migration step in maintenance mode

* Improve uniqueness validation for PartTestTemplate

* Add 'template' field to StockItemTestResult

- Links to a PartTestTemplate instance
- Add migrations to link existing PartTestTemplates

* Add "results" count to PartTestTemplate API

- Include in rendered tables

* Add 'results' column to test result table

- Allow filtering too

* Update serializer for StockItemTestResult

- Include template information
- Update CUI and PUI tables

* Control template_detail field with query params

* Update ref in api_version.py

* Update data migration

- Ensure new template is created for top level assembly

* Fix admin integration

* Update StockItemTestResult table

- Remove 'test' field
- Make 'template' field non-nullable
- Previous data migrations should have accounted for this

* Implement "legacy" API support

- Create test result by providing test name
- Lookup existing template

* PUI: Cleanup table

* Update tasks.py

- Exclude temporary settings when exporting data

* Fix unique validation check

* Remove duplicate code

* CUI: Fix data rendering

* More refactoring of PUI table

* More fixes for PUI table

* Get row expansion working (kinda)

* Improve rendering of subtable

* More PUI updates:

- Edit existing results
- Add new results

* allow delete of test result

* Fix typo

* Updates for admin integration

* Unit tests for stock migrations

* Added migration test for PartTestTemplate

* Fix for AttachmentTable

- Rebuild actions when permissions are recalculated

* Update test fixtures

* Add ModelType information

* Fix TableState

* Fix dataFormatter type def

* Improve table rendering

* Correctly filter "edit" and "delete" buttons

* Loosen requirements for dataFormatter

* Fixtures for report tests

* Better API filtering for StocokItemTestResult list

- Add Filter class
- Add option for filtering against legacy "name" data

* Cleanup API filter

* Fix unit tests

* Further unit test fixes

* Include test results for installed stock items

* Improve rendering of test result table

* Fix filtering for getTestResults

* More unit test fixes

* Fix more unit tests

* FIx part unit test

* More fixes

* More unit test fixes

* Rebuild stock item trees when merging

* Helper function for adding a test result to a stock item

* Set init fix

* Code cleanup

* Cleanup unused variables

* Add docs and more unit tests

* Update build unit test
This commit is contained in:
Oliver
2024-02-18 23:26:01 +11:00
committed by GitHub
parent ad1c1ae604
commit 0f51127adf
50 changed files with 1505 additions and 243 deletions

View File

@ -68,6 +68,8 @@ function getModelRenderer(model) {
return renderPartCategory;
case 'partparametertemplate':
return renderPartParameterTemplate;
case 'parttesttemplate':
return renderPartTestTemplate;
case 'purchaseorder':
return renderPurchaseOrder;
case 'salesorder':
@ -483,6 +485,18 @@ function renderPartParameterTemplate(data, parameters={}) {
}
function renderPartTestTemplate(data, parameters={}) {
return renderModel(
{
text: data.test_name,
textSecondary: data.description,
},
parameters
);
}
// Renderer for "ManufacturerPart" model
function renderManufacturerPart(data, parameters={}) {

View File

@ -2867,6 +2867,18 @@ function loadPartTestTemplateTable(table, options) {
field: 'test_name',
title: '{% trans "Test Name" %}',
sortable: true,
formatter: function(value, row) {
let html = value;
if (row.results && row.results > 0) {
html += `
<span class='badge bg-dark rounded-pill float-right' title='${row.results} {% trans "results" %}'>
${row.results}
</span>`;
}
return html;
}
},
{
field: 'description',
@ -2909,7 +2921,7 @@ function loadPartTestTemplateTable(table, options) {
} else {
var text = '{% trans "This test is defined for a parent part" %}';
return renderLink(text, `/part/${row.part}/tests/`);
return renderLink(text, `/part/${row.part}/?display=test-templates`);
}
}
}

View File

@ -1381,7 +1381,11 @@ function formatDate(row) {
/* Construct set of default fields for a StockItemTestResult */
function stockItemTestResultFields(options={}) {
let fields = {
test: {},
template: {
filters: {
include_inherited: true,
}
},
result: {},
value: {},
attachment: {},
@ -1393,6 +1397,10 @@ function stockItemTestResultFields(options={}) {
},
};
if (options.part) {
fields.template.filters.part = options.part;
}
if (options.stock_item) {
fields.stock_item.value = options.stock_item;
}
@ -1412,6 +1420,7 @@ function loadStockTestResultsTable(table, options) {
let params = {
part: options.part,
include_inherited: true,
};
var filters = loadTableFilters(filterKey, params);
@ -1424,17 +1433,16 @@ function loadStockTestResultsTable(table, options) {
let html = '';
if (row.requires_attachment == false && row.requires_value == false && !row.result) {
if (row.parent != parent_node && row.requires_attachment == false && row.requires_value == false && !row.result) {
// Enable a "quick tick" option for this test result
html += makeIconButton('fa-check-circle icon-green', 'button-test-tick', row.test_name, '{% trans "Pass test" %}');
}
html += makeIconButton('fa-plus icon-green', 'button-test-add', row.test_name, '{% trans "Add test result" %}');
html += makeIconButton('fa-plus icon-green', 'button-test-add', row.templateId, '{% trans "Add test result" %}');
if (!grouped && row.result != null) {
var pk = row.pk;
html += makeEditButton('button-test-edit', pk, '{% trans "Edit test result" %}');
html += makeDeleteButton('button-test-delete', pk, '{% trans "Delete test result" %}');
html += makeEditButton('button-test-edit', row.testId, '{% trans "Edit test result" %}');
html += makeDeleteButton('button-test-delete', row.testId, '{% trans "Delete test result" %}');
}
return wrapButtons(html);
@ -1532,9 +1540,14 @@ function loadStockTestResultsTable(table, options) {
],
onLoadSuccess: function(tableData) {
// Set "parent" for each existing row
tableData.forEach(function(item, idx) {
tableData[idx].parent = parent_node;
// Construct an initial dataset based on the returned templates
let results = tableData.map((template) => {
return {
...template,
templateId: template.pk,
parent: parent_node,
results: []
};
});
// Once the test template data are loaded, query for test results
@ -1545,6 +1558,7 @@ function loadStockTestResultsTable(table, options) {
stock_item: options.stock_item,
user_detail: true,
attachment_detail: true,
template_detail: false,
ordering: '-date',
};
@ -1561,54 +1575,40 @@ function loadStockTestResultsTable(table, options) {
query_params,
{
success: function(data) {
// Iterate through the returned test data
data.forEach(function(item) {
var match = false;
var override = false;
data.sort((a, b) => {
return a.pk < b.pk;
}).forEach((row) => {
let idx = results.findIndex((template) => {
return template.templateId == row.template;
});
// Extract the simplified test key
var key = item.key;
if (idx > -1) {
// Attempt to associate this result with an existing test
for (var idx = 0; idx < tableData.length; idx++) {
results[idx].results.push(row);
var row = tableData[idx];
if (key == row.key) {
item.test_name = row.test_name;
item.test_description = row.description;
item.required = row.required;
if (row.result == null) {
item.parent = parent_node;
tableData[idx] = item;
override = true;
} else {
item.parent = row.pk;
}
match = true;
break;
// Check if a test result is already recorded
if (results[idx].testId) {
// Push this result into the results array
results.push({
...results[idx],
...row,
parent: results[idx].templateId,
testId: row.pk,
});
} else {
// First result - update the parent row
results[idx] = {
...row,
...results[idx],
testId: row.pk,
};
}
}
// No match could be found
if (!match) {
item.test_name = item.test;
item.parent = parent_node;
}
if (!override) {
tableData.push(item);
}
});
// Push data back into the table
table.bootstrapTable('load', tableData);
table.bootstrapTable('load', results);
}
}
);
@ -1645,25 +1645,17 @@ function loadStockTestResultsTable(table, options) {
$(table).on('click', '.button-test-add', function() {
var button = $(this);
var test_name = button.attr('pk');
var templateId = button.attr('pk');
let fields = stockItemTestResultFields();
fields['stock_item']['value'] = options.stock_item;
fields['template']['value'] = templateId;
fields['template']['filters']['part'] = options.part;
constructForm('{% url "api-stock-test-result-list" %}', {
method: 'POST',
fields: {
test: {
value: test_name,
},
result: {},
value: {},
attachment: {},
notes: {
icon: 'fa-sticky-note',
},
stock_item: {
value: options.stock_item,
hidden: true,
}
},
fields: fields,
title: '{% trans "Add Test Result" %}',
onSuccess: reloadTestTable,
});
@ -1692,11 +1684,9 @@ function loadStockTestResultsTable(table, options) {
var url = `/api/stock/test/${pk}/`;
var row = $(table).bootstrapTable('getRowByUniqueId', pk);
var html = `
<div class='alert alert-block alert-danger'>
<strong>{% trans "Delete test result" %}:</strong> ${row.test_name || row.test || row.key}
<strong>{% trans "Delete test result" %}</strong>
</div>`;
constructForm(url, {