mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-18 04:56:29 -06:00
Merge branch 'jstretch-ui-work' into feature
This commit is contained in:
commit
5406acf329
322
netbox/netbox/navigation_menu.py
Normal file
322
netbox/netbox/navigation_menu.py
Normal file
@ -0,0 +1,322 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence, Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class MenuItem:
|
||||
"""A navigation menu item link. Example: Sites, Platforms, RIRs, etc."""
|
||||
|
||||
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
|
||||
class MenuGroup:
|
||||
"""A group of menu items within a menu."""
|
||||
|
||||
label: str
|
||||
items: Sequence[MenuItem]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Menu:
|
||||
"""A top level menu group. Example: Organization, Devices, IPAM."""
|
||||
|
||||
label: str
|
||||
icon: str
|
||||
groups: Sequence[MenuGroup]
|
||||
|
||||
|
||||
ORGANIZATION_MENU = Menu(
|
||||
label="Organization",
|
||||
icon="domain",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Sites",
|
||||
items=(
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
add_url="extras:tag_add", import_url="extras:tag_import"),),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
DEVICES_MENU = Menu(
|
||||
label="Devices",
|
||||
icon="server",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Devices",
|
||||
items=(
|
||||
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",
|
||||
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",
|
||||
add_url=None, import_url="dcim:cable_import"),
|
||||
MenuItem(
|
||||
label="Console Connections", url="dcim:console_connections_list", add_url=None, import_url=None,
|
||||
),
|
||||
MenuItem(
|
||||
label="Interface Connections", url="dcim:interface_connections_list", add_url=None, import_url=None,
|
||||
),
|
||||
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",
|
||||
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"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
IPAM_MENU = Menu(
|
||||
label="IPAM",
|
||||
icon="counter",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="IP Addresses",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
add_url=None, import_url="ipam:service_import"),),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
VIRTUALIZATION_MENU = Menu(
|
||||
label="Virtualization",
|
||||
icon="monitor",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Virtual Machines",
|
||||
items=(
|
||||
MenuItem(
|
||||
label="Virtual Machines",
|
||||
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",
|
||||
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", add_url="virtualization:clustergroup_add", import_url="virtualization:clustergroup_import"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
CIRCUITS_MENU = Menu(
|
||||
label="Circuits",
|
||||
icon="transit-connection-variant",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Circuits",
|
||||
items=(
|
||||
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",
|
||||
add_url="circuits:provider_add", import_url="circuits:provider_import"),
|
||||
MenuItem(
|
||||
label="Provider Networks", url="circuits:providernetwork_list", add_url="circuits:providernetwork_add", import_url="circuits:providernetwork_import"
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
POWER_MENU = Menu(
|
||||
label="Power",
|
||||
icon="flash",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Power",
|
||||
items=(
|
||||
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"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
OTHER_MENU = Menu(
|
||||
label="Other",
|
||||
icon="notification-clear-all",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Logging",
|
||||
items=(
|
||||
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),
|
||||
MenuItem(label="Webhooks", url="extras:webhook_list",
|
||||
add_url="extras:webhook_add", import_url="extras:webhook_import"),
|
||||
),
|
||||
),
|
||||
MenuGroup(
|
||||
label="Customization",
|
||||
items=(
|
||||
MenuItem(label="Custom Fields", url="extras:customfield_list",
|
||||
add_url="extras:customfield_add", import_url="extras:customfield_import"),
|
||||
MenuItem(label="Custom Links", url="extras:customlink_list",
|
||||
add_url="extras:customlink_add", import_url="extras:customlink_import"),
|
||||
MenuItem(label="Export Templates", url="extras:exporttemplate_list",
|
||||
add_url="extras:exporttemplate_add", import_url="extras:exporttemplate_import"),
|
||||
),
|
||||
),
|
||||
MenuGroup(
|
||||
label="Miscellaneous",
|
||||
items=(
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
MENUS = (
|
||||
ORGANIZATION_MENU,
|
||||
DEVICES_MENU,
|
||||
IPAM_MENU,
|
||||
VIRTUALIZATION_MENU,
|
||||
CIRCUITS_MENU,
|
||||
POWER_MENU,
|
||||
OTHER_MENU,
|
||||
)
|
@ -6,35 +6,41 @@
|
||||
{% load static %}
|
||||
|
||||
{% block layout %}
|
||||
<div class="container-fluid">
|
||||
<main class="ms-sm-auto px-0">
|
||||
<div class="container-fluid px-0">
|
||||
<main class="ms-sm-auto">
|
||||
{# Sidebar #}
|
||||
<nav id="sidebar-menu" class="d-md-block sidebar collapse px-0" data-simplebar>
|
||||
|
||||
{# Sidebar content #}
|
||||
<div class="position-sticky pt-3">
|
||||
<div class="position-sticky">
|
||||
|
||||
{# Logo #}
|
||||
<a class="p-1 sidebar-logo d-none d-md-flex justify-content-center" href="{% url 'home' %}">
|
||||
<img src="{% static 'netbox_logo.svg' %}" alt="NetBox logo" />
|
||||
</a>
|
||||
<div class="py-2">
|
||||
<a class="sidebar-logo d-none d-md-flex justify-content-center" href="{% url 'home' %}">
|
||||
<img src="{% static 'netbox_logo.svg' %}" alt="NetBox logo" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Search bar #}
|
||||
<ul class="nav flex-column px-4">
|
||||
<ul class="nav flex-column px-1">
|
||||
|
||||
{# Search bar for collapsed menu #}
|
||||
<div class="d-block d-md-none mx-1 my-3 search-container">
|
||||
{% search_options %}
|
||||
</div>
|
||||
<div class="d-flex d-md-none mx-1 my-3 justify-content-center justify-content-md-end order-last order-md-0">
|
||||
{% include 'inc/profile_button.html' %}
|
||||
</div>
|
||||
|
||||
{# Navigation menu #}
|
||||
{% nav %}
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
{# Sidebar footer #}
|
||||
<div class="d-flex flex-column container-fluid mt-auto justify-content-end sidebar-bottom">
|
||||
<nav class="nav justify-content-between mb-2 mt-4 px-2">
|
||||
<nav class="nav justify-content-evenly my-2 px-2">
|
||||
|
||||
{# Documentation #}
|
||||
<a type="button" class="nav-link" href="https://netbox.readthedocs.io/" target="_blank">
|
||||
@ -89,7 +95,7 @@
|
||||
|
||||
{# Page header #}
|
||||
{% block header %}
|
||||
<div class="title-container px-3 py-3">
|
||||
<div class="title-container px-3 pb-3">
|
||||
|
||||
{# Title #}
|
||||
<div id="content-title">
|
||||
|
@ -4,39 +4,29 @@
|
||||
{% block title %}Delete {{ table.rows|length }} {{ obj_type_plural|bettertitle }}?{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-md-12 col-lg-8 offset-lg-2">
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
<h4 class="alert-heading">Confirm Bulk Deletion</h4>
|
||||
<hr />
|
||||
<div>
|
||||
<strong>Warning:</strong> The following operation will delete <strong>{{ table.rows|length }}</strong> {{ obj_type_plural }}. Please carefully review the {{ obj_type_plural }} to be deleted and confirm below.
|
||||
</div>
|
||||
{% block message_extra %}{% endblock %}
|
||||
<div class="container-md px-0">
|
||||
<div class="alert alert-danger mb-3" role="alert">
|
||||
<h4 class="alert-heading">Confirm Bulk Deletion</h4>
|
||||
<hr />
|
||||
<div>
|
||||
<strong>Warning:</strong> The following operation will delete <strong>{{ table.rows|length }}</strong> {{ obj_type_plural }}. Please carefully review the {{ obj_type_plural }} to be deleted and confirm below.
|
||||
</div>
|
||||
{% block message_extra %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12 col-lg-8 offset-lg-2">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{% include 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="container-xl px-0">
|
||||
{% include 'inc/table.html' %}
|
||||
<div class="row mt-3">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="text-end">
|
||||
<a href="{{ return_url }}" class="btn btn-outline-dark">Cancel</a>
|
||||
<button type="submit" name="_confirm" class="btn btn-danger">Delete {{ table.rows|length }} {{ obj_type_plural }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col col-md-12 col-lg-8 offset-lg-2">
|
||||
<form action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="text-end">
|
||||
<a href="{{ return_url }}" class="btn btn-outline-dark">Cancel</a>
|
||||
<button type="submit" name="_confirm" class="btn btn-danger">Delete {{ table.rows|length }} {{ obj_type_plural }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -15,11 +15,7 @@
|
||||
{% endfor %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{% include 'inc/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% include 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="col col-md-4">
|
||||
<div class="card">
|
||||
|
@ -4,37 +4,25 @@
|
||||
{% block title %}Remove {{ table.rows|length }} {{ obj_type_plural|bettertitle }}?{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6 offset-md-3">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Confirm Bulk Removal</h4>
|
||||
<p><strong>Warning:</strong> The following operation will remove {{ table.rows|length }} {{ obj_type_plural }} from {{ parent_obj }}.</p>
|
||||
<hr />
|
||||
<p class="mb-0">Please carefully review the {{ obj_type_plural }} to be removed and confirm below.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-md px-0">
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Confirm Bulk Removal</h4>
|
||||
<p><strong>Warning:</strong> The following operation will remove {{ table.rows|length }} {{ obj_type_plural }} from {{ parent_obj }}.</p>
|
||||
<hr />
|
||||
<p class="mb-0">Please carefully review the {{ obj_type_plural }} to be removed and confirm below.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
{% include 'inc/table.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-6 offset-md-3">
|
||||
<form action="." method="post" class="form">
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="text-center">
|
||||
<a href="{{ return_url }}" class="btn btn-outline-dark">Cancel</a>
|
||||
<button type="submit" name="_confirm" class="btn btn-danger">Delete these {{ table.rows|length }} {{ obj_type_plural }}</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="container-xl px-0">
|
||||
{% include 'inc/table.html' %}
|
||||
<form action="." method="post" class="form">
|
||||
{% csrf_token %}
|
||||
{% for field in form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
<div class="text-center">
|
||||
<a href="{{ return_url }}" class="btn btn-outline-dark">Cancel</a>
|
||||
<button type="submit" name="_confirm" class="btn btn-danger">Delete these {{ table.rows|length }} {{ obj_type_plural }}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
@ -7,26 +7,22 @@
|
||||
{% block content %}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-7">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Current Name</th>
|
||||
<th>New Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for obj in selected_objects %}
|
||||
<tr{% if obj.new_name and obj.name != obj.new_name %} class="success"{% endif %}>
|
||||
<td>{{ obj.name }}</td>
|
||||
<td>{{ obj.new_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Current Name</th>
|
||||
<th>New Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for obj in selected_objects %}
|
||||
<tr{% if obj.new_name and obj.name != obj.new_name %} class="success"{% endif %}>
|
||||
<td>{{ obj.name }}</td>
|
||||
<td>{{ obj.new_name }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col col-md-5">
|
||||
<form action="" method="post" class="form form-horizontal">
|
||||
|
@ -25,98 +25,96 @@
|
||||
|
||||
{% block content %}
|
||||
{% if filter_form %}
|
||||
<div class="col col-md-12 noprint">
|
||||
{% include 'inc/advanced_search.html' %}
|
||||
</div>
|
||||
{% include 'inc/advanced_search.html' %}
|
||||
{% endif %}
|
||||
{% if table.paginator.num_pages > 1 %}
|
||||
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
|
||||
<div class="row mb-3">
|
||||
<form method="post" class="form col-md-12">
|
||||
<div id="select-all-box" class="d-none card noprint">
|
||||
<div class="row mb-3">
|
||||
<form method="post" class="form col-md-12">
|
||||
{% csrf_token %}
|
||||
<div id="select-all-box" class="d-none card noprint">
|
||||
<div class="card-body d-inline-flex justify-content-between align-items-center">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="select-all" name="_all" class="form-check-input" />
|
||||
<label for="select-all" class="form-check-label">
|
||||
Select <strong>all {{ table.rows|length }} {{ table.data.verbose_name_plural }}</strong> Matching Query
|
||||
</label>
|
||||
</div>
|
||||
<div class="float-end">
|
||||
{% if bulk_edit_url and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm" disabled>
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit All
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if bulk_delete_url and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm" disabled>
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete All
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body d-inline-flex justify-content-between align-items-center">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="select-all" name="_all" class="form-check-input" />
|
||||
<label for="select-all" class="form-check-label">
|
||||
Select <strong>all {{ table.rows|length }} {{ table.data.verbose_name_plural }}</strong> Matching Query
|
||||
</label>
|
||||
</div>
|
||||
<div class="float-end">
|
||||
{% if bulk_edit_url and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm" disabled>
|
||||
<span class="mdi mdi-pencil" aria-hidden="true"></span> Edit All
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if bulk_delete_url and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm" disabled>
|
||||
<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span> Delete All
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
|
||||
{# Object list filter, table config #}
|
||||
<div class="row mb-3">
|
||||
<div class="col col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-md-4 offset-md-8 d-flex noprint table-controls">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control object-filter" placeholder="Filter" title="Filter text (regular expressions supported)" />
|
||||
{% if request.user.is_authenticated and table_config_form %}
|
||||
<button type="button" class="btn btn-outline-dark btn-sm" data-bs-toggle="modal" data-bs-target="#ObjectTable_config" title="Configure Table">
|
||||
<i class="mdi mdi-table-eye"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if filter_form %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#advanced-search-content">
|
||||
Advanced Search
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
|
||||
{% if permissions.change or permissions.delete %}
|
||||
<form method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="return_url" value="{% if return_url %}{{ return_url }}{% else %}{{ request.path }}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}{% endif %}" />
|
||||
{% include table_template|default:'inc/responsive_table.html' %}
|
||||
<div class="float-start noprint bulk-buttons">
|
||||
{% block bulk_buttons %}{% endblock %}
|
||||
{% if bulk_edit_url and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if bulk_delete_url and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="table-responsive">
|
||||
{% render_table table 'inc/table.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-md-4 offset-md-8 d-flex noprint table-controls">
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="text" class="form-control object-filter" placeholder="Filter" title="Filter text (regular expressions supported)" />
|
||||
{% if request.user.is_authenticated and table_config_form %}
|
||||
<button type="button" class="btn btn-outline-dark btn-sm" data-bs-toggle="modal" data-bs-target="#ObjectTable_config" title="Configure Table">
|
||||
<i class="mdi mdi-table-eye"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if filter_form %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline-dark"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#advanced-search-content">
|
||||
Advanced Search
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Object table #}
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
{% with bulk_edit_url=content_type.model_class|validated_viewname:"bulk_edit" bulk_delete_url=content_type.model_class|validated_viewname:"bulk_delete" %}
|
||||
{% if permissions.change or permissions.delete %}
|
||||
<form method="post" class="form form-horizontal">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="return_url" value="{% if return_url %}{{ return_url }}{% else %}{{ request.path }}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}{% endif %}" />
|
||||
<div class="table-responsive">
|
||||
{% render_table table 'inc/table.html' %}
|
||||
</div>
|
||||
<div class="float-start noprint bulk-buttons">
|
||||
{% block bulk_buttons %}{% endblock %}
|
||||
{% if bulk_edit_url and permissions.change %}
|
||||
<button type="submit" name="_edit" formaction="{% url bulk_edit_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-warning btn-sm">
|
||||
<i class="mdi mdi-pencil" aria-hidden="true"></i> Edit Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if bulk_delete_url and permissions.delete %}
|
||||
<button type="submit" name="_delete" formaction="{% url bulk_delete_url %}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}" class="btn btn-danger btn-sm">
|
||||
<i class="mdi mdi-trash-can-outline" aria-hidden="true"></i> Delete Selected
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="table-responsive">
|
||||
{% render_table table 'inc/table.html' %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% include 'inc/paginator.html' with paginator=table.paginator page=table.page %}
|
||||
</div>
|
||||
</div>
|
||||
{% table_config_form table table_name="ObjectTable" %}
|
||||
{% endblock content %}
|
||||
|
@ -1,65 +1,67 @@
|
||||
{% load form_helpers %}
|
||||
{% load helpers %}
|
||||
|
||||
<div class="collapse" id="advanced-search-content">
|
||||
<form action="." method="get">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Advanced Search
|
||||
</h5>
|
||||
<div class="card-body overflow-visible d-flex flex-wrap justify-content-between py-3">
|
||||
{% for field in filter_form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
{% if filter_form.field_groups %}
|
||||
{% for group in filter_form.field_groups %}
|
||||
<div class="col">
|
||||
{% for name in group %}
|
||||
{% with field=filter_form|get_item:name %}
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-floating mb-3 mx-3">
|
||||
{{ field }}
|
||||
{{ field.label_tag }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for field in filter_form.visible_fields %}
|
||||
<div class="col">
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-floating mb-3">
|
||||
{{ field }}
|
||||
{{ field.label_tag }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-end noprint border-0">
|
||||
<button type="button" class="btn btn-sm btn-outline-dark m-1" data-bs-toggle="collapse" data-bs-target="#advanced-search-content">
|
||||
<i class="mdi mdi-close"></i> Close
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger m-1" data-reset-select>
|
||||
<i class="mdi mdi-backspace"></i> Reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary m-1">
|
||||
<i class="mdi mdi-magnify"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div id="advanced-search-content" class="collapse mb-3">
|
||||
<div class="col col-md-12 noprint">
|
||||
<form action="." method="get">
|
||||
<div class="card">
|
||||
<h5 class="card-header">
|
||||
Advanced Search
|
||||
</h5>
|
||||
<div class="card-body overflow-visible d-flex flex-wrap justify-content-between py-3">
|
||||
{% for field in filter_form.hidden_fields %}
|
||||
{{ field }}
|
||||
{% endfor %}
|
||||
{% if filter_form.field_groups %}
|
||||
{% for group in filter_form.field_groups %}
|
||||
<div class="col">
|
||||
{% for name in group %}
|
||||
{% with field=filter_form|get_item:name %}
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-floating mb-3 mx-3">
|
||||
{{ field }}
|
||||
{{ field.label_tag }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% for field in filter_form.visible_fields %}
|
||||
<div class="col">
|
||||
{% if field|widget_type == 'checkboxinput' %}
|
||||
<div class="form-check mb-3">
|
||||
<label class="form-check-label" for="{{ field.id_for_label }}">{{ field.label }}</label>
|
||||
{{ field }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-floating mb-3">
|
||||
{{ field }}
|
||||
{{ field.label_tag }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="card-footer text-end noprint border-0">
|
||||
<button type="button" class="btn btn-sm btn-outline-dark m-1" data-bs-toggle="collapse" data-bs-target="#advanced-search-content">
|
||||
<i class="mdi mdi-close"></i> Close
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger m-1" data-reset-select>
|
||||
<i class="mdi mdi-backspace"></i> Reset
|
||||
</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary m-1">
|
||||
<i class="mdi mdi-magnify"></i> Search
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% load helpers %}
|
||||
|
||||
<div class="paginator float-end text-end my-3">
|
||||
<div class="paginator float-end text-end">
|
||||
{% if paginator.num_pages > 1 %}
|
||||
<div class="btn-group btn-group-sm mb-3" role="group" aria-label="Pages">
|
||||
{% if page.has_previous %}
|
||||
|
@ -1,7 +1,6 @@
|
||||
{% load django_tables2 %}
|
||||
|
||||
<table{% if table.attrs %} {{ table.attrs.as_html }}{% endif %}>
|
||||
<caption class="text-center small mt-3"></caption>
|
||||
{% if table.show_header %}
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
{% for group in menu.groups %}
|
||||
{# Within each main menu, there are groups of menu items #}
|
||||
<div class="flex-column nav px-2">
|
||||
<div class="flex-column nav">
|
||||
|
||||
{% if menu.groups|length > 1 %}
|
||||
<h6 class="accordion-item-title">{{ group.label }}</h6>
|
||||
@ -32,23 +32,25 @@
|
||||
<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 %}">
|
||||
<a class="nav-link flex-grow-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>
|
||||
{% if item.has_add or item.has_import %}
|
||||
<div class="btn-group ps-1">
|
||||
{% 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>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -1,332 +1,14 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Sequence, Optional
|
||||
from typing import Dict
|
||||
from django import template
|
||||
from django.template import Context
|
||||
from django.contrib.auth.context_processors import PermWrapper
|
||||
|
||||
from netbox.navigation_menu import Menu, MenuGroup, MENUS
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@dataclass
|
||||
class MenuItem:
|
||||
"""A navigation menu item link. Example: Sites, Platforms, RIRs, etc."""
|
||||
|
||||
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
|
||||
class MenuGroup:
|
||||
"""A group of menu items within a menu."""
|
||||
|
||||
label: str
|
||||
items: Sequence[MenuItem]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Menu:
|
||||
"""A top level menu group. Example: Organization, Devices, IPAM."""
|
||||
|
||||
label: str
|
||||
icon: str
|
||||
groups: Sequence[MenuGroup]
|
||||
|
||||
|
||||
ORGANIZATION_MENU = Menu(
|
||||
label="Organization",
|
||||
icon="domain",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Sites",
|
||||
items=(
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
add_url="extras:tag_add", import_url="extras:tag_import"),),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
DEVICES_MENU = Menu(
|
||||
label="Devices",
|
||||
icon="server",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Devices",
|
||||
items=(
|
||||
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",
|
||||
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",
|
||||
add_url=None, import_url="dcim:cable_import"),
|
||||
MenuItem(
|
||||
label="Console Connections", url="dcim:console_connections_list", add_url=None, import_url=None,
|
||||
),
|
||||
MenuItem(
|
||||
label="Interface Connections", url="dcim:interface_connections_list", add_url=None, import_url=None,
|
||||
),
|
||||
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",
|
||||
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"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
IPAM_MENU = Menu(
|
||||
label="IPAM",
|
||||
icon="counter",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="IP Addresses",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
add_url=None, import_url="ipam:service_import"),),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
VIRTUALIZATION_MENU = Menu(
|
||||
label="Virtualization",
|
||||
icon="monitor",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Virtual Machines",
|
||||
items=(
|
||||
MenuItem(
|
||||
label="Virtual Machines",
|
||||
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",
|
||||
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", add_url="virtualization:clustergroup_add", import_url="virtualization:clustergroup_import"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
CIRCUITS_MENU = Menu(
|
||||
label="Circuits",
|
||||
icon="transit-connection-variant",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Circuits",
|
||||
items=(
|
||||
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",
|
||||
add_url="circuits:provider_add", import_url="circuits:provider_import"),
|
||||
MenuItem(
|
||||
label="Provider Networks", url="circuits:providernetwork_list", add_url="circuits:providernetwork_add", import_url="circuits:providernetwork_import"
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
POWER_MENU = Menu(
|
||||
label="Power",
|
||||
icon="flash",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Power",
|
||||
items=(
|
||||
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"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
OTHER_MENU = Menu(
|
||||
label="Other",
|
||||
icon="notification-clear-all",
|
||||
groups=(
|
||||
MenuGroup(
|
||||
label="Logging",
|
||||
items=(
|
||||
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),
|
||||
MenuItem(label="Webhooks", url="extras:webhook_list",
|
||||
add_url="extras:webhook_add", import_url="extras:webhook_import"),
|
||||
),
|
||||
),
|
||||
MenuGroup(
|
||||
label="Customization",
|
||||
items=(
|
||||
MenuItem(label="Custom Fields", url="extras:customfield_list",
|
||||
add_url="extras:customfield_add", import_url="extras:customfield_import"),
|
||||
MenuItem(label="Custom Links", url="extras:customlink_list",
|
||||
add_url="extras:customlink_add", import_url="extras:customlink_import"),
|
||||
MenuItem(label="Export Templates", url="extras:exporttemplate_list",
|
||||
add_url="extras:exporttemplate_add", import_url="extras:exporttemplate_import"),
|
||||
),
|
||||
),
|
||||
MenuGroup(
|
||||
label="Miscellaneous",
|
||||
items=(
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
MENUS = (
|
||||
ORGANIZATION_MENU,
|
||||
DEVICES_MENU,
|
||||
IPAM_MENU,
|
||||
VIRTUALIZATION_MENU,
|
||||
CIRCUITS_MENU,
|
||||
POWER_MENU,
|
||||
OTHER_MENU,
|
||||
)
|
||||
|
||||
|
||||
def process_menu(menu: Menu, perms: PermWrapper) -> MenuGroup:
|
||||
"""Enable a menu item if view permissions exist for the user."""
|
||||
for group in menu.groups:
|
||||
|
Loading…
Reference in New Issue
Block a user