diff --git a/shimatta_kenkyusho/api/serializers.py b/shimatta_kenkyusho/api/serializers.py index 6ba6aaf..c3d6f29 100644 --- a/shimatta_kenkyusho/api/serializers.py +++ b/shimatta_kenkyusho/api/serializers.py @@ -18,6 +18,7 @@ class PackageSerializerNoLink(serializers.ModelSerializer): fields = '__all__' class PackageSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() class Meta: model = parts_models.Package fields = '__all__' @@ -30,7 +31,6 @@ class StorageSerializer(serializers.HyperlinkedModelSerializer): fields = ['url', 'id', 'name', 'parent_storage', 'responsible', 'full_path'] 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') @@ -41,6 +41,7 @@ class ComponentSerializer(serializers.HyperlinkedModelSerializer): class StockSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() ro_package_name = serializers.ReadOnlyField(source='component.package.name') ro_component_name = serializers.ReadOnlyField(source='component.name') ro_manufacturer_name = serializers.ReadOnlyField(source='component.manufacturer.name') @@ -50,6 +51,7 @@ class StockSerializer(serializers.HyperlinkedModelSerializer): fields = '__all__' class DistributorSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() class Meta: model = parts_models.Distributor fields = '__all__' @@ -58,16 +60,19 @@ class StockIncrementDecrementSerializer(serializers.Serializer): increment = serializers.IntegerField() class ManufacturerSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() class Meta: model = parts_models.Manufacturer fields = '__all__' class ComponentTypeSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() class Meta: model = parts_models.ComponentType fields = '__all__' class ComponentParameterTypeSerializer(serializers.HyperlinkedModelSerializer): + id = serializers.ReadOnlyField() class Meta: model = parts_models.ComponentParameterType fields = '__all__' \ No newline at end of file diff --git a/shimatta_kenkyusho/parts/forms.py b/shimatta_kenkyusho/parts/forms.py index 9eb9e5d..c8e9db0 100644 --- a/shimatta_kenkyusho/parts/forms.py +++ b/shimatta_kenkyusho/parts/forms.py @@ -4,49 +4,65 @@ from django.core.exceptions import ValidationError from parts import models as parts_models from shimatta_modules.EngineeringNumberConverter import EngineeringNumberConverter import uuid +from django.urls import reverse class AutoCompleteWidget(widgets.Input): template_name = 'widgets/autocomplete-foreign-key.html' - def __init__(self, api_search_url, image_field_name, foreign_model, *args, **kwargs): + def __init__(self, api_search_url, image_field_name, foreign_model, name_field_name, *args, **kwargs): super().__init__(*args, **kwargs) self.image_field_name = image_field_name self.foreign_model = foreign_model self.api_search_url = api_search_url + self.name_field_name = name_field_name def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) if value is not None: try: - instance = self.foreign_model.objects.get(id=uuid.UUID(value)) + try: + my_id = uuid.UUID(value) + except: + my_id = int(value) + instance = self.foreign_model.objects.get(id=my_id) except Exception as ex: instance = None else: instance = None image = None - if instance is not None: + if instance is not None and self.image_field_name is not None: image = getattr(instance, self.image_field_name) + display_name = None + if instance: + display_name = getattr(instance, self.name_field_name) context['custom'] = { - 'search_url': self.api_search_url, + 'search_url': reverse(self.api_search_url), 'image_field_name': self.image_field_name, 'current_instance': instance, 'image': image, + 'name_field_name': self.name_field_name, + 'name': display_name, } return context - class AutocompleteForeingKeyField(forms.UUIDField): - def __init__(self, foreign_model=None, api_search_url=None, image_field_name='image', **kwargs): + def __init__(self, foreign_model=None, api_search_url=None, image_field_name='image', name_field_name='name', **kwargs): super().__init__(**kwargs) - self.widget = AutoCompleteWidget(api_search_url, image_field_name, foreign_model) + self.widget = AutoCompleteWidget(api_search_url, image_field_name, foreign_model, name_field_name) self.foreign_model = foreign_model def clean(self, value): - pre_cleaned_uuid = super().clean(value) + try: + pre_cleaned_uuid = super().clean(value) + except Exception as ex: + try: + pre_cleaned_uuid = int(value) + except: + raise ex if pre_cleaned_uuid is None and not self.required: return None try: @@ -161,9 +177,9 @@ class AddStockForm(forms.Form): new_stock.save() class ComponentForm(forms.ModelForm): - manufacturer = AutocompleteForeingKeyField(api_search_url='foo', foreign_model=parts_models.Manufacturer) - component_type = AutocompleteForeingKeyField(api_search_url='bar', foreign_model=parts_models.ComponentType, required=False, image_field_name=None) - package = AutocompleteForeingKeyField(api_search_url='pkgurl', foreign_model=parts_models.Package, required=False) + manufacturer = AutocompleteForeingKeyField(api_search_url='manufacturer-list', foreign_model=parts_models.Manufacturer, required=False) + component_type = AutocompleteForeingKeyField(api_search_url='componenttype-list', foreign_model=parts_models.ComponentType, name_field_name='class_name', required=False, image_field_name=None) + package = AutocompleteForeingKeyField(api_search_url='package-list', foreign_model=parts_models.Package, required=False) class Meta: model = parts_models.Component fields = '__all__' diff --git a/shimatta_kenkyusho/static/js/autocomplete-foreign-key-field.js b/shimatta_kenkyusho/static/js/autocomplete-foreign-key-field.js new file mode 100644 index 0000000..37bb883 --- /dev/null +++ b/shimatta_kenkyusho/static/js/autocomplete-foreign-key-field.js @@ -0,0 +1,93 @@ +function clear_foreign_key_field(uuid_field, dflex_container) { + dflex_container.innerHTML = ''; + var span = document.createElement('span'); + span.setAttribute('class', 'text-secondary'); + span.appendChild(document.createTextNode('None selected')); + dflex_container.appendChild(span); + uuid_field.removeAttribute('value') +} + +function initialize_autocompletion_foreign_key_field(search_element) { + var image_field_name = search_element.getAttribute('data-ac-image-field'); + var name_field_name = search_element.getAttribute('data-ac-name-field'); + var search_url = search_element.getAttribute('data-ac-url'); + var base_id = search_element.getAttribute('id'); + var uuid_field = search_element.parentElement.querySelector('#'+base_id+'-uuid-field'); + var dflex_container = search_element.parentElement.querySelector('#'+base_id+'-dflex-container'); + var initial_delete_button = search_element.parentElement.querySelector('[data-ac-delete]'); + + console.log(initial_delete_button); + console.log(image_field_name); + console.log(search_url); + console.log(base_id); + + if (initial_delete_button) { + initial_delete_button.addEventListener('click', (e) => { + clear_foreign_key_field(uuid_field, dflex_container); + }); + } + + new AutocompleteCustomUi( + base_id, base_id+'-ac-ul', function(search_query, autocomplete_obj) { + api_ajax_request_without_send('GET', search_url+`?search=${encodeURIComponent(search_query)}`, function(method, url, json) { + if (json.results == undefined || json.results == null) + return; + var results = json.results; + var nodes = []; + + if (image_field_name != '' && image_field_name != null) { + for (var i = 0; i < results.length; i++) { + var res = results[i]; + var node = AutocompleteCustomUi.create_media_div(res[image_field_name], [document.createTextNode(res[name_field_name])]); + nodes.push({'ui': node, 'data': {'result': res, 'uuid_field': uuid_field}}); + } + } else { + for (var i = 0; i < results.length; i++) { + nodes.push({'ui': document.createTextNode(results[i][name_field_name]), 'data': {'result':results[i], 'uuid_field': uuid_field}}) + } + } + + autocomplete_obj.show_results(nodes, function(data) { + var name = data['result'][name_field_name]; + if (image_field_name != '' && image_field_name != null) { + var image = data['result'][image_field_name]; + if (image == null) { + image = fallback_img_path; + } + dflex_content = AutocompleteCustomUi.create_media_div(image, [document.createTextNode(name)]); + } else { + dflex_content = document.createTextNode(name); + } + dflex_container.innerHTML = ''; + dflex_container.appendChild(dflex_content); + + search_element.value = data['result'][name_field_name]; + data['uuid_field'].value = data['result'].id; + + var span = document.createElement('span'); + span.setAttribute('class', 'btn-close ms-4'); + span.addEventListener('click', (e) => { + clear_foreign_key_field(uuid_field, dflex_container); + search_element.value = ''; + }); + dflex_container.appendChild(span); + + }) + }, function (){}); + } + ) +} + + +function initialize_autocompletion_for_foreign_key_fields() { + var autocomplete_searches = document.querySelectorAll("[data-ac-url]"); + if (autocomplete_searches.length == 0) { + return; + } + autocomplete_searches.forEach(initialize_autocompletion_foreign_key_field); +} + + +document.addEventListener("DOMContentLoaded", function(event) { + initialize_autocompletion_for_foreign_key_fields(); +}); \ No newline at end of file diff --git a/shimatta_kenkyusho/static/js/autocomplete.js b/shimatta_kenkyusho/static/js/autocomplete.js index 07cd4ba..b99c0d0 100644 --- a/shimatta_kenkyusho/static/js/autocomplete.js +++ b/shimatta_kenkyusho/static/js/autocomplete.js @@ -19,7 +19,7 @@ class AutocompleteCustomUi { img_div.appendChild(img); ui.appendChild(img_div); var text_div = document.createElement('div'); - text_div.setAttribute('class', 'flex-grow-1 ms-3'); + text_div.setAttribute('class', 'ms-3'); if (text_nodes != undefined) { for (var i = 0; i < text_nodes.length; i++) { diff --git a/shimatta_kenkyusho/templates/base.html b/shimatta_kenkyusho/templates/base.html index 5f6b3cf..7ec0325 100644 --- a/shimatta_kenkyusho/templates/base.html +++ b/shimatta_kenkyusho/templates/base.html @@ -76,6 +76,7 @@ + {% block custom_scripts %} {% endblock custom_scripts %} diff --git a/shimatta_kenkyusho/templates/parts/components-detail.html b/shimatta_kenkyusho/templates/parts/components-detail.html index a669055..f96bee6 100644 --- a/shimatta_kenkyusho/templates/parts/components-detail.html +++ b/shimatta_kenkyusho/templates/parts/components-detail.html @@ -119,11 +119,6 @@ -
{% if component.get_resolved_image %} @@ -149,7 +144,7 @@ {% endif %} -{% include 'parts/modals/edit-component-modal.html' with heading="Edit "|add:component.name form=edit_form %} +{% include 'parts/modals/edit-component-modal.html' with heading="Edit "|add:component.name form=comp_form %} {% endblock content %} {% block custom_scripts %} diff --git a/shimatta_kenkyusho/templates/parts/modals/edit-component-modal.html b/shimatta_kenkyusho/templates/parts/modals/edit-component-modal.html index c48d910..1966e97 100644 --- a/shimatta_kenkyusho/templates/parts/modals/edit-component-modal.html +++ b/shimatta_kenkyusho/templates/parts/modals/edit-component-modal.html @@ -17,58 +17,12 @@ Needs following context: - - \ No newline at end of file diff --git a/shimatta_kenkyusho/templates/widgets/autocomplete-foreign-key.html b/shimatta_kenkyusho/templates/widgets/autocomplete-foreign-key.html index ec1a0cf..bf80086 100644 --- a/shimatta_kenkyusho/templates/widgets/autocomplete-foreign-key.html +++ b/shimatta_kenkyusho/templates/widgets/autocomplete-foreign-key.html @@ -1,5 +1,5 @@