diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index c1b86b6528..05b94aef38 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -239,6 +239,32 @@ class CategoryParameterList(generics.ListAPIView): return queryset +class CategoryTree(generics.ListAPIView): + """ API endpoint for accessing a list of PartCategory objects ready for rendering a jstree. + """ + + queryset = PartCategory.objects.all() + serializer_class = part_serializers.CategoryTree + + def filter_queryset(self, queryset): + """ + """ + queryset = super().filter_queryset(queryset) + + params = self.request.query_params + cat_id = params.get('id', None) + + if cat_id in (None, '', '#', ): + queryset = queryset.filter(parent=None) + else: + queryset = queryset.filter(parent_id=cat_id) + + return queryset + + def get(self, request, *args, **kwargs): + return super().get(request, *args, **kwargs) + + class PartSalePriceList(generics.ListCreateAPIView): """ API endpoint for list view of PartSalePriceBreak model @@ -1515,6 +1541,7 @@ part_api_urls = [ # Base URL for PartCategory API endpoints url(r'^category/', include([ + url(r'^tree/(?P[-\w]+)/', CategoryTree.as_view(), name='api-part-category-tree'), url(r'^parameters/', CategoryParameterList.as_view(), name='api-part-category-parameter-list'), url(r'^(?P\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'), diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 1be81c16ba..7d15f7c4e6 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -70,6 +70,39 @@ class CategorySerializer(InvenTreeModelSerializer): ] +class CategoryTree(InvenTreeModelSerializer): + """ Serializer for PartCategory """ + + id = serializers.IntegerField(source='pk', read_only=True) + + text = serializers.CharField(source='name', read_only=True) + + parent = serializers.SerializerMethodField() + + children = serializers.SerializerMethodField() + + a_attr = serializers.SerializerMethodField() + + def get_parent(self, obj): + return obj.parent.pk if obj.parent else '#' + + def get_children(self, obj): + return True if obj.has_children else False + + def get_a_attr(self, obj): + return {'href': obj.get_absolute_url()} + + class Meta: + model = PartCategory + fields = [ + 'id', + 'text', + 'parent', + 'children', + 'a_attr', + ] + + class PartAttachmentSerializer(InvenTreeAttachmentSerializer): """ Serializer for the PartAttachment class diff --git a/InvenTree/part/templates/part/category.html b/InvenTree/part/templates/part/category.html index 4797571fda..62817516b7 100644 --- a/InvenTree/part/templates/part/category.html +++ b/InvenTree/part/templates/part/category.html @@ -6,6 +6,10 @@ {% include 'part/category_sidebar.html' %} {% endblock %} +{% block sidetree %} +
+{% endblock %} + {% block heading %} {% if category %} {% trans "Part Category" %}: {{ category.name }} @@ -240,6 +244,7 @@ {% endif %} enableSidebar('category'); + enableSidetree('category'); loadPartCategoryTable( $('#subcategory-table'), { diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 38bd406d75..67845d4611 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -9,6 +9,10 @@ {% include 'part/part_sidebar.html' %} {% endblock %} +{% block sidetree %} +
+{% endblock %} + {% block page_content %}
@@ -1061,5 +1065,6 @@ {% endif %} enableSidebar('part'); + enableSidetree('part'); {% endblock %} diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index e97324bf74..70abcca433 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -46,6 +46,7 @@ + diff --git a/InvenTree/templates/js/dynamic/nav.js b/InvenTree/templates/js/dynamic/nav.js index b99a3bb6bd..b0ffdb574c 100644 --- a/InvenTree/templates/js/dynamic/nav.js +++ b/InvenTree/templates/js/dynamic/nav.js @@ -145,6 +145,43 @@ function enableSidebar(label, options={}) { } +/** + * Enable support for a sidetree on this page + */ + function enableSidetree(label, options={}) { + $('#tree').jstree({ + 'core' : { + 'data' : { + 'url' : function (node) { + return '/api/part/category/tree/root/' + }, + 'data' : function (node) { + return { 'id' : node.id }; + } + } + } + }).bind("select_node.jstree",function (e, data) { + window.location.href = data.node.a_attr.href; + }); + + $('#sidetree-toggle').click(function() { + // Add callback to "collapse" and "expand" the sidebar + + // By default, the menu is "expanded" + var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded'; + + // We wish to "toggle" the state! + setSidebarState(label, state == 'expanded' ? 'collapsed' : 'expanded'); + }); + + // Set the initial state (default = expanded) + var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded'; + + // setSidebarState(label, state); + + // Finally, show the sidebar + $('#sidetree').show(); +} /* * Set the "toggle" state of the sidebar