mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
implement layout changes
This commit is contained in:
parent
9b89afd6dc
commit
1d9e55ca6e
@ -12,7 +12,7 @@ OBJ_TYPE_CHOICES = (
|
||||
('site', 'Sites'),
|
||||
('rack', 'Racks'),
|
||||
('rackgroup', 'Rack Groups'),
|
||||
('devicetype', 'Device types'),
|
||||
('devicetype', 'Device Types'),
|
||||
('device', 'Devices'),
|
||||
('virtualchassis', 'Virtual Chassis'),
|
||||
('cable', 'Cables'),
|
||||
@ -22,7 +22,7 @@ OBJ_TYPE_CHOICES = (
|
||||
('vrf', 'VRFs'),
|
||||
('aggregate', 'Aggregates'),
|
||||
('prefix', 'Prefixes'),
|
||||
('ipaddress', 'IP addresses'),
|
||||
('ipaddress', 'IP Addresses'),
|
||||
('vlan', 'VLANs'),
|
||||
)),
|
||||
('Secrets', (
|
||||
@ -33,10 +33,21 @@ OBJ_TYPE_CHOICES = (
|
||||
)),
|
||||
('Virtualization', (
|
||||
('cluster', 'Clusters'),
|
||||
('virtualmachine', 'Virtual machines'),
|
||||
('virtualmachine', 'Virtual Machines'),
|
||||
)),
|
||||
)
|
||||
|
||||
def build_options():
|
||||
options = [{"label": OBJ_TYPE_CHOICES[0][1], "items": []}]
|
||||
|
||||
for label, choices in OBJ_TYPE_CHOICES[1:]:
|
||||
items = []
|
||||
|
||||
for value, choice_label in choices:
|
||||
items.append({"label": choice_label, "value": value})
|
||||
|
||||
options.append({"label": label, "items": items })
|
||||
return options
|
||||
|
||||
class SearchForm(BootstrapMixin, forms.Form):
|
||||
q = forms.CharField(
|
||||
@ -45,3 +56,4 @@ class SearchForm(BootstrapMixin, forms.Form):
|
||||
obj_type = forms.ChoiceField(
|
||||
choices=OBJ_TYPE_CHOICES, required=False, label='Type'
|
||||
)
|
||||
options = build_options()
|
||||
|
36
netbox/utilities/templates/navigation/nav_items.html
Normal file
36
netbox/utilities/templates/navigation/nav_items.html
Normal file
@ -0,0 +1,36 @@
|
||||
<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>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if forloop.counter != menu.groups|length %}
|
||||
<hr class="dropdown-divider my-3" />
|
||||
{% endif %} {% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
52
netbox/utilities/templates/search/searchbar.html
Normal file
52
netbox/utilities/templates/search/searchbar.html
Normal file
@ -0,0 +1,52 @@
|
||||
<form class="input-group w-100" action="{% url 'search' %}" method="get">
|
||||
<input
|
||||
name="q"
|
||||
id="id_q"
|
||||
type="text"
|
||||
aria-label="Search"
|
||||
placeholder="Search"
|
||||
class="form-control"
|
||||
value="{{ request.GET.q }}"
|
||||
aria-describedby="search-button"
|
||||
/>
|
||||
<input id="search-obj-type" name="obj_type" hidden type="text" />
|
||||
<span class="input-group-text" id="selected-value">All Objects</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
data-bs-toggle="dropdown"
|
||||
class="btn btn-outline-secondary dropdown-toggle"
|
||||
>
|
||||
<i class="bi-filter"></i>
|
||||
</button>
|
||||
<ul id="object-type-selector" class="dropdown-menu dropdown-menu-end">
|
||||
{% for option in options %} {% if option.items|length == 0 %}
|
||||
<li>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
type="button"
|
||||
data-search-value="{{ option.value }}"
|
||||
>
|
||||
{{ option.label }}
|
||||
</button>
|
||||
</li>
|
||||
{% else %}
|
||||
<li><h6 class="dropdown-header">{{ option.label }}</h6></li>
|
||||
{% endif %} {% for item in option.items %}
|
||||
<li>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
type="button"
|
||||
data-search-value="{{ item.value }}"
|
||||
>
|
||||
{{ item.label }}
|
||||
</button>
|
||||
</li>
|
||||
{% endfor %} {% if forloop.counter != options|length %}
|
||||
<li><hr class="dropdown-divider" /></li>
|
||||
{% endif %} {% endfor %}
|
||||
</ul>
|
||||
<button class="btn btn-primary" type="submit" id="search-button">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</form>
|
21
netbox/utilities/templatetags/get_status.py
Normal file
21
netbox/utilities/templatetags/get_status.py
Normal file
@ -0,0 +1,21 @@
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
TERMS_DANGER = ("delete", "deleted", "remove", "removed")
|
||||
TERMS_WARNING = ("changed", "updated", "change", "update")
|
||||
TERMS_SUCCESS = ("created", "added", "create", "add")
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def get_status(text: str) -> str:
|
||||
lower = text.lower()
|
||||
|
||||
if lower in TERMS_DANGER:
|
||||
return "danger"
|
||||
elif lower in TERMS_WARNING:
|
||||
return "warning"
|
||||
elif lower in TERMS_SUCCESS:
|
||||
return "success"
|
||||
else:
|
||||
return "info"
|
42
netbox/utilities/templatetags/nav.py
Normal file
42
netbox/utilities/templatetags/nav.py
Normal file
@ -0,0 +1,42 @@
|
||||
from pathlib import Path
|
||||
from typing import Dict, List
|
||||
from django import template
|
||||
from django.template import Context
|
||||
from django.contrib.auth.context_processors import PermWrapper
|
||||
|
||||
import yaml
|
||||
|
||||
register = template.Library()
|
||||
|
||||
NAV_GROUPS = Path.cwd() / "utilities" / "templatetags" / "nav.yaml"
|
||||
|
||||
|
||||
def import_groups() -> Dict:
|
||||
with NAV_GROUPS.open("r") as f:
|
||||
menus = yaml.safe_load(f.read())
|
||||
return menus
|
||||
|
||||
|
||||
def process_nav_group(nav_group: Dict, perms: PermWrapper) -> Dict:
|
||||
"""Enable a menu item if view permissions exist for the user."""
|
||||
for group in nav_group["groups"]:
|
||||
for item in group["items"]:
|
||||
# Parse the URL template tag to a permission string.
|
||||
app, scope = item["url"].split(":")
|
||||
view_perm = f"{app}.view_{scope}"
|
||||
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
|
||||
|
||||
return nav_group
|
||||
|
||||
|
||||
@register.inclusion_tag("navigation/nav_items.html", takes_context=True)
|
||||
def nav(context: Context) -> Dict:
|
||||
"""Provide navigation items to template."""
|
||||
perms: PermWrapper = context["perms"]
|
||||
nav_menus = import_groups()
|
||||
groups = [process_nav_group(g, perms) for g in nav_menus["menus"]]
|
||||
|
||||
return {"nav_items": groups, "request": context["request"]}
|
205
netbox/utilities/templatetags/nav.yaml
Normal file
205
netbox/utilities/templatetags/nav.yaml
Normal file
@ -0,0 +1,205 @@
|
||||
menus:
|
||||
- label: Organization
|
||||
groups:
|
||||
- label: Sites
|
||||
items:
|
||||
- label: Sites
|
||||
url: 'dcim:site_list'
|
||||
disabled: true
|
||||
- label: Regions
|
||||
url: 'dcim:region_list'
|
||||
disabled: true
|
||||
- label: Racks
|
||||
items:
|
||||
- label: Racks
|
||||
url: 'dcim:rack_list'
|
||||
disabled: true
|
||||
- label: Rack Groups
|
||||
url: 'dcim:rackgroup_list'
|
||||
disabled: true
|
||||
- label: Rack Roles
|
||||
url: 'dcim:rackrole_list'
|
||||
disabled: true
|
||||
- label: Elevations
|
||||
url: 'dcim:rack_elevation_list'
|
||||
disabled: true
|
||||
- label: Tenancy
|
||||
items:
|
||||
- label: Tenants
|
||||
url: 'tenancy:tenant_list'
|
||||
disabled: true
|
||||
- label: Tenant Groups
|
||||
url: 'tenancy:tenantgroup_list'
|
||||
disabled: true
|
||||
- label: Tags
|
||||
items:
|
||||
- label: Tags
|
||||
url: 'extras:tag_list'
|
||||
disabled: true
|
||||
- label: Devices
|
||||
groups:
|
||||
- items:
|
||||
- disabled: true
|
||||
label: Devices
|
||||
url: dcim:device_list
|
||||
- disabled: true
|
||||
label: Device Roles
|
||||
url: dcim:devicerole_list
|
||||
- disabled: true
|
||||
label: Platforms
|
||||
url: dcim:platform_list
|
||||
- disabled: true
|
||||
label: Virtual Chassis
|
||||
url: dcim:virtualchassis_list
|
||||
label: Devices
|
||||
- items:
|
||||
- disabled: true
|
||||
label: Device Types
|
||||
url: dcim:devicetype_list
|
||||
- disabled: true
|
||||
label: Manufacturers
|
||||
url: dcim:manufacturer_list
|
||||
label: Device Types
|
||||
- items:
|
||||
- disabled: true
|
||||
label: Cables
|
||||
url: dcim:cable_list
|
||||
- disabled: true
|
||||
label: Console Connections
|
||||
url: dcim:console_connections_list
|
||||
- disabled: true
|
||||
label: Interface Connections
|
||||
url: dcim:interface_connections_list
|
||||
- disabled: true
|
||||
label: Power Connections
|
||||
url: dcim:power_connections_list
|
||||
label: Connections
|
||||
- items:
|
||||
- disabled: true
|
||||
label: Interfaces
|
||||
url: dcim:interface_list
|
||||
- disabled: true
|
||||
label: Front Ports
|
||||
url: dcim:frontport_list
|
||||
- disabled: true
|
||||
label: Rear Ports
|
||||
url: dcim:rearport_list
|
||||
- disabled: true
|
||||
label: Console Ports
|
||||
url: dcim:consoleport_list
|
||||
- disabled: true
|
||||
label: Console Server Ports
|
||||
url: dcim:consoleserverport_list
|
||||
- disabled: true
|
||||
label: Power Ports
|
||||
url: dcim:powerport_list
|
||||
- disabled: true
|
||||
label: Power Outlets
|
||||
url: dcim:poweroutlet_list
|
||||
- disabled: true
|
||||
label: Device Bays
|
||||
url: dcim:devicebay_list
|
||||
- disabled: true
|
||||
label: Inventory Items
|
||||
url: dcim:inventoryitem_list
|
||||
label: Device Components
|
||||
- label: IPAM
|
||||
groups:
|
||||
- label: IP Addresses
|
||||
items:
|
||||
- label: IP Addresses
|
||||
url: 'ipam:ipaddress_list'
|
||||
disabled: true
|
||||
- label: Prefixes
|
||||
items:
|
||||
- label: Prefixes
|
||||
url: 'ipam:prefix_list'
|
||||
disabled: true
|
||||
- label: Prefix & VLAN Roles
|
||||
url: 'ipam:role_list'
|
||||
disabled: true
|
||||
- label: Aggregates
|
||||
items:
|
||||
- label: Aggregates
|
||||
url: 'ipam:aggregate_list'
|
||||
disabled: true
|
||||
- label: RIRs
|
||||
url: 'ipam:rir_list'
|
||||
disabled: true
|
||||
- label: VRFs
|
||||
items:
|
||||
- label: VRFs
|
||||
url: 'ipam:vrf_list'
|
||||
disabled: true
|
||||
- label: Route Targets
|
||||
url: 'ipam:routetarget_list'
|
||||
disabled: true
|
||||
- label: VLANs
|
||||
items:
|
||||
- label: VLANs
|
||||
url: 'ipam:vlan_list'
|
||||
disabled: true
|
||||
- label: VLAN Groups
|
||||
url: 'ipam:vlangroup_list'
|
||||
disabled: true
|
||||
- label: Services
|
||||
items:
|
||||
- label: Services
|
||||
url: 'ipam:service_list'
|
||||
disabled: true
|
||||
- label: Virtualization
|
||||
groups:
|
||||
- label: Virtual Machines
|
||||
items:
|
||||
- label: Virtual Machines
|
||||
url: 'virtualization:virtualmachine_list'
|
||||
disabled: true
|
||||
- label: Interfaces
|
||||
url: 'virtualization:vminterface_list'
|
||||
disabled: true
|
||||
- label: Clusters
|
||||
items:
|
||||
- label: Clusters
|
||||
url: 'virtualization:cluster_list'
|
||||
disabled: true
|
||||
- label: Cluster Types
|
||||
url: 'virtualization:clustertype_list'
|
||||
disabled: true
|
||||
- label: Cluster Groups
|
||||
url: 'virtualization:clustergroup_list'
|
||||
disabled: true
|
||||
- label: Circuits
|
||||
groups:
|
||||
- label: Circuits
|
||||
items:
|
||||
- label: Circuits
|
||||
url: 'circuits:circuit_list'
|
||||
disabled: true
|
||||
- label: Circuit Types
|
||||
url: 'circuits:circuittype_list'
|
||||
disabled: true
|
||||
- label: Providers
|
||||
items:
|
||||
- label: Providers
|
||||
url: 'circuits:provider_list'
|
||||
disabled: true
|
||||
- label: Power
|
||||
groups:
|
||||
- label: Power
|
||||
items:
|
||||
- label: Power Feeds
|
||||
url: 'dcim:powerfeed_list'
|
||||
disabled: true
|
||||
- label: Power Panels
|
||||
url: 'dcim:powerpanel_list'
|
||||
disabled: true
|
||||
- label: Secrets
|
||||
groups:
|
||||
- label: Secrets
|
||||
items:
|
||||
- label: Secrets
|
||||
url: 'secrets:secret_list'
|
||||
disabled: true
|
||||
- label: Secret Roles
|
||||
url: 'secrets:secretrole_list'
|
||||
disabled: true
|
13
netbox/utilities/templatetags/search_options.py
Normal file
13
netbox/utilities/templatetags/search_options.py
Normal file
@ -0,0 +1,13 @@
|
||||
from typing import Dict
|
||||
from netbox.forms import SearchForm
|
||||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
search_form = SearchForm()
|
||||
|
||||
|
||||
@register.inclusion_tag("search/searchbar.html")
|
||||
def search_options() -> Dict:
|
||||
"""Provide search options to template."""
|
||||
return {"options": search_form.options}
|
Loading…
Reference in New Issue
Block a user