mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	Feature/icons for PartCategory and StockLocation (#3542)
* Added icon to stock location - added `icon` field to `stock_stocklocation` model - added input field to stock location form - added icon to breadcrumb treeview in header - added icon to sub-locations table - added icon to location detail information - added `STOCK_LOCATION_DEFAULT_ICON` setting as default * Added icon to part category - added `icon` field to `part_partcategory` model - added input field to part category form - added icon to breadcrumb treeview in header - added icon to sub-categories table - added icon to category detail information - added `PART_CATEGORY_DEFAULT_ICON` setting as default * Added `blocktrans` to allowed tags in ci check * fix: style * Added `endblocktrans` to allowed tags in ci check * fix: missing `,` in ci check allowed tags script * Removed blocktrans from js and fixed style
This commit is contained in:
		@@ -1028,3 +1028,8 @@ a {
 | 
				
			|||||||
    margin-top: 3px;
 | 
					    margin-top: 3px;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.treeview .node-icon {
 | 
				
			||||||
 | 
					    margin-left: 0.25rem;
 | 
				
			||||||
 | 
					    margin-right: 0.25rem;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1070,6 +1070,12 @@ class InvenTreeSetting(BaseInvenTreeSetting):
 | 
				
			|||||||
            'validator': InvenTree.validators.validate_part_name_format
 | 
					            'validator': InvenTree.validators.validate_part_name_format
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        'PART_CATEGORY_DEFAULT_ICON': {
 | 
				
			||||||
 | 
					            'name': _('Part Category Default Icon'),
 | 
				
			||||||
 | 
					            'description': _('Part category default icon (empty means no icon)'),
 | 
				
			||||||
 | 
					            'default': '',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'LABEL_ENABLE': {
 | 
					        'LABEL_ENABLE': {
 | 
				
			||||||
            'name': _('Enable label printing'),
 | 
					            'name': _('Enable label printing'),
 | 
				
			||||||
            'description': _('Enable label printing from the web interface'),
 | 
					            'description': _('Enable label printing from the web interface'),
 | 
				
			||||||
@@ -1168,6 +1174,12 @@ class InvenTreeSetting(BaseInvenTreeSetting):
 | 
				
			|||||||
            'validator': bool,
 | 
					            'validator': bool,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        'STOCK_LOCATION_DEFAULT_ICON': {
 | 
				
			||||||
 | 
					            'name': _('Stock Location Default Icon'),
 | 
				
			||||||
 | 
					            'description': _('Stock location default icon (empty means no icon)'),
 | 
				
			||||||
 | 
					            'default': '',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'BUILDORDER_REFERENCE_PATTERN': {
 | 
					        'BUILDORDER_REFERENCE_PATTERN': {
 | 
				
			||||||
            'name': _('Build Order Reference Pattern'),
 | 
					            'name': _('Build Order Reference Pattern'),
 | 
				
			||||||
            'description': _('Required pattern for generating Build Order reference field'),
 | 
					            'description': _('Required pattern for generating Build Order reference field'),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								InvenTree/part/migrations/0084_partcategory_icon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								InvenTree/part/migrations/0084_partcategory_icon.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Generated by Django 3.2.15 on 2022-08-15 08:38
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('part', '0083_auto_20220731_2357'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='partcategory',
 | 
				
			||||||
 | 
					            name='icon',
 | 
				
			||||||
 | 
					            field=models.CharField(blank=True, help_text='Icon (optional)', max_length=100, verbose_name='Icon'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -101,6 +101,13 @@ class PartCategory(MetadataMixin, InvenTreeTree):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    default_keywords = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Default keywords'), help_text=_('Default keywords for parts in this category'))
 | 
					    default_keywords = models.CharField(null=True, blank=True, max_length=250, verbose_name=_('Default keywords'), help_text=_('Default keywords for parts in this category'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    icon = models.CharField(
 | 
				
			||||||
 | 
					        blank=True,
 | 
				
			||||||
 | 
					        max_length=100,
 | 
				
			||||||
 | 
					        verbose_name=_("Icon"),
 | 
				
			||||||
 | 
					        help_text=_("Icon (optional)")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def get_api_url():
 | 
					    def get_api_url():
 | 
				
			||||||
        """Return the API url associated with the PartCategory model"""
 | 
					        """Return the API url associated with the PartCategory model"""
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,6 +75,7 @@ class CategorySerializer(InvenTreeModelSerializer):
 | 
				
			|||||||
            'pathstring',
 | 
					            'pathstring',
 | 
				
			||||||
            'starred',
 | 
					            'starred',
 | 
				
			||||||
            'url',
 | 
					            'url',
 | 
				
			||||||
 | 
					            'icon',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -88,6 +89,7 @@ class CategoryTree(InvenTreeModelSerializer):
 | 
				
			|||||||
            'pk',
 | 
					            'pk',
 | 
				
			||||||
            'name',
 | 
					            'name',
 | 
				
			||||||
            'parent',
 | 
					            'parent',
 | 
				
			||||||
 | 
					            'icon',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
{% extends "part/part_app_base.html" %}
 | 
					{% extends "part/part_app_base.html" %}
 | 
				
			||||||
{% load static %}
 | 
					{% load static %}
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					{% load inventree_extras %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block sidebar %}
 | 
					{% block sidebar %}
 | 
				
			||||||
{% include 'part/category_sidebar.html' %}
 | 
					{% include 'part/category_sidebar.html' %}
 | 
				
			||||||
@@ -12,7 +13,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{% block heading %}
 | 
					{% block heading %}
 | 
				
			||||||
{% if category %}
 | 
					{% if category %}
 | 
				
			||||||
{% trans "Part Category" %}: {{ category.name }}
 | 
					{% trans "Part Category" %}:
 | 
				
			||||||
 | 
					{% settings_value "PART_CATEGORY_DEFAULT_ICON" as default_icon %}
 | 
				
			||||||
 | 
					{% if category.icon or default_icon %}
 | 
				
			||||||
 | 
					<span class="{{ category.icon|default:default_icon }}"></span>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					{{ category.name }}
 | 
				
			||||||
{% else %}
 | 
					{% else %}
 | 
				
			||||||
{% trans "Parts" %}
 | 
					{% trans "Parts" %}
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
@@ -288,7 +294,8 @@
 | 
				
			|||||||
            node.href = `/part/category/${node.pk}/`;
 | 
					            node.href = `/part/category/${node.pk}/`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return node;
 | 
					            return node;
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
 | 
					        defaultIcon: global_settings.PART_CATEGORY_DEFAULT_ICON,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onPanelLoad('subcategories', function() {
 | 
					    onPanelLoad('subcategories', function() {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								InvenTree/stock/migrations/0083_stocklocation_icon.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								InvenTree/stock/migrations/0083_stocklocation_icon.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Generated by Django 3.2.15 on 2022-08-15 08:38
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('stock', '0082_alter_stockitem_link'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='stocklocation',
 | 
				
			||||||
 | 
					            name='icon',
 | 
				
			||||||
 | 
					            field=models.CharField(blank=True, help_text='Icon (optional)', max_length=100, verbose_name='Icon'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -78,6 +78,13 @@ class StockLocation(MetadataMixin, InvenTreeTree):
 | 
				
			|||||||
        """Return API url."""
 | 
					        """Return API url."""
 | 
				
			||||||
        return reverse('api-location-list')
 | 
					        return reverse('api-location-list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    icon = models.CharField(
 | 
				
			||||||
 | 
					        blank=True,
 | 
				
			||||||
 | 
					        max_length=100,
 | 
				
			||||||
 | 
					        verbose_name=_("Icon"),
 | 
				
			||||||
 | 
					        help_text=_("Icon (optional)")
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    owner = models.ForeignKey(Owner, on_delete=models.SET_NULL, blank=True, null=True,
 | 
					    owner = models.ForeignKey(Owner, on_delete=models.SET_NULL, blank=True, null=True,
 | 
				
			||||||
                              verbose_name=_('Owner'),
 | 
					                              verbose_name=_('Owner'),
 | 
				
			||||||
                              help_text=_('Select Owner'),
 | 
					                              help_text=_('Select Owner'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -570,6 +570,7 @@ class LocationTreeSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 | 
				
			|||||||
            'pk',
 | 
					            'pk',
 | 
				
			||||||
            'name',
 | 
					            'name',
 | 
				
			||||||
            'parent',
 | 
					            'parent',
 | 
				
			||||||
 | 
					            'icon',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -607,6 +608,7 @@ class LocationSerializer(InvenTree.serializers.InvenTreeModelSerializer):
 | 
				
			|||||||
            'pathstring',
 | 
					            'pathstring',
 | 
				
			||||||
            'items',
 | 
					            'items',
 | 
				
			||||||
            'owner',
 | 
					            'owner',
 | 
				
			||||||
 | 
					            'icon',
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{% block heading %}
 | 
					{% block heading %}
 | 
				
			||||||
{% if location %}
 | 
					{% if location %}
 | 
				
			||||||
{% trans "Stock Location" %}: {{ location.name }}
 | 
					{% trans "Stock Location" %}:
 | 
				
			||||||
 | 
					{% settings_value "STOCK_LOCATION_DEFAULT_ICON" as default_icon %}
 | 
				
			||||||
 | 
					{% if location.icon or default_icon %}
 | 
				
			||||||
 | 
					<span class="{{ location.icon|default:default_icon }}"></span>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					{{ location.name }}
 | 
				
			||||||
{% else %}
 | 
					{% else %}
 | 
				
			||||||
{% trans "Stock" %}
 | 
					{% trans "Stock" %}
 | 
				
			||||||
{% endif %}
 | 
					{% endif %}
 | 
				
			||||||
@@ -380,7 +385,8 @@
 | 
				
			|||||||
            node.href = `/stock/location/${node.pk}/`;
 | 
					            node.href = `/stock/location/${node.pk}/`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return node;
 | 
					            return node;
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
 | 
					        defaultIcon: global_settings.STOCK_LOCATION_DEFAULT_ICON,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,6 +36,8 @@
 | 
				
			|||||||
        <tr><td colspan='5'></td></tr>
 | 
					        <tr><td colspan='5'></td></tr>
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="PART_INTERNAL_PRICE" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="PART_INTERNAL_PRICE" %}
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="PART_BOM_USE_INTERNAL_PRICE" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="PART_BOM_USE_INTERNAL_PRICE" %}
 | 
				
			||||||
 | 
					        <tr><td colspan='5'></td></tr>
 | 
				
			||||||
 | 
					        {% include "InvenTree/settings/setting.html" with key="PART_CATEGORY_DEFAULT_ICON" icon="fa-icons" %}
 | 
				
			||||||
    </tbody>
 | 
					    </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,6 +17,7 @@
 | 
				
			|||||||
        {% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_SALE" icon="fa-truck" %}
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_BUILD" icon="fa-tools" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="STOCK_ALLOW_EXPIRED_BUILD" icon="fa-tools" %}
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="STOCK_OWNERSHIP_CONTROL" icon="fa-users" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="STOCK_OWNERSHIP_CONTROL" icon="fa-users" %}
 | 
				
			||||||
 | 
					        {% include "InvenTree/settings/setting.html" with key="STOCK_LOCATION_DEFAULT_ICON" icon="fa-icons" %}
 | 
				
			||||||
    </tbody>
 | 
					    </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -216,6 +216,7 @@ function enableBreadcrumbTree(options) {
 | 
				
			|||||||
                    enableLinks: true,
 | 
					                    enableLinks: true,
 | 
				
			||||||
                    expandIcon: 'fas fa-chevron-right',
 | 
					                    expandIcon: 'fas fa-chevron-right',
 | 
				
			||||||
                    collapseIcon: 'fa fa-chevron-down',
 | 
					                    collapseIcon: 'fa fa-chevron-down',
 | 
				
			||||||
 | 
					                    nodeIcon: options.defaultIcon,
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -301,7 +301,11 @@ function categoryFields() {
 | 
				
			|||||||
        default_location: {},
 | 
					        default_location: {},
 | 
				
			||||||
        default_keywords: {
 | 
					        default_keywords: {
 | 
				
			||||||
            icon: 'fa-key',
 | 
					            icon: 'fa-key',
 | 
				
			||||||
        }
 | 
					        },
 | 
				
			||||||
 | 
					        icon: {
 | 
				
			||||||
 | 
					            help_text: `{% trans "Icon (optional) - Explore all available icons on" %} <a href="https://fontawesome.com/v5/search?s=solid" target="_blank" rel="noopener noreferrer">Font Awesome</a>.`,
 | 
				
			||||||
 | 
					            placeholder: 'fas fa-tag',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1916,6 +1920,11 @@ function loadPartCategoryTable(table, options) {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const icon = row.icon || global_settings.PART_CATEGORY_DEFAULT_ICON;
 | 
				
			||||||
 | 
					                    if (icon) {
 | 
				
			||||||
 | 
					                        html += `<span class="${icon} me-1"></span>`;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    html += renderLink(
 | 
					                    html += renderLink(
 | 
				
			||||||
                        value,
 | 
					                        value,
 | 
				
			||||||
                        `/part/category/${row.pk}/`
 | 
					                        `/part/category/${row.pk}/`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -114,6 +114,10 @@ function stockLocationFields(options={}) {
 | 
				
			|||||||
        name: {},
 | 
					        name: {},
 | 
				
			||||||
        description: {},
 | 
					        description: {},
 | 
				
			||||||
        owner: {},
 | 
					        owner: {},
 | 
				
			||||||
 | 
					        icon: {
 | 
				
			||||||
 | 
					            help_text: `{% trans "Icon (optional) - Explore all available icons on" %} <a href="https://fontawesome.com/v5/search?s=solid" target="_blank" rel="noopener noreferrer">Font Awesome</a>.`,
 | 
				
			||||||
 | 
					            placeholder: 'fas fa-box',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (options.parent) {
 | 
					    if (options.parent) {
 | 
				
			||||||
@@ -2402,6 +2406,11 @@ function loadStockLocationTable(table, options) {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const icon = row.icon || global_settings.STOCK_LOCATION_DEFAULT_ICON;
 | 
				
			||||||
 | 
					                    if (icon) {
 | 
				
			||||||
 | 
					                        html += `<span class="${icon} me-1"></span>`;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    html += renderLink(
 | 
					                    html += renderLink(
 | 
				
			||||||
                        value,
 | 
					                        value,
 | 
				
			||||||
                        `/stock/location/${row.pk}/`
 | 
					                        `/stock/location/${row.pk}/`
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user