Просмотр исходного кода

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

checktheroads 4 лет назад
Родитель
Сommit
6b1397d257
2 измененных файлов с 184 добавлено и 86 удалено
  1. 60 26
      netbox/utilities/templates/navigation/nav_items.html
  2. 124 60
      netbox/utilities/templatetags/nav.py

+ 60 - 26
netbox/utilities/templates/navigation/nav_items.html

@@ -1,34 +1,68 @@
 <div id="sidenav-accordion" class="accordion accordion-flush nav-item">
   {% for menu in nav_items %}
-  <div class="accordion-item">
-    <a
-      href="#"
-      role="button"
-      aria-expanded="true"
-      data-bs-toggle="collapse"
-      data-bs-target="#{{ menu.label|lower }}"
-      class="d-flex justify-content-between align-items-center accordion-button nav-link collapsed">
-        <span class="fw-bold sidebar-nav-link">
-          {{ menu.label }}
-        </span>
-      </a>
-    <div id="{{ menu.label|lower }}" class="accordion-collapse collapse" data-bs-parent="#sidenav-accordion">
-      <div class="multi-level accordion-body px-0">
-        {% for group in menu.groups %}
-        <div class="flex-column nav px-2">
-          {% if menu.groups|length > 1 %}
-          <h6 class="accordion-item-title">{{ group.label }}</h6>
-          {% endif %} {% for item in group.items %}
-          <div class="nav-item">
-            <a class="nav-link" href="{% url item.url %}">{{ item.label }}</a>
-          </div>
+
+    {# Main Collapsible Menu #}
+    <div class="accordion-item">
+      <a
+        href="#"
+        role="button"
+        aria-expanded="true"
+        data-bs-toggle="collapse"
+        data-bs-target="#{{ menu.label|lower }}"
+        class="d-flex justify-content-between align-items-center accordion-button nav-link collapsed">
+          <span class="fw-bold sidebar-nav-link">
+            {{ menu.label }}
+          </span>
+        </a>
+
+      <div id="{{ menu.label|lower }}" class="accordion-collapse collapse" data-bs-parent="#sidenav-accordion">
+        <div class="multi-level accordion-body px-0">
+          
+          {% for group in menu.groups %}
+            {# Within each main menu, there are groups of menu items #}
+            <div class="flex-column nav px-2">
+              
+              {% 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 %}
+
         </div>
-        {% if forloop.counter != menu.groups|length %}
-        <hr class="dropdown-divider my-2" />
-        {% endif %} {% endfor %}
       </div>
     </div>
-  </div>
   {% endfor %}
 </div>

+ 124 - 60
netbox/utilities/templatetags/nav.py

@@ -1,5 +1,5 @@
 from dataclasses import dataclass
-from typing import Dict, Sequence
+from typing import Dict, Sequence, Optional
 from django import template
 from django.template import Context
 from django.contrib.auth.context_processors import PermWrapper
@@ -14,6 +14,10 @@ class MenuItem:
     label: str
     url: str
     disabled: bool = True
+    add_url: Optional[str] = None
+    import_url: Optional[str] = None
+    has_add: bool = False
+    has_import: bool = False
 
 
 @dataclass
@@ -38,30 +42,41 @@ ORGANIZATION_MENU = Menu(
         MenuGroup(
             label="Sites",
             items=(
-                MenuItem(label="Sites", url="dcim:site_list"),
-                MenuItem(label="Site Groups", url="dcim:sitegroup_list"),
-                MenuItem(label="Regions", url="dcim:region_list"),
-                MenuItem(label="Locations", url="dcim:location_list"),
+                MenuItem(label="Sites", url="dcim:site_list",
+                         add_url="dcim:site_add", import_url="dcim:site_import"),
+                MenuItem(label="Site Groups", url="dcim:sitegroup_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(
             label="Racks",
             items=(
-                MenuItem(label="Racks", url="dcim:rack_list"),
-                MenuItem(label="Rack Roles", url="dcim:rackrole_list"),
-                MenuItem(label="Elevations", url="dcim:rack_elevation_list"),
+                MenuItem(label="Racks", url="dcim:rack_list",
+                         add_url="dcim:rack_add", import_url="dcim:rack_import"),
+                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(
             label="Tenancy",
             items=(
-                MenuItem(label="Tenants", url="tenancy:tenant_list"),
-                MenuItem(label="Tenant Groups", url="tenancy:tenantgroup_list"),
+                MenuItem(label="Tenants", url="tenancy:tenant_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(
             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(
             label="Devices",
             items=(
-                MenuItem(label="Devices", url="dcim:device_list"),
-                MenuItem(label="Device Roles", url="dcim:devicerole_list"),
-                MenuItem(label="Platforms", url="dcim:platform_list"),
-                MenuItem(label="Virtual Chassis", url="dcim:virtualchassis_list"),
+                MenuItem(label="Devices", url="dcim:device_list",
+                         add_url="dcim:device_add", import_url="dcim:device_import"),
+                MenuItem(label="Device Roles", url="dcim:devicerole_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(
             label="Device Types",
             items=(
-                MenuItem(label="Device Types", url="dcim:devicetype_list"),
-                MenuItem(label="Manufacturers", url="dcim:manufacturer_list"),
+                MenuItem(label="Device Types", url="dcim:devicetype_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(
             label="Connections",
             items=(
-                MenuItem(label="Cables", url="dcim:cable_list"),
+                MenuItem(label="Cables", url="dcim:cable_list",
+                         add_url=None, import_url="dcim:cable_import"),
                 MenuItem(
-                    label="Console Connections", url="dcim:console_connections_list"
+                    label="Console Connections", url="dcim:console_connections_list", add_url=None, import_url=None,
                 ),
                 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(
             label="Device Components",
             items=(
-                MenuItem(label="Interfaces", url="dcim:interface_list"),
-                MenuItem(label="Front Ports", url="dcim:frontport_list"),
-                MenuItem(label="Rear Ports", url="dcim:rearport_list"),
-                MenuItem(label="Console Ports", url="dcim:consoleport_list"),
-                MenuItem(
-                    label="Console Server Ports", url="dcim:consoleserverport_list"
-                ),
-                MenuItem(label="Power Ports", url="dcim:powerport_list"),
-                MenuItem(label="Power Outlets", url="dcim:poweroutlet_list"),
-                MenuItem(label="Device Bays", url="dcim:devicebay_list"),
-                MenuItem(label="Inventory Items", url="dcim:inventoryitem_list"),
+                MenuItem(label="Interfaces", url="dcim:interface_list",
+                         add_url=None, import_url="dcim:interface_import"),
+                MenuItem(label="Front Ports", url="dcim:frontport_list",
+                         add_url=None, import_url="dcim:frontport_import"),
+                MenuItem(label="Rear Ports", url="dcim:rearport_list",
+                         add_url=None, import_url="dcim:rearport_import"),
+                MenuItem(label="Console Ports", url="dcim:consoleport_list",
+                         add_url=None, import_url="dcim:consoleport_import"),
+                MenuItem(label="Console Server Ports", url="dcim:consoleserverport_list",
+                         add_url=None, import_url="dcim:consoleserverport_import"),
+                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=(
         MenuGroup(
             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(
             label="Prefixes",
             items=(
-                MenuItem(label="Prefixes", url="ipam:prefix_list"),
-                MenuItem(label="Prefix & VLAN Roles", url="ipam:role_list"),
+                MenuItem(label="Prefixes", url="ipam:prefix_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(
             label="Aggregates",
             items=(
-                MenuItem(label="Aggregates", url="ipam:aggregate_list"),
-                MenuItem(label="RIRs", url="ipam:rir_list"),
+                MenuItem(label="Aggregates", url="ipam:aggregate_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(
             label="VRFs",
             items=(
-                MenuItem(label="VRFs", url="ipam:vrf_list"),
-                MenuItem(label="Route Targets", url="ipam:routetarget_list"),
+                MenuItem(label="VRFs", url="ipam:vrf_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(
             label="VLANs",
             items=(
-                MenuItem(label="VLANs", url="ipam:vlan_list"),
-                MenuItem(label="VLAN Groups", url="ipam:vlangroup_list"),
+                MenuItem(label="VLANs", url="ipam:vlan_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(
             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=(
                 MenuItem(
                     label="Virtual Machines",
-                    url="virtualization:virtualmachine_list",
-                ),
-                MenuItem(label="Interfaces", url="virtualization:vminterface_list"),
+                    url="virtualization:virtualmachine_list", add_url="virtualization:virtualmachine_add", import_url="virtualization:virtualmachine_import"),
+                MenuItem(label="Interfaces",
+                         url="virtualization:vminterface_list", add_url="virtualization:vminterface_add", import_url="virtualization:vminterface_import"),
             ),
         ),
         MenuGroup(
             label="Clusters",
             items=(
-                MenuItem(label="Clusters", url="virtualization:cluster_list"),
-                MenuItem(label="Cluster Types", url="virtualization:clustertype_list"),
+                MenuItem(label="Clusters", url="virtualization:cluster_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(
-                    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(
             label="Circuits",
             items=(
-                MenuItem(label="Circuits", url="circuits:circuit_list"),
-                MenuItem(label="Circuit Types", url="circuits:circuittype_list"),
+                MenuItem(label="Circuits", url="circuits:circuit_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(
             label="Providers",
             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(
-                    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(
             label="Power",
             items=(
-                MenuItem(label="Power Feeds", url="dcim:powerfeed_list"),
-                MenuItem(label="Power Panels", url="dcim:powerpanel_list"),
+                MenuItem(label="Power Feeds", url="dcim:powerfeed_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(
             label="Logging",
             items=(
-                MenuItem(label="Change Log", url="extras:objectchange_list"),
-                MenuItem(label="Journal Entries", url="extras:journalentry_list"),
+                MenuItem(label="Change Log", url="extras:objectchange_list",
+                         add_url=None, import_url=None),
+                MenuItem(label="Journal Entries",
+                         url="extras:journalentry_list", add_url=None, import_url=None),
             ),
         ),
         MenuGroup(
             label="Miscellaneous",
             items=(
-                MenuItem(label="Config Contexts", url="extras:configcontext_list"),
-                MenuItem(label="Reports", url="extras:report_list"),
-                MenuItem(label="Scripts", url="extras:script_list"),
+                MenuItem(label="Config Contexts",
+                         url="extras:configcontext_list", add_url=None, import_url=None),
+                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:
             # Parse the URL template tag to a permission string.
             app, scope = item.url.split(":")
+            object_name = scope.replace("_list", "")
+
             view_perm = f"{app}.view_{scope}"
+            add_perm = f"{app}.add_object_name"
+
             if view_perm in perms:
                 # If the view permission for each item exists, toggle
                 # the `disabled` field, which will be used in the UI.
                 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