mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'inventree:master' into webhooks
This commit is contained in:
commit
f6d43946b3
@ -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;
|
||||
|
@ -1150,7 +1150,7 @@ class BuildItem(models.Model):
|
||||
|
||||
bom_item_valid = False
|
||||
|
||||
if self.bom_item:
|
||||
if self.bom_item and self.build:
|
||||
"""
|
||||
A BomItem object has already been assigned. This is valid if:
|
||||
|
||||
@ -1162,10 +1162,13 @@ class BuildItem(models.Model):
|
||||
iii) The Part referenced by the StockItem is a valid substitute for the BomItem
|
||||
"""
|
||||
|
||||
if self.build and self.build.part == self.bom_item.part:
|
||||
|
||||
if self.build.part == self.bom_item.part:
|
||||
bom_item_valid = self.bom_item.is_stock_item_valid(self.stock_item)
|
||||
|
||||
elif self.bom_item.inherited:
|
||||
if self.build.part in self.bom_item.part.get_descendants(include_self=False):
|
||||
bom_item_valid = self.bom_item.is_stock_item_valid(self.stock_item)
|
||||
|
||||
# If the existing BomItem is *not* valid, try to find a match
|
||||
if not bom_item_valid:
|
||||
|
||||
|
@ -309,14 +309,20 @@ class BuildAllocationItemSerializer(serializers.Serializer):
|
||||
)
|
||||
|
||||
def validate_bom_item(self, bom_item):
|
||||
|
||||
# TODO: Fix this validation - allow for variants and substitutes!
|
||||
"""
|
||||
Check if the parts match!
|
||||
"""
|
||||
|
||||
build = self.context['build']
|
||||
|
||||
# BomItem must point to the same 'part' as the parent build
|
||||
# BomItem should point to the same 'part' as the parent build
|
||||
if build.part != bom_item.part:
|
||||
raise ValidationError(_("bom_item.part must point to the same part as the build order"))
|
||||
|
||||
# If not, it may be marked as "inherited" from a parent part
|
||||
if bom_item.inherited and build.part in bom_item.part.get_descendants(include_self=False):
|
||||
pass
|
||||
else:
|
||||
raise ValidationError(_("bom_item.part must point to the same part as the build order"))
|
||||
|
||||
return bom_item
|
||||
|
||||
|
@ -77,6 +77,11 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<td>{% trans "Part" %}</td>
|
||||
<td><a href="{% url 'part-detail' build.part.id %}?display=build-orders">{{ build.part.full_name }}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{% trans "Quantity" %}</td>
|
||||
<td>{{ build.quantity }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-info-circle'></span></td>
|
||||
<td>{% trans "Build Description" %}</td>
|
||||
@ -127,11 +132,6 @@ src="{% static 'img/blank_image.png' %}"
|
||||
{% block details_right %}
|
||||
<table class='table table-striped table-condensed'>
|
||||
<col width='25'>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{% trans "Quantity" %}</td>
|
||||
<td>{{ build.quantity }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Status" %}</td>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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<pk>\d+)/?', CategoryDetail.as_view(), name='api-part-category-detail'),
|
||||
|
@ -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
|
||||
|
@ -6,6 +6,10 @@
|
||||
{% include 'part/category_sidebar.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb_tree %}
|
||||
<div id="breadcrumb-tree"></div>
|
||||
{% 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: {
|
||||
|
@ -9,6 +9,10 @@
|
||||
{% include 'part/part_sidebar.html' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb_tree %}
|
||||
<div id="breadcrumb-tree"></div>
|
||||
{% endblock breadcrumb_tree %}
|
||||
|
||||
{% block page_content %}
|
||||
|
||||
<div class='panel panel-hidden' id='panel-part-stock'>
|
||||
@ -132,10 +136,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='panel panel-hidden' id='panel-pricing'>
|
||||
<!-- TODO -->
|
||||
</div>
|
||||
|
||||
<div class='panel panel-hidden' id='panel-variants'>
|
||||
<div class='panel-heading'>
|
||||
<div class='d-flex flex-wrap'>
|
||||
@ -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 %}
|
||||
|
@ -14,9 +14,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<a href='#' id='breadcrumb-tree-toggle' class="breadcrumb-item"><i class="fas fa-bars"></i></a>
|
||||
{% 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 %}
|
||||
|
@ -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<pk>\d+)/', LocationDetail.as_view(), name='api-location-detail'),
|
||||
url(r'^.*$', StockLocationList.as_view(), name='api-location-list'),
|
||||
])),
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -9,9 +9,15 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<a href='#' id='breadcrumb-tree-toggle' class="breadcrumb-item"><i class="fas fa-bars"></i></a>
|
||||
{% include 'stock/loc_link.html' with location=item.location %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb_tree %}
|
||||
<div id="breadcrumb-tree"></div>
|
||||
{% 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 %}
|
||||
|
@ -7,6 +7,10 @@
|
||||
{% include "stock/location_sidebar.html" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb_tree %}
|
||||
<div id="breadcrumb-tree"></div>
|
||||
{% 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 %}
|
||||
|
@ -18,9 +18,10 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumbs %}
|
||||
<a href='#' id='breadcrumb-tree-toggle' class="breadcrumb-item"><i class="fas fa-bars"></i></a>
|
||||
{% if item %}
|
||||
{% include 'stock/loc_link.html' with location=item.location %}
|
||||
{% else %}
|
||||
{% include 'stock/loc_link.html' with location=location %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock breadcrumbs %}
|
||||
|
@ -74,13 +74,13 @@
|
||||
|
||||
<div class='row flex-nowrap inventree-body'>
|
||||
<div class='col-auto px-1 sidebar-wrapper'>
|
||||
<div id='sidebar' class='collapse collapse-horizontal show border-end' style='display: none;'>
|
||||
<div id='sidebar' class='collapse collapse-horizontal show' style='display: none;'>
|
||||
<div id='sidebar-nav' class='list-group text-sm-start'>
|
||||
<ul id='sidebar-list-group' class='list-group sidebar-list-group'>
|
||||
{% block sidebar %}
|
||||
<!-- Sidebar goes here -->
|
||||
{% endblock %}
|
||||
{% include "sidebar_toggle.html" %}
|
||||
{% include "sidebar_toggle.html" with target='sidebar' %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@ -104,14 +104,20 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block breadcrumb_list %}
|
||||
<div class='container-fluid navigation'>
|
||||
<div class='container-fluid navigation' id='breadcrumb-div'>
|
||||
<nav aria-label='breadcrumb'>
|
||||
<ol class='breadcrumb'>
|
||||
<ol class='breadcrumb' id='breadcrumb-list'>
|
||||
{% block breadcrumbs %}
|
||||
{% endblock %}
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div id='breadcrumb-tree-collapse' class='collapse collapse-horizontal show border' style='display: none;'>
|
||||
{% block breadcrumb_tree %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
@ -6,6 +6,7 @@
|
||||
addSidebarHeader,
|
||||
addSidebarItem,
|
||||
addSidebarLink,
|
||||
enableBreadcrumbTree,
|
||||
enableSidebar,
|
||||
onPanelLoad,
|
||||
*/
|
||||
@ -145,6 +146,101 @@ function enableSidebar(label, options={}) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable support for breadcrumb tree navigation on this page
|
||||
*/
|
||||
function enableBreadcrumbTree(options) {
|
||||
|
||||
var label = options.label;
|
||||
|
||||
if (!label) {
|
||||
console.log('ERROR: enableBreadcrumbTree called without supplying label');
|
||||
return;
|
||||
}
|
||||
|
||||
var filters = options.filters || {};
|
||||
|
||||
inventreeGet(
|
||||
options.url,
|
||||
filters,
|
||||
{
|
||||
success: function(data) {
|
||||
|
||||
// Data are returned from the InvenTree server as a flattened list;
|
||||
// We need to convert this into a tree structure
|
||||
|
||||
var nodes = {};
|
||||
var roots = [];
|
||||
var node = null;
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
node = data[i];
|
||||
node.nodes = [];
|
||||
nodes[node.pk] = node;
|
||||
node.selectable = false;
|
||||
|
||||
if (options.processNode) {
|
||||
node = options.processNode(node);
|
||||
}
|
||||
|
||||
node.state = {
|
||||
expanded: node.pk == options.selected,
|
||||
selected: node.pk == options.selected,
|
||||
};
|
||||
}
|
||||
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
node = data[i];
|
||||
|
||||
if (node.parent != null) {
|
||||
nodes[node.parent].nodes.push(node);
|
||||
|
||||
if (node.state.expanded) {
|
||||
nodes[node.parent].state.expanded = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
roots.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
$('#breadcrumb-tree').treeview({
|
||||
data: roots,
|
||||
showTags: true,
|
||||
enableLinks: true,
|
||||
expandIcon: 'fas fa-chevron-right',
|
||||
collapseIcon: 'fa fa-chevron-down',
|
||||
});
|
||||
|
||||
setBreadcrumbTreeState(label, state);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
$('#breadcrumb-tree-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!
|
||||
setBreadcrumbTreeState(label, state == 'expanded' ? 'collapsed' : 'expanded');
|
||||
});
|
||||
|
||||
// Set the initial state (default = expanded)
|
||||
var state = localStorage.getItem(`inventree-tree-state-${label}`) || 'expanded';
|
||||
|
||||
function setBreadcrumbTreeState(label, state) {
|
||||
|
||||
if (state == 'collapsed') {
|
||||
$('#breadcrumb-tree-collapse').hide(100);
|
||||
} else {
|
||||
$('#breadcrumb-tree-collapse').show(100);
|
||||
}
|
||||
|
||||
localStorage.setItem(`inventree-tree-state-${label}`, state);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the "toggle" state of the sidebar
|
||||
@ -180,7 +276,7 @@ function setSidebarState(label, state) {
|
||||
function addSidebarItem(options={}) {
|
||||
|
||||
var html = `
|
||||
<a href='#' id='select-${options.label}' title='${options.text}' class='list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate sidebar-selector' data-bs-parent='#sidebar'>
|
||||
<a href='#' id='select-${options.label}' title='${options.text}' class='list-group-item sidebar-list-group-item border-end d-inline-block text-truncate sidebar-selector' data-bs-parent='#sidebar'>
|
||||
<i class='bi bi-bootstrap'></i>
|
||||
${options.content_before || ''}
|
||||
<span class='sidebar-item-icon fas ${options.icon}'></span>
|
||||
@ -199,7 +295,7 @@ function addSidebarItem(options={}) {
|
||||
function addSidebarHeader(options={}) {
|
||||
|
||||
var html = `
|
||||
<span title='${options.text}' class="list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate" data-bs-parent="#sidebar">
|
||||
<span title='${options.text}' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate" data-bs-parent="#sidebar">
|
||||
<h6>
|
||||
<i class="bi bi-bootstrap"></i>
|
||||
<span class='sidebar-item-text' style='display: none;'>${options.text}</span>
|
||||
|
@ -1658,7 +1658,7 @@ function allocateStockToSalesOrder(order_id, line_items, options={}) {
|
||||
var available = Math.max((data.quantity || 0) - (data.allocated || 0), 0);
|
||||
|
||||
// Remaining quantity to be allocated?
|
||||
var remaining = opts.quantity || available;
|
||||
var remaining = Math.max(line_item.quantity - line_item.shipped - line_item.allocated, 0);
|
||||
|
||||
// Maximum amount that we need
|
||||
var desired = Math.min(available, remaining);
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
<span title='{{ text }}' class="list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate bg-light" data-bs-parent="#sidebar">
|
||||
<span title='{{ text }}' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate bg-light" data-bs-parent="#sidebar">
|
||||
<h6>
|
||||
<i class="bi bi-bootstrap"></i>
|
||||
{% if icon %}<span class='sidebar-item-icon fas {{ icon }}'></span>{% endif %}
|
||||
|
@ -1,5 +1,5 @@
|
||||
{% load i18n %}
|
||||
<a href="#" id='select-{{ label }}' title='{{ text }}' class="list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate sidebar-selector" data-bs-parent="#sidebar">
|
||||
<a href="#" id='select-{{ label }}' title='{{ text }}' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate sidebar-selector" data-bs-parent="#sidebar">
|
||||
<i class="bi bi-bootstrap"></i>
|
||||
<span class='sidebar-item-icon fas {{ icon|default:"fa-circle" }}'></span>
|
||||
<span class='sidebar-item-text' style='display: none;'>{{ text }}</span>
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% load i18n %}
|
||||
<a href="{{ url }}" class="list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate" data-bs-parent="#sidebar">
|
||||
<a href="{{ url }}" class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate" data-bs-parent="#sidebar">
|
||||
<i class="bi bi-bootstrap"></i><span class='sidebar-item-icon fas {{ icon }}'></span><span class='sidebar-item-text' style='display: none;'>{{ text }}</span>
|
||||
</a>
|
||||
|
@ -1,3 +1,4 @@
|
||||
<a href="#" id='sidebar-toggle' class="list-group-item sidebar-list-group-item border-end-0 d-inline-block text-truncate sidebar-toggle" data-bs-parent="#sidebar" style='display: none;'>
|
||||
<a href="#" id='{{ target }}-toggle' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate sidebar-toggle" data-bs-parent="#sidebar" style='display: none;'>
|
||||
<i class="bi bi-bootstrap"></i><span id='sidebar-toggle-icon' class='sidebar-item-icon fas fa-chevron-left'></span>
|
||||
{% if text %}<span class='sidebar-item-text' style='display: none;'>{{ text }}</span>{% endif %}
|
||||
</a>
|
||||
|
Loading…
Reference in New Issue
Block a user