Add code for component autocompletion in add-stock-modal
This commit is contained in:
parent
88bebfa2c8
commit
b4e561279b
@ -32,10 +32,13 @@ class StorageSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class ComponentSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
||||
package_data = PackageSerializerNoLink(source='package', read_only=True)
|
||||
ro_manufacturer_name = serializers.ReadOnlyField(source='manufacturer.name')
|
||||
ro_image = serializers.ReadOnlyField(source='get_resolved_image')
|
||||
|
||||
class Meta:
|
||||
model = parts_models.Component
|
||||
fields = ['url', 'id', 'name', 'package_data', 'package', 'pref_distri']
|
||||
fields = ['url', 'id', 'name', 'package_data', 'package', 'pref_distri', 'image', 'manufacturer', 'ro_manufacturer_name', 'ro_image']
|
||||
|
||||
|
||||
class StockSerializer(serializers.HyperlinkedModelSerializer):
|
||||
ro_package_name = serializers.ReadOnlyField(source='component.package.name')
|
||||
@ -53,3 +56,8 @@ class DistributorSerializer(serializers.HyperlinkedModelSerializer):
|
||||
|
||||
class StockIncrementDecrementSerializer(serializers.Serializer):
|
||||
increment = serializers.IntegerField()
|
||||
|
||||
class ManufacturerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = parts_models.Manufacturer
|
||||
fields = '__all__'
|
@ -11,6 +11,7 @@ router.register(r'parts/components', PartsComponentViewSet)
|
||||
router.register(r'parts/stocks', PartsStockViewSet)
|
||||
router.register(r'parts/packages', PartsPackageViewSet)
|
||||
router.register(r'parts/distributors', PartsDistributorviewSet)
|
||||
router.register(r'parts/manufacturers', PartsManufacturerViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
|
@ -49,6 +49,13 @@ class PartsComponentViewSet(viewsets.ModelViewSet):
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['name', 'package__name', 'manufacturer__name']
|
||||
|
||||
class PartsManufacturerViewSet(viewsets.ModelViewSet):
|
||||
queryset = parts_models.Manufacturer.objects.all()
|
||||
serializer_class = ManufacturerSerializer
|
||||
permission_classes = [permissions.DjangoModelPermissions]
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['name']
|
||||
|
||||
class PartsStockViewSet(viewsets.ModelViewSet):
|
||||
queryset = parts_models.Stock.objects.all()
|
||||
serializer_class = StockSerializer
|
||||
|
44
shimatta_kenkyusho/static/js/add-stock-modal.js
Normal file
44
shimatta_kenkyusho/static/js/add-stock-modal.js
Normal file
@ -0,0 +1,44 @@
|
||||
new AutocompleteCustomUi('add-stock-search', 'add-stock-search-ac-dropdown',
|
||||
function(search, autocomplete_obj) {
|
||||
api_search_component(search, function(results) {
|
||||
components = results.results;
|
||||
var test = [];
|
||||
for (var i = 0; i < components.length; i++) {
|
||||
var c = components[i];
|
||||
var node = document.createElement('div');
|
||||
node.setAttribute('class', 'd-flex align-items-center');
|
||||
var img_container = document.createElement('div');
|
||||
img_container.setAttribute('class', 'flex-shrink-0');
|
||||
var text_container = document.createElement('div');
|
||||
text_container.setAttribute('class', 'flex-grow-1 ms-1');
|
||||
var img = document.createElement('img');
|
||||
var img_path = fallback_img_path;
|
||||
var style = "width:64px;max-height:64px;";
|
||||
if (c.ro_image != null) {
|
||||
img_path = c.ro_image;
|
||||
style = "max-width:64px;max-height:64px;";
|
||||
}
|
||||
img.setAttribute('src', img_path);
|
||||
img.setAttribute('style', style)
|
||||
img_container.appendChild(img);
|
||||
|
||||
var name_text = document.createTextNode(c.name);
|
||||
var heading = document.createElement('h6');
|
||||
heading.appendChild(name_text);
|
||||
text_container.appendChild(heading);
|
||||
if (c.package_data != null) {
|
||||
text_container.appendChild(document.createTextNode('in '+c.package_data.name));
|
||||
}
|
||||
if (c.ro_manufacturer_name) {
|
||||
text_container.appendChild(document.createTextNode(' by '+c.ro_manufacturer_name));
|
||||
}
|
||||
|
||||
node.appendChild(img_container);
|
||||
node.appendChild(text_container);
|
||||
|
||||
test.push({'ui': node, 'data': c.url})
|
||||
}
|
||||
autocomplete_obj.show_results(test,
|
||||
function(data) {console.log(data);});
|
||||
}, function(){});
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
const autocomplete_query_delay_ms = 60;
|
||||
|
||||
class AutocompleteText {
|
||||
class AutocompleteCustomUi {
|
||||
constructor(text_id, dropdown_id, query_function)
|
||||
{
|
||||
this.text_id = text_id;
|
||||
@ -10,9 +10,56 @@ class AutocompleteText {
|
||||
document.getElementById(text_id).addEventListener("keyup", this.ac_delay(function(event) {
|
||||
this.query_callback(document.getElementById(this.text_id).value, this);
|
||||
}, autocomplete_query_delay_ms).bind(this));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} nodes_to_add A liust of dictionaries containing the shown objects and the data called when clicked.
|
||||
*
|
||||
* The list: {{'ui': <nodes>, 'data': 'my_data'}, {}, ...}
|
||||
*
|
||||
*/
|
||||
show_results(nodes_to_add, data_clicked_callback) {
|
||||
var ul = document.getElementById(this.dropdown_id);
|
||||
ul.innerHTML = '';
|
||||
this.select_data = {};
|
||||
|
||||
for (var i = 0; i < nodes_to_add.length; i++) {
|
||||
var ui = nodes_to_add[i]['ui'];
|
||||
var data = nodes_to_add[i]['data']
|
||||
var dropdown_node = document.createElement('li');
|
||||
dropdown_node.dataset.ac_clicked = data;
|
||||
dropdown_node.addEventListener('click',
|
||||
(e) => {
|
||||
data_clicked_callback(e.currentTarget.dataset.ac_clicked);
|
||||
var text_box = document.getElementById(this.text_id);
|
||||
var dropdown = bootstrap.Dropdown.getOrCreateInstance(text_box);
|
||||
dropdown.hide();
|
||||
});
|
||||
|
||||
dropdown_node.setAttribute('class', 'dropdown-item');
|
||||
dropdown_node.appendChild(ui);
|
||||
ul.appendChild(dropdown_node);
|
||||
}
|
||||
|
||||
var dropdown = bootstrap.Dropdown.getOrCreateInstance(document.getElementById(this.text_id));
|
||||
dropdown.show();
|
||||
}
|
||||
|
||||
ac_delay(callback, ms) {
|
||||
var timer = 0;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() {
|
||||
callback.apply(context, args);
|
||||
}, ms || 0);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class AutocompleteText extends AutocompleteCustomUi {
|
||||
show_results(results) {
|
||||
var ul = document.getElementById(this.dropdown_id);
|
||||
ul.innerHTML = '';
|
||||
@ -41,17 +88,4 @@ class AutocompleteText {
|
||||
var dropdown = bootstrap.Dropdown.getOrCreateInstance(document.getElementById(this.text_id));
|
||||
dropdown.show();
|
||||
}
|
||||
|
||||
ac_delay(callback, ms) {
|
||||
var timer = 0;
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() {
|
||||
callback.apply(context, args);
|
||||
}, ms || 0);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -27,4 +27,8 @@ function api_ajax_request_without_send(method, url, onSuccess, onFail) {
|
||||
|
||||
function api_search_user(search, onSuccess, onFail) {
|
||||
return api_ajax_request_without_send('GET', api_urls_v1['user-list']+`?search=${encodeURIComponent(search)}`, function(method, url, json) {onSuccess(json);}, onFail);
|
||||
}
|
||||
|
||||
function api_search_component(search, onSuccess, onFail) {
|
||||
return api_ajax_request_without_send('GET', api_urls_v1['component-list']+`?search=${encodeURIComponent(search)}`, function(method, url, json) {onSuccess(json);}, onFail);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
{% comment %}
|
||||
Input context:
|
||||
- form: A stock-create-form
|
||||
{% endcomment %}
|
||||
<div class="modal fade" id="add-stock-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Add Stock</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="dropdown">
|
||||
<input class="form-control" autocomplete="off" data-bs-toggle="dropdown" type="search" id="add-stock-search" placeholder="Search Component" aria-label="Search for Component">
|
||||
<ul class="dropdown-menu" aria-labelledby="add-stock-search" id="add-stock-search-ac-dropdown">
|
||||
</div>
|
||||
<hr>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<input type="submit" class="btn btn-primary" value="Add Stock" name="submit-add-stock">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,7 +2,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Delete Storage</h5>
|
||||
<h5 class="modal-title">Delete Storage</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="" method="post">
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="staticBackdropLabel">Add Storage</h5>
|
||||
<h5 class="modal-title">Add Storage</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="" method="post">
|
||||
|
@ -54,6 +54,9 @@
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#add-stock-modal">
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</button>
|
||||
<div class="list-group">
|
||||
{% for stock in stocks %}
|
||||
<li class="list-group-item list-group-item-action d-flex align-items-center">
|
||||
@ -109,6 +112,10 @@
|
||||
{% with delete_storage_errors as err_msgs %}
|
||||
{% include 'parts/modals/delete-storage-modal.html' %}
|
||||
{% endwith %}
|
||||
<!-- Modal for adding stock to this storage -->
|
||||
{% with add_stock_form as form %}
|
||||
{% include 'parts/modals/add-stock-modal.html' %}
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
{% endblock content %}
|
||||
@ -140,6 +147,10 @@ function(search, autocomplete_obj) {
|
||||
}, function(){});
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
const fallback_img_path = "{% static 'css/icons/card-image.svg' %}";
|
||||
</script>
|
||||
<script type="text/javascript" src="{% static 'js/add-stock-modal.js' %}"></script>
|
||||
|
||||
{% endblock custom_scripts %}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user