1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

#6732: Add "add" and "import" buttons to each item as appropriate

This commit is contained in:
checktheroads
2021-05-22 18:11:56 -07:00
parent 0a01629b15
commit 7d640e2aab
2 changed files with 184 additions and 86 deletions

View File

@ -1,34 +1,68 @@
<div id="sidenav-accordion" class="accordion accordion-flush nav-item"> <div id="sidenav-accordion" class="accordion accordion-flush nav-item">
{% for menu in nav_items %} {% for menu in nav_items %}
<div class="accordion-item">
<a {# Main Collapsible Menu #}
href="#" <div class="accordion-item">
role="button" <a
aria-expanded="true" href="#"
data-bs-toggle="collapse" role="button"
data-bs-target="#{{ menu.label|lower }}" aria-expanded="true"
class="d-flex justify-content-between align-items-center accordion-button nav-link collapsed"> data-bs-toggle="collapse"
<span class="fw-bold sidebar-nav-link"> data-bs-target="#{{ menu.label|lower }}"
{{ menu.label }} class="d-flex justify-content-between align-items-center accordion-button nav-link collapsed">
</span> <span class="fw-bold sidebar-nav-link">
</a> {{ menu.label }}
<div id="{{ menu.label|lower }}" class="accordion-collapse collapse" data-bs-parent="#sidenav-accordion"> </span>
<div class="multi-level accordion-body px-0"> </a>
{% for group in menu.groups %}
<div class="flex-column nav px-2"> <div id="{{ menu.label|lower }}" class="accordion-collapse collapse" data-bs-parent="#sidenav-accordion">
{% if menu.groups|length > 1 %} <div class="multi-level accordion-body px-0">
<h6 class="accordion-item-title">{{ group.label }}</h6>
{% endif %} {% for item in group.items %} {% for group in menu.groups %}
<div class="nav-item"> {# Within each main menu, there are groups of menu items #}
<a class="nav-link" href="{% url item.url %}">{{ item.label }}</a> <div class="flex-column nav px-2">
</div>
{% if menu.groups|length > 1 %}
<h6 class="accordion-item-title">{{ group.label }}</h6>
{% endif %}
{% for item in group.items %}
{# Each Menu Item #}
<div class="nav-item d-flex justify-content-between align-items-center">
{# Menu Link with Text #}
<a class="nav-link flex-grow-1 me-1" href="{% url item.url %}">
{{ item.label }}
</a>
{# Add & Import Buttons #}
<div class="btn-group">
{% if item.has_add %}
<a class="btn btn-sm btn-success lh-1" href="{% url item.add_url %}" title="Add {{ item.label }}">
<i class="mdi mdi-plus-thick"></i>
</a>
{% endif %}
{% if item.has_import %}
<a class="btn btn-sm btn-outline-success lh-1" href="{% url item.import_url %}" title="Import {{ item.label }}">
<i class="mdi mdi-upload"></i>
</a>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{# Show a divider if not the last group #}
{% if forloop.counter != menu.groups|length %}
<hr class="dropdown-divider my-2" />
{% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% if forloop.counter != menu.groups|length %}
<hr class="dropdown-divider my-2" />
{% endif %} {% endfor %}
</div> </div>
</div> </div>
</div>
{% endfor %} {% endfor %}
</div> </div>

View File

@ -1,5 +1,5 @@
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, Sequence from typing import Dict, Sequence, Optional
from django import template from django import template
from django.template import Context from django.template import Context
from django.contrib.auth.context_processors import PermWrapper from django.contrib.auth.context_processors import PermWrapper
@ -14,6 +14,10 @@ class MenuItem:
label: str label: str
url: str url: str
disabled: bool = True disabled: bool = True
add_url: Optional[str] = None
import_url: Optional[str] = None
has_add: bool = False
has_import: bool = False
@dataclass @dataclass
@ -38,30 +42,41 @@ ORGANIZATION_MENU = Menu(
MenuGroup( MenuGroup(
label="Sites", label="Sites",
items=( items=(
MenuItem(label="Sites", url="dcim:site_list"), MenuItem(label="Sites", url="dcim:site_list",
MenuItem(label="Site Groups", url="dcim:sitegroup_list"), add_url="dcim:site_add", import_url="dcim:site_import"),
MenuItem(label="Regions", url="dcim:region_list"), MenuItem(label="Site Groups", url="dcim:sitegroup_list",
MenuItem(label="Locations", url="dcim:location_list"), add_url="dcim:sitegroup_add", import_url="dcim:sitegroup_import"),
MenuItem(label="Regions", url="dcim:region_list",
add_url="dcim:region_add", import_url="dcim:region_import"),
MenuItem(label="Locations", url="dcim:location_list",
add_url="dcim:location_add", import_url="dcim:location_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Racks", label="Racks",
items=( items=(
MenuItem(label="Racks", url="dcim:rack_list"), MenuItem(label="Racks", url="dcim:rack_list",
MenuItem(label="Rack Roles", url="dcim:rackrole_list"), add_url="dcim:rack_add", import_url="dcim:rack_import"),
MenuItem(label="Elevations", url="dcim:rack_elevation_list"), MenuItem(label="Rack Roles", url="dcim:rackrole_list",
add_url="dcim:rackrole_add", import_url="dcim:rackrole_import"),
MenuItem(label="Elevations", url="dcim:rack_elevation_list",
add_url=None, import_url=None),
), ),
), ),
MenuGroup( MenuGroup(
label="Tenancy", label="Tenancy",
items=( items=(
MenuItem(label="Tenants", url="tenancy:tenant_list"), MenuItem(label="Tenants", url="tenancy:tenant_list",
MenuItem(label="Tenant Groups", url="tenancy:tenantgroup_list"), add_url="tenancy:tenant_add", import_url="tenancy:tenant_import"),
MenuItem(label="Tenant Groups",
url="tenancy:tenantgroup_list", add_url="tenancy:tenantgroup_add",
import_url="tenancy:tenantgroup_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Tags", label="Tags",
items=(MenuItem(label="Tags", url="extras:tag_list"),), items=(MenuItem(label="Tags", url="extras:tag_list",
add_url="extras:tag_add", import_url="extras:tag_import"),),
), ),
), ),
) )
@ -72,46 +87,62 @@ DEVICES_MENU = Menu(
MenuGroup( MenuGroup(
label="Devices", label="Devices",
items=( items=(
MenuItem(label="Devices", url="dcim:device_list"), MenuItem(label="Devices", url="dcim:device_list",
MenuItem(label="Device Roles", url="dcim:devicerole_list"), add_url="dcim:device_add", import_url="dcim:device_import"),
MenuItem(label="Platforms", url="dcim:platform_list"), MenuItem(label="Device Roles", url="dcim:devicerole_list",
MenuItem(label="Virtual Chassis", url="dcim:virtualchassis_list"), add_url="dcim:devicerole_add", import_url="dcim:devicerole_import"),
MenuItem(label="Platforms", url="dcim:platform_list",
add_url="dcim:platform_add", import_url="dcim:platform_import"),
MenuItem(label="Virtual Chassis",
url="dcim:virtualchassis_list", add_url="dcim:virtualchassis_add",
import_url="dcim:virtualchassis_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Device Types", label="Device Types",
items=( items=(
MenuItem(label="Device Types", url="dcim:devicetype_list"), MenuItem(label="Device Types", url="dcim:devicetype_list",
MenuItem(label="Manufacturers", url="dcim:manufacturer_list"), add_url="dcim:devicetype_add", import_url="dcim:devicetype_import"),
MenuItem(label="Manufacturers", url="dcim:manufacturer_list",
add_url="dcim:manufacturer_add", import_url="dcim:manufacturer_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Connections", label="Connections",
items=( items=(
MenuItem(label="Cables", url="dcim:cable_list"), MenuItem(label="Cables", url="dcim:cable_list",
add_url=None, import_url="dcim:cable_import"),
MenuItem( MenuItem(
label="Console Connections", url="dcim:console_connections_list" label="Console Connections", url="dcim:console_connections_list", add_url=None, import_url=None,
), ),
MenuItem( MenuItem(
label="Interface Connections", url="dcim:interface_connections_list" label="Interface Connections", url="dcim:interface_connections_list", add_url=None, import_url=None,
), ),
MenuItem(label="Power Connections", url="dcim:power_connections_list"), MenuItem(label="Power Connections",
url="dcim:power_connections_list", add_url=None, import_url=None,),
), ),
), ),
MenuGroup( MenuGroup(
label="Device Components", label="Device Components",
items=( items=(
MenuItem(label="Interfaces", url="dcim:interface_list"), MenuItem(label="Interfaces", url="dcim:interface_list",
MenuItem(label="Front Ports", url="dcim:frontport_list"), add_url=None, import_url="dcim:interface_import"),
MenuItem(label="Rear Ports", url="dcim:rearport_list"), MenuItem(label="Front Ports", url="dcim:frontport_list",
MenuItem(label="Console Ports", url="dcim:consoleport_list"), add_url=None, import_url="dcim:frontport_import"),
MenuItem( MenuItem(label="Rear Ports", url="dcim:rearport_list",
label="Console Server Ports", url="dcim:consoleserverport_list" add_url=None, import_url="dcim:rearport_import"),
), MenuItem(label="Console Ports", url="dcim:consoleport_list",
MenuItem(label="Power Ports", url="dcim:powerport_list"), add_url=None, import_url="dcim:consoleport_import"),
MenuItem(label="Power Outlets", url="dcim:poweroutlet_list"), MenuItem(label="Console Server Ports", url="dcim:consoleserverport_list",
MenuItem(label="Device Bays", url="dcim:devicebay_list"), add_url=None, import_url="dcim:consoleserverport_import"),
MenuItem(label="Inventory Items", url="dcim:inventoryitem_list"), MenuItem(label="Power Ports", url="dcim:powerport_list",
add_url=None, import_url="dcim:powerport_import"),
MenuItem(label="Power Outlets", url="dcim:poweroutlet_list",
add_url=None, import_url="dcim:poweroutlet_import"),
MenuItem(label="Device Bays", url="dcim:devicebay_list",
add_url=None, import_url="dcim:devicebay_import"),
MenuItem(label="Inventory Items",
url="dcim:inventoryitem_list", add_url=None, import_url="dcim:inventoryitem_import"),
), ),
), ),
), ),
@ -122,39 +153,51 @@ IPAM_MENU = Menu(
groups=( groups=(
MenuGroup( MenuGroup(
label="IP Addresses", label="IP Addresses",
items=(MenuItem(label="IP Addresses", url="ipam:ipaddress_list"),), items=(
MenuItem(label="IP Addresses", url="ipam:ipaddress_list",
add_url="ipam:ipaddress_add", import_url="ipam:ipaddress_import"),
),
), ),
MenuGroup( MenuGroup(
label="Prefixes", label="Prefixes",
items=( items=(
MenuItem(label="Prefixes", url="ipam:prefix_list"), MenuItem(label="Prefixes", url="ipam:prefix_list",
MenuItem(label="Prefix & VLAN Roles", url="ipam:role_list"), add_url="ipam:prefix_add", import_url="ipam:prefix_import"),
MenuItem(label="Prefix & VLAN Roles", url="ipam:role_list",
add_url="ipam:role_add", import_url="ipam:role_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Aggregates", label="Aggregates",
items=( items=(
MenuItem(label="Aggregates", url="ipam:aggregate_list"), MenuItem(label="Aggregates", url="ipam:aggregate_list",
MenuItem(label="RIRs", url="ipam:rir_list"), add_url="ipam:aggregate_add", import_url="ipam:aggregate_import"),
MenuItem(label="RIRs", url="ipam:rir_list",
add_url="ipam:rir_add", import_url="ipam:rir_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="VRFs", label="VRFs",
items=( items=(
MenuItem(label="VRFs", url="ipam:vrf_list"), MenuItem(label="VRFs", url="ipam:vrf_list",
MenuItem(label="Route Targets", url="ipam:routetarget_list"), add_url="ipam:vrf_add", import_url="ipam:vrf_import"),
MenuItem(label="Route Targets", url="ipam:routetarget_list",
add_url="ipam:routetarget_add", import_url="ipam:routetarget_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="VLANs", label="VLANs",
items=( items=(
MenuItem(label="VLANs", url="ipam:vlan_list"), MenuItem(label="VLANs", url="ipam:vlan_list",
MenuItem(label="VLAN Groups", url="ipam:vlangroup_list"), add_url="ipam:vlan_add", import_url="ipam:vlan_import"),
MenuItem(label="VLAN Groups", url="ipam:vlangroup_list",
add_url="ipam:vlangroup_add", import_url="ipam:vlangroup_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Services", label="Services",
items=(MenuItem(label="Services", url="ipam:service_list"),), items=(MenuItem(label="Services", url="ipam:service_list",
add_url=None, import_url="ipam:service_import"),),
), ),
), ),
) )
@ -167,19 +210,20 @@ VIRTUALIZATION_MENU = Menu(
items=( items=(
MenuItem( MenuItem(
label="Virtual Machines", label="Virtual Machines",
url="virtualization:virtualmachine_list", url="virtualization:virtualmachine_list", add_url="virtualization:virtualmachine_add", import_url="virtualization:virtualmachine_import"),
), MenuItem(label="Interfaces",
MenuItem(label="Interfaces", url="virtualization:vminterface_list"), url="virtualization:vminterface_list", add_url="virtualization:vminterface_add", import_url="virtualization:vminterface_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Clusters", label="Clusters",
items=( items=(
MenuItem(label="Clusters", url="virtualization:cluster_list"), MenuItem(label="Clusters", url="virtualization:cluster_list",
MenuItem(label="Cluster Types", url="virtualization:clustertype_list"), add_url="virtualization:cluster_add", import_url="virtualization:cluster_import"),
MenuItem(label="Cluster Types",
url="virtualization:clustertype_list", add_url="virtualization:clustertype_add", import_url="virtualization:clustertype_import"),
MenuItem( MenuItem(
label="Cluster Groups", url="virtualization:clustergroup_list" label="Cluster Groups", url="virtualization:clustergroup_list", add_url="virtualization:clustergroup_add", import_url="virtualization:clustergroup_import"),
),
), ),
), ),
), ),
@ -191,16 +235,19 @@ CIRCUITS_MENU = Menu(
MenuGroup( MenuGroup(
label="Circuits", label="Circuits",
items=( items=(
MenuItem(label="Circuits", url="circuits:circuit_list"), MenuItem(label="Circuits", url="circuits:circuit_list",
MenuItem(label="Circuit Types", url="circuits:circuittype_list"), add_url="circuits:circuit_add", import_url="circuits:circuit_import"),
MenuItem(label="Circuit Types",
url="circuits:circuittype_list", add_url="circuits:circuittype_add", import_url="circuits:circuittype_import"),
), ),
), ),
MenuGroup( MenuGroup(
label="Providers", label="Providers",
items=( items=(
MenuItem(label="Providers", url="circuits:provider_list"), MenuItem(label="Providers", url="circuits:provider_list",
add_url="circuits:provider_add", import_url="circuits:provider_import"),
MenuItem( MenuItem(
label="Provider Networks", url="circuits:providernetwork_list" label="Provider Networks", url="circuits:providernetwork_list", add_url="circuits:providernetwork_add", import_url="circuits:providernetwork_import"
), ),
), ),
), ),
@ -213,8 +260,10 @@ POWER_MENU = Menu(
MenuGroup( MenuGroup(
label="Power", label="Power",
items=( items=(
MenuItem(label="Power Feeds", url="dcim:powerfeed_list"), MenuItem(label="Power Feeds", url="dcim:powerfeed_list",
MenuItem(label="Power Panels", url="dcim:powerpanel_list"), add_url="dcim:powerfeed_add", import_url="dcim:powerfeed_import"),
MenuItem(label="Power Panels", url="dcim:powerpanel_list",
add_url="dcim:powerpanel_add", import_url="dcim:powerpanel_import"),
), ),
), ),
), ),
@ -226,16 +275,21 @@ OTHER_MENU = Menu(
MenuGroup( MenuGroup(
label="Logging", label="Logging",
items=( items=(
MenuItem(label="Change Log", url="extras:objectchange_list"), MenuItem(label="Change Log", url="extras:objectchange_list",
MenuItem(label="Journal Entries", url="extras:journalentry_list"), add_url=None, import_url=None),
MenuItem(label="Journal Entries",
url="extras:journalentry_list", add_url=None, import_url=None),
), ),
), ),
MenuGroup( MenuGroup(
label="Miscellaneous", label="Miscellaneous",
items=( items=(
MenuItem(label="Config Contexts", url="extras:configcontext_list"), MenuItem(label="Config Contexts",
MenuItem(label="Reports", url="extras:report_list"), url="extras:configcontext_list", add_url=None, import_url=None),
MenuItem(label="Scripts", url="extras:script_list"), MenuItem(label="Reports", url="extras:report_list",
add_url=None, import_url=None),
MenuItem(label="Scripts", url="extras:script_list",
add_url=None, import_url=None),
), ),
), ),
), ),
@ -258,12 +312,22 @@ def process_menu(menu: Menu, perms: PermWrapper) -> MenuGroup:
for item in group.items: for item in group.items:
# Parse the URL template tag to a permission string. # Parse the URL template tag to a permission string.
app, scope = item.url.split(":") app, scope = item.url.split(":")
object_name = scope.replace("_list", "")
view_perm = f"{app}.view_{scope}" view_perm = f"{app}.view_{scope}"
add_perm = f"{app}.add_object_name"
if view_perm in perms: if view_perm in perms:
# If the view permission for each item exists, toggle # If the view permission for each item exists, toggle
# the `disabled` field, which will be used in the UI. # the `disabled` field, which will be used in the UI.
item.disabled = False item.disabled = False
if add_perm in perms:
if item.add_url is not None:
item.has_add = True
if item.import_url is not None:
item.has_import = True
return menu return menu