diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 98aead45ee..0b74204094 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -215,7 +215,7 @@ } .treeview .list-group-item { - padding: 10px 5px; + padding: 3px 5px; } .treeview .list-group-item .indent { @@ -539,7 +539,7 @@ padding: 0px 10px; } -.breadcrump { +.breadcrumb { margin-bottom: 5px; margin-left: 5px; margin-right: 10px; diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index c1b86b6528..a672e79051 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -239,6 +239,23 @@ class CategoryParameterList(generics.ListAPIView): return queryset +class CategoryTree(generics.ListAPIView): + """ + API endpoint for accessing a list of PartCategory objects ready for rendering a tree. + """ + + queryset = PartCategory.objects.all() + serializer_class = part_serializers.CategoryTree + + filter_backends = [ + DjangoFilterBackend, + filters.OrderingFilter, + ] + + # Order by tree level (top levels first) and then name + ordering = ['level', 'name'] + + class PartSalePriceList(generics.ListCreateAPIView): """ API endpoint for list view of PartSalePriceBreak model @@ -1515,6 +1532,7 @@ part_api_urls = [ # Base URL for PartCategory API endpoints url(r'^category/', include([ + url(r'^tree/', 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..cf9d34a44c 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -70,6 +70,20 @@ class CategorySerializer(InvenTreeModelSerializer): ] +class CategoryTree(InvenTreeModelSerializer): + """ + Serializer for PartCategory tree + """ + + class Meta: + model = PartCategory + fields = [ + 'pk', + 'name', + 'parent', + ] + + 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..4de0005672 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 breadcrumb_tree %} + +{% endblock breadcrumb_tree %} + {% block heading %} {% if category %} {% trans "Part Category" %}: {{ category.name }} @@ -239,8 +243,24 @@ {% endif %} + // Enable left-hand navigation sidebar enableSidebar('category'); + // Enable breadcrumb tree view + enableBreadcrumbTree({ + label: 'category', + url: '{% url "api-part-category-tree" %}', + {% if category %} + selected: {{ category.pk }}, + {% endif %} + processNode: function(node) { + node.text = node.name; + node.href = `/part/category/${node.pk}/`; + + return node; + } + }); + loadPartCategoryTable( $('#subcategory-table'), { params: { diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index de1d46596a..f1b47bc4e2 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 breadcrumb_tree %} + +{% endblock breadcrumb_tree %} + {% block page_content %}
@@ -132,10 +136,6 @@
-
- -
-
@@ -1066,4 +1066,18 @@ enableSidebar('part'); + enableBreadcrumbTree({ + label: 'part', + url: '{% url "api-part-category-tree" %}', + {% if part.category %} + selected: {{ part.category.pk }}, + {% endif %} + processNode: function(node) { + node.text = node.name; + node.href = `/part/category/${node.pk}/`; + + return node; + } + }); + {% endblock %} diff --git a/InvenTree/part/templates/part/part_app_base.html b/InvenTree/part/templates/part/part_app_base.html index 992ac15e87..0b578aaadd 100644 --- a/InvenTree/part/templates/part/part_app_base.html +++ b/InvenTree/part/templates/part/part_app_base.html @@ -14,9 +14,10 @@ {% endblock %} {% block breadcrumbs %} + {% if part %} {% include "part/cat_link.html" with category=part.category part=part %} {% else %} {% include 'part/cat_link.html' with category=category %} {% endif %} -{% endblock %} +{% endblock breadcrumbs %} diff --git a/InvenTree/stock/api.py b/InvenTree/stock/api.py index 26787878a8..9961bb7bae 100644 --- a/InvenTree/stock/api.py +++ b/InvenTree/stock/api.py @@ -277,6 +277,24 @@ class StockLocationList(generics.ListCreateAPIView): ] +class StockLocationTree(generics.ListAPIView): + """ + API endpoint for accessing a list of StockLocation objects, + ready for rendering as a tree + """ + + queryset = StockLocation.objects.all() + serializer_class = StockSerializers.LocationTreeSerializer + + filter_backends = [ + DjangoFilterBackend, + filters.OrderingFilter, + ] + + # Order by tree level (top levels first) and then name + ordering = ['level', 'name'] + + class StockFilter(rest_filters.FilterSet): """ FilterSet for StockItem LIST API @@ -1182,6 +1200,9 @@ class LocationDetail(generics.RetrieveUpdateDestroyAPIView): stock_api_urls = [ url(r'^location/', include([ + + url(r'^tree/', StockLocationTree.as_view(), name='api-location-tree'), + url(r'^(?P\d+)/', LocationDetail.as_view(), name='api-location-detail'), url(r'^.*$', StockLocationList.as_view(), name='api-location-list'), ])), diff --git a/InvenTree/stock/serializers.py b/InvenTree/stock/serializers.py index fb78eaeaa0..e69cd90f82 100644 --- a/InvenTree/stock/serializers.py +++ b/InvenTree/stock/serializers.py @@ -390,6 +390,20 @@ class SerializeStockItemSerializer(serializers.Serializer): ) +class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer): + """ + Serializer for a simple tree view + """ + + class Meta: + model = StockLocation + fields = [ + 'pk', + 'name', + 'parent', + ] + + class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer): """ Detailed information about a stock location """ diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html index 64b45ed0c8..65f5f21000 100644 --- a/InvenTree/stock/templates/stock/item_base.html +++ b/InvenTree/stock/templates/stock/item_base.html @@ -9,9 +9,15 @@ {% endblock %} {% block breadcrumbs %} + {% include 'stock/loc_link.html' with location=item.location %} {% endblock %} +{% block breadcrumb_tree %} + +{% endblock breadcrumb_tree %} + + {% block heading %} {% trans "Stock Item" %}: {{ item.part.full_name}} {% endblock heading %} @@ -611,4 +617,18 @@ $('#serial-number-search').click(function() { findStockItemBySerialNumber({{ item.part.pk }}); }); +enableBreadcrumbTree({ + label: 'stockitem', + url: '{% url "api-location-tree" %}', + {% if item.location %} + selected: {{ item.location.pk }}, + {% endif %} + processNode: function(node) { + node.text = node.name; + node.href = `/stock/item/${node.pk}/`; + + return node; + } +}); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/location.html b/InvenTree/stock/templates/stock/location.html index 6a201e610c..39b9faedb4 100644 --- a/InvenTree/stock/templates/stock/location.html +++ b/InvenTree/stock/templates/stock/location.html @@ -7,6 +7,10 @@ {% include "stock/location_sidebar.html" %} {% endblock %} +{% block breadcrumb_tree %} + +{% endblock breadcrumb_tree %} + {% block heading %} {% if location %} {% trans "Stock Location" %}: {{ location.name }} @@ -348,4 +352,19 @@ enableSidebar('stocklocation'); + // Enable breadcrumb tree view + enableBreadcrumbTree({ + label: 'location', + url: '{% url "api-location-tree" %}', + {% if location %} + selected: {{ location.pk }}, + {% endif %} + processNode: function(node) { + node.text = node.name; + node.href = `/stock/location/${node.pk}/`; + + return node; + } + }); + {% endblock %} diff --git a/InvenTree/stock/templates/stock/stock_app_base.html b/InvenTree/stock/templates/stock/stock_app_base.html index 3da3fad240..93994ebd21 100644 --- a/InvenTree/stock/templates/stock/stock_app_base.html +++ b/InvenTree/stock/templates/stock/stock_app_base.html @@ -18,9 +18,10 @@ {% endblock %} {% block breadcrumbs %} + {% if item %} {% include 'stock/loc_link.html' with location=item.location %} {% else %} {% include 'stock/loc_link.html' with location=location %} {% endif %} -{% endblock %} +{% endblock breadcrumbs %} diff --git a/InvenTree/templates/base.html b/InvenTree/templates/base.html index 5636af86e8..a71f4e67c9 100644 --- a/InvenTree/templates/base.html +++ b/InvenTree/templates/base.html @@ -74,13 +74,13 @@