More features

- Custom renderers depending on specified model name
- Paginate API results
This commit is contained in:
Oliver 2021-06-26 14:09:35 +10:00
parent b29db6f258
commit 565631ef87
5 changed files with 150 additions and 15 deletions

View File

@ -973,3 +973,10 @@ input[type="date"].form-control, input[type="time"].form-control, input[type="da
.select2-container {
width: 100%;
}
.select2-thumbnail {
max-width: 24px;
max-height: 24px;
border-radius: 4px;
margin-right: 10px;
}

View File

@ -105,6 +105,7 @@ settings_urls = [
dynamic_javascript_urls = [
url(r'^api.js', DynamicJsView.as_view(template_name='js/api.js'), name='api.js'),
url(r'^forms.js', DynamicJsView.as_view(template_name='js/forms.js'), name='forms.js'),
url(r'^model_renderers.js', DynamicJsView.as_view(template_name='js/model_renderers.js'), name='model_renderers.js'),
url(r'^modals.js', DynamicJsView.as_view(template_name='js/modals.js'), name='modals.js'),
url(r'^barcode.js', DynamicJsView.as_view(template_name='js/barcode.js'), name='barcode.js'),
url(r'^bom.js', DynamicJsView.as_view(template_name='js/bom.js'), name='bom.js'),

View File

@ -150,6 +150,7 @@
<!-- translated -->
<script type='text/javascript' src="{% i18n_static 'api.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'forms.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'model_renderers.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'barcode.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'bom.js' %}"></script>
<script type='text/javascript' src="{% i18n_static 'company.js' %}"></script>

View File

@ -364,7 +364,8 @@ function initializeRelatedField(modal, name, field, options) {
// TODO: Add 'placeholder' support for entry select2 fields
// TODO: Add 'pagination' support for the query
// limit size for AJAX requests
var pageSize = options.pageSize || 25;
select.select2({
ajax: {
@ -377,31 +378,52 @@ function initializeRelatedField(modal, name, field, options) {
cache: true,
// matcher: partialMatcher,
data: function(params) {
if (!params.page) {
offset = 0;
} else {
offset = (params.page - 1) * pageSize;
}
// Re-format search term into InvenTree API style
return {
search: params.term,
offset: offset,
limit: pageSize,
};
},
processResults: function(data) {
processResults: function(response) {
// Convert the returned InvenTree data into select2-friendly format
var rows = [];
// Only ever show the first x items
for (var idx = 0; idx < data.length && idx < 50; idx++) {
var row = data[idx];
var data = [];
// Reformat to match select2 requirements
row.id = row.id || row.pk;
var more = false;
// TODO: Fix me?
row.text = `This is ${field.api_url}${row.id}/`;
if ('count' in response && 'results' in response) {
// Response is paginated
data = response.results;
rows.push(row);
// Any more data available?
if (response.next) {
more = true;
}
} else {
// Non-paginated response
data = response;
}
// Each 'row' must have the 'id' attribute
for (var idx = 0; idx < data.length; idx++) {
data[idx].id = data[idx].pk;
}
// Ref: https://select2.org/data-sources/formats
var results = {
results: rows,
results: data,
pagination: {
more: more,
}
};
return results;
@ -442,7 +464,7 @@ function initializeRelatedField(modal, name, field, options) {
* - parameters: The field definition (OPTIONS) request
* - options: Other options provided at time of modal creation by the client
*/
function renderModelData(name, model, data, paramaters, options) {
function renderModelData(name, model, data, parameters, options) {
if (!data) {
return '{% trans "Searching" %}...';
@ -452,20 +474,41 @@ function renderModelData(name, model, data, paramaters, options) {
var html = null;
var renderer = null;
// Find a custom renderer
switch (model) {
case 'company':
html = `<span>${data.name}</span> - <i>${data.description}</i>`;
renderer = renderCompany;
break;
case 'stockitem':
renderer = renderStockItem;
break;
case 'stocklocation':
renderer = renderStockLocation;
break;
case 'part':
renderer = renderPart;
break;
case 'partcategory':
renderer = renderPartCategory;
break;
default:
break;
}
if (renderer != null) {
html = renderer(name, data, parameters, options);
}
if (html != null) {
// Render HTML to an object
var $state = $(html);
return $state;
} else {
console.log(`ERROR: Rendering not implemented for model '${model}'`);
// Simple text rendering
return data.text;
return data.id;
}
}

View File

@ -0,0 +1,83 @@
/*
* This file contains functions for rendering various InvenTree database models,
* in particular for displaying them in modal forms in a 'select2' context.
*
* Each renderer is provided with three arguments:
*
* - name: The 'name' of the model instance in the referring model
* - data: JSON data which represents the model instance. Returned via a GET request.
* - parameters: The field parameters provided via an OPTIONS request to the endpoint.
* - options: User options provided by the client
*/
// Renderer for "Company" model
function renderCompany(name, data, parameters, options) {
var html = `<span>${data.name}</span> - <i>${data.description}</i>`;
return html;
}
// Renderer for "StockItem" model
function renderStockItem(name, data, parameters, options) {
// TODO - Include part detail, location, quantity
// TODO - Include part image
}
// Renderer for "StockLocation" model
function renderStockLocation(name, data, parameters, options) {
var html = `<span>${data.name}</span>`;
if (data.description) {
html += ` - <i>${data.description}</i>`;
}
if (data.pathstring) {
html += `<p><small>${data.pathstring}</small></p>`;
}
return html;
}
// Renderer for "Part" model
function renderPart(name, data, parameters, options) {
var image = data.image;
if (!image) {
image = `/static/img/blank_image.png`;
}
var html = `<img src='${image}' class='select2-thumbnail'>`;
html += ` <span>${data.full_name ?? data.name}</span>`;
if (data.description) {
html += ` - <i>${data.description}</i>`;
}
return html;
}
// Renderer for "PartCategory" model
function renderPartCategory(name, data, parameters, options) {
var html = `<span>${data.name}</span>`;
if (data.description) {
html += ` - <i>${data.description}</i>`;
}
if (data.pathstring) {
html += `<p><small>${data.pathstring}</small></p>`;
}
return html;
}