mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 20:16:44 +00:00
Implemented tree view
Using library bootstrap-treeview - part category tree - stock location tree - Currenly is functional but looks terrible
This commit is contained in:
parent
095492203f
commit
8d0789c37c
@ -12,6 +12,7 @@ from build.urls import build_urls
|
|||||||
|
|
||||||
from part.api import part_api_urls
|
from part.api import part_api_urls
|
||||||
from company.api import company_api_urls
|
from company.api import company_api_urls
|
||||||
|
from stock.api import stock_api_urls
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
@ -25,6 +26,7 @@ admin.site.site_header = "InvenTree Admin"
|
|||||||
apipatterns = [
|
apipatterns = [
|
||||||
url(r'^part/', include(part_api_urls)),
|
url(r'^part/', include(part_api_urls)),
|
||||||
url(r'^company/', include(company_api_urls)),
|
url(r'^company/', include(company_api_urls)),
|
||||||
|
url(r'^stock/', include(stock_api_urls)),
|
||||||
|
|
||||||
# User URLs
|
# User URLs
|
||||||
url(r'^user/', include(user_urls)),
|
url(r'^user/', include(user_urls)),
|
||||||
|
@ -5,6 +5,48 @@ from django.template.loader import render_to_string
|
|||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
|
|
||||||
from django.views.generic import UpdateView, CreateView, DeleteView
|
from django.views.generic import UpdateView, CreateView, DeleteView
|
||||||
|
from rest_framework import views
|
||||||
|
from django.http import JsonResponse
|
||||||
|
|
||||||
|
|
||||||
|
class TreeSerializer(views.APIView):
|
||||||
|
|
||||||
|
def itemToJson(self, item):
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'text': item.name,
|
||||||
|
'href': item.get_absolute_url(),
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.has_children:
|
||||||
|
nodes = []
|
||||||
|
|
||||||
|
for child in item.children.all().order_by('name'):
|
||||||
|
nodes.append(self.itemToJson(child))
|
||||||
|
|
||||||
|
data['nodes'] = nodes
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
|
||||||
|
top_items = self.model.objects.filter(parent=None).order_by('name')
|
||||||
|
|
||||||
|
nodes = []
|
||||||
|
|
||||||
|
for item in top_items:
|
||||||
|
nodes.append(self.itemToJson(item))
|
||||||
|
|
||||||
|
top = {
|
||||||
|
'text': self.title,
|
||||||
|
'nodes': nodes,
|
||||||
|
}
|
||||||
|
|
||||||
|
response = {
|
||||||
|
'tree': [top]
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsonResponse(response, safe=False)
|
||||||
|
|
||||||
|
|
||||||
class AjaxView(object):
|
class AjaxView(object):
|
||||||
|
@ -7,9 +7,17 @@ from rest_framework import generics, permissions
|
|||||||
|
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
|
|
||||||
from .models import Part
|
from .models import Part, PartCategory
|
||||||
from .serializers import PartSerializer
|
from .serializers import PartSerializer
|
||||||
|
|
||||||
|
from InvenTree.views import TreeSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class PartCategoryTree(TreeSerializer):
|
||||||
|
|
||||||
|
title = "Parts"
|
||||||
|
model = PartCategory
|
||||||
|
|
||||||
|
|
||||||
class PartList(generics.ListCreateAPIView):
|
class PartList(generics.ListCreateAPIView):
|
||||||
|
|
||||||
@ -44,5 +52,7 @@ class PartList(generics.ListCreateAPIView):
|
|||||||
|
|
||||||
part_api_urls = [
|
part_api_urls = [
|
||||||
|
|
||||||
|
url(r'^tree/?', PartCategoryTree.as_view(), name='api-part-tree'),
|
||||||
|
|
||||||
url(r'^.*$', PartList.as_view(), name='api-part-list'),
|
url(r'^.*$', PartList.as_view(), name='api-part-list'),
|
||||||
]
|
]
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/footable.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
<script type='text/javascript' src="{% static 'script/modal_form.js' %}"></script>
|
||||||
<script type='text/javascript' src="{% static 'script/bootstrap-treeview.js' %}"></script>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block js_ready %}
|
{% block js_ready %}
|
||||||
$('#part-list').footable();
|
$('#part-list').footable();
|
||||||
@ -44,7 +43,36 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function loadTree() {
|
||||||
|
var requestData = {};
|
||||||
|
|
||||||
|
{% if category %}
|
||||||
|
requestData.category = {{ category.id }};
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "{% url 'api-part-tree' %}",
|
||||||
|
type: 'get',
|
||||||
|
dataType: 'json',
|
||||||
|
data: requestData,
|
||||||
|
success: function (response) {
|
||||||
|
if (response.tree) {
|
||||||
|
$("#part-tree").treeview({
|
||||||
|
data: response.tree,
|
||||||
|
enableLinks: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xhr, ajaxOptions, thrownError) {
|
||||||
|
alert('Error retrieving part tree:\n' + thrownError);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
$("#create-part").click(function() {
|
$("#create-part").click(function() {
|
||||||
launchModalForm("#modal-form", "{% url 'part-create' %}");
|
launchModalForm("#modal-form", "{% url 'part-create' %}");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
loadTree();
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
37
InvenTree/static/css/bootstrap-treeview.css
vendored
Normal file
37
InvenTree/static/css/bootstrap-treeview.css
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/* =========================================================
|
||||||
|
* bootstrap-treeview.css v1.2.0
|
||||||
|
* =========================================================
|
||||||
|
* Copyright 2013 Jonathan Miles
|
||||||
|
* Project URL : http://www.jondmiles.com/bootstrap-treeview
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* ========================================================= */
|
||||||
|
|
||||||
|
.treeview .list-group-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeview span.indent {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeview span.icon {
|
||||||
|
width: 12px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.treeview .node-disabled {
|
||||||
|
color: silver;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
@ -41,8 +41,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.inventree-content {
|
.inventree-content {
|
||||||
padding-left: 15px;
|
padding-left: 5px;
|
||||||
padding-right: 15px;
|
padding-right: 5px;
|
||||||
|
padding-top: 15px;
|
||||||
|
margin-right: 50px;
|
||||||
|
margin-left: 50px;
|
||||||
|
width: 100%;
|
||||||
|
transition: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
padding-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
@ -61,4 +70,19 @@
|
|||||||
max-height: calc(100vh - 200px) !important;
|
max-height: calc(100vh - 200px) !important;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The side navigation menu */
|
||||||
|
.sidenav {
|
||||||
|
height: 100%; /* 100% Full-height */
|
||||||
|
width: 0px; /* 0 width - change this with JavaScript */
|
||||||
|
position: fixed; /* Stay in place */
|
||||||
|
background-color: #fff; /* Black*/
|
||||||
|
overflow-x: hidden; /* Disable horizontal scroll */
|
||||||
|
transition: 0.5s; /* 0.5 second transition effect to slide in the sidenav */
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
align-items: stretch;
|
||||||
|
display: flex;
|
||||||
}
|
}
|
1249
InvenTree/static/script/bootstrap-treeview.js
vendored
Normal file
1249
InvenTree/static/script/bootstrap-treeview.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
InvenTree/static/script/sidenav.js
Normal file
9
InvenTree/static/script/sidenav.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
function openSideNav() {
|
||||||
|
document.getElementById("sidenav").style.width = "250px";
|
||||||
|
document.getElementById("inventree-content").style.marginLeft = "270px";
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSideNav() {
|
||||||
|
document.getElementById("sidenav").style.width = "0";
|
||||||
|
document.getElementById("inventree-content").style.marginLeft = "0";
|
||||||
|
}
|
20
InvenTree/static/script/trees.js
Normal file
20
InvenTree/static/script/trees.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
function loadTree(url, tree, data) {
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: url,
|
||||||
|
type: 'get',
|
||||||
|
dataType: 'json',
|
||||||
|
data: data,
|
||||||
|
success: function (response) {
|
||||||
|
if (response.tree) {
|
||||||
|
$(tree).treeview({
|
||||||
|
data: response.tree,
|
||||||
|
enableLinks: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (xhr, ajaxOptions, thrownError) {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -3,11 +3,20 @@ from django_filters import NumberFilter
|
|||||||
|
|
||||||
from rest_framework import generics, permissions, response
|
from rest_framework import generics, permissions, response
|
||||||
|
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
# from InvenTree.models import FilterChildren
|
# from InvenTree.models import FilterChildren
|
||||||
from .models import StockLocation, StockItem
|
from .models import StockLocation, StockItem
|
||||||
from .serializers import StockItemSerializer, StockQuantitySerializer
|
from .serializers import StockItemSerializer, StockQuantitySerializer
|
||||||
from .serializers import LocationSerializer
|
from .serializers import LocationSerializer
|
||||||
|
|
||||||
|
from InvenTree.views import TreeSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class StockCategoryTree(TreeSerializer):
|
||||||
|
title = 'Stock'
|
||||||
|
model = StockLocation
|
||||||
|
|
||||||
|
|
||||||
class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
class StockDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
"""
|
"""
|
||||||
@ -127,3 +136,8 @@ class LocationList(generics.ListCreateAPIView):
|
|||||||
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
|
||||||
filter_backends = (DjangoFilterBackend,)
|
filter_backends = (DjangoFilterBackend,)
|
||||||
filter_class = StockLocationFilter
|
filter_class = StockLocationFilter
|
||||||
|
|
||||||
|
|
||||||
|
stock_api_urls = [
|
||||||
|
url(r'^tree/?', StockCategoryTree.as_view(), name='api-stock-tree'),
|
||||||
|
]
|
@ -15,9 +15,7 @@
|
|||||||
|
|
||||||
{% block css %}
|
{% block css %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<title>
|
<title>
|
||||||
@ -31,22 +29,42 @@ InvenTree
|
|||||||
|
|
||||||
{% include "navbar.html" %}
|
{% include "navbar.html" %}
|
||||||
|
|
||||||
<div class="container container-fluid inventree-content">
|
<div class='main body wrapper'>
|
||||||
|
|
||||||
|
{% include "sidebar.html" %}
|
||||||
|
|
||||||
|
<div class="container container-fluid inventree-content" id='inventree-content'>
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Each view fills in here.. -->
|
<!-- Each view fills in here.. -->
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Scripts -->
|
||||||
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'script/jquery_3.3.1_jquery.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'script/bootstrap.min.js' %}"></script>
|
<script type="text/javascript" src="{% static 'script/bootstrap.min.js' %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
|
<script type="text/javascript" src="{% static 'script/select2/select2.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'script/bootstrap-treeview.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'script/trees.js' %}"></script>
|
||||||
|
<script type='text/javascript' src="{% static 'script/sidenav.js' %}"></script>
|
||||||
|
|
||||||
{% block js_load %}
|
{% block js_load %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
loadTree("{% url 'api-part-tree' %}",
|
||||||
|
"#part-tree");
|
||||||
|
|
||||||
|
loadTree("{% url 'api-stock-tree' %}",
|
||||||
|
"#stock-tree");
|
||||||
|
|
||||||
|
$('#logo').click(function() {
|
||||||
|
openSideNav();
|
||||||
|
});
|
||||||
|
|
||||||
{% block js_ready %}
|
{% block js_ready %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
|
|
||||||
<nav class="navbar navbar-default">
|
<nav class="navbar navbar-default navbar-fixed-top">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand" href="/"><img src="{% static 'img/inventree.png' %}" width="40" height="40"/></a>
|
<a class="navbar-brand" id='logo'><img src="{% static 'img/inventree.png' %}" width="40" height="40"/></a>
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li><a href="{% url 'part-index' %}">Parts</a></li>
|
<li><a href="{% url 'part-index' %}">Parts</a></li>
|
||||||
|
9
InvenTree/templates/sidebar.html
Normal file
9
InvenTree/templates/sidebar.html
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<div class='sidenav' id='sidenav'>
|
||||||
|
|
||||||
|
<div id='part-tree'></div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div id='stock-tree'></div>
|
||||||
|
|
||||||
|
</div>
|
Loading…
x
Reference in New Issue
Block a user