Replies: 1 comment 1 reply
-
For those who want to try it out... Set the BANNER_BOTTOM in your configuration.py Put this code in opt/netbox/netbox/media/scripts/nbn.js const nbtn_views = {
'/dcim/devices/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Interfaces': ['interfaces/', 'mdi-dots-vertical'],
'Console Ports': ['console-ports/', 'mdi-dots-vertical'],
'Power Ports': ['power-ports/', 'mdi-dots-vertical'],
'Inventory': ['inventory/', 'mdi-dots-vertical'],
'Status': ['status/', 'mdi-dots-vertical'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/dcim/racks/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Devices': ['/dcim/devices/?rack_id=$id$', 'mdi-dots-vertical'],
'Power Feeds': ['/dcim/power-feeds/?rack_id=$id$', 'mdi-dots-vertical'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/ip-addresses/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/prefixes/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Child Prefixes': ['prefixes/', 'mdi-chart-pie'],
'Child IPranges': ['ip-ranges/', 'mdi-barcode'],
'IP Addresses': ['ip-addresses/', 'mdi-dots-vertical'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/aggregates/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Prefixes': ['/ipam/prefixes/?within_include=$obj$', 'mdi-chart-pie'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/vrfs/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Prefixes': ['/ipam/prefixes/?vrf_id=$id$', 'mdi-dots-horizontal'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/vlans/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Device Interfaces': ['interfaces/', 'mdi-chart-pie'],
'VM Interfaces': ['vm-interfaces/', 'mdi-barcode'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/ipam/vlan-groups/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'VLANs': ['/ipam/vlans/?group_id=$id$', 'mdi-dots-horizontal'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/tenancy/tenants/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'VLANs': ['/ipam/vlans/?tenant_id=$id$', 'mdi-dots-horizontal'],
'Prefixes': ['/ipam/prefixes/?tenant_id=$id$', 'mdi-dots-horizontal'],
'Devices': ['/dcim/devices/?tenant_id=$id$', 'mdi-dots-horizontal'],
'VMs': ['/virtualization/virtual-machines/?tenant_id=$id$', 'mdi-dots-horizontal'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
'/tenancy/tenant-groups/': {
'View': ['', 'mdi-share'],
'Edit': ['edit/?return_url=$return_url$', 'mdi-pencil'],
'Delete': ['delete/?return_url=$return_url$', 'mdi-delete'],
},
};
function nbtnHideBox() {
document.getElementById("nbtnboxmenu").style.display = "none"
}
function nbtnShowbox(e) {
e.preventDefault();
var nbtnboxmenu = document.getElementById("nbtnboxmenu");
if (nbtnboxmenu) {
if (nbtnboxmenu.style.display != "block") {
var url = new URL(e.currentTarget.url)
var nbtnboxpos = e.currentTarget.getBoundingClientRect();
var urlpath = url.pathname;
var parts = urlpath.split('/');
var id = parts[3];
var objtext = e.relatedTarget.innerText;
var nbtnmenu = nbtnboxmenu.getElementsByClassName('nbtn-menu')[0]
nbtnmenu.innerHTML = '';
for (const view of Object.keys(nbtn_views)) {
if (urlpath.startsWith(view)) {
for (const items of Object.keys(nbtn_views[view])) {
var newurl = new URL(url);
var viewitem = nbtn_views[view][items][0].replace('$id$', id).replace('$obj$', encodeURI(objtext)).replace('$return_url$',encodeURIComponent(window.location.href));
var uri = viewitem.split('?');
if (viewitem.startsWith('/')) {
newurl.pathname = uri[0];
} else {
newurl.pathname += uri[0];
}
if (uri.length>1) {
for (var vars of uri[1].split('&')) {
vars = vars.split(/=(.+)/)
newurl.searchParams.set(vars[0], vars[1]);
}
}
nbtnmenu.innerHTML += '<li class="list-group-item list-group-item-action' + (items == 'Delete' ? ' trash' : '') + '"><a href="' + newurl + '"><i class="mdi ' + nbtn_views[view][items][1] + '"></i> ' + items + '</a></li>';
}
}
}
nbtnboxmenu.style.display = "block";
var menuWidth = nbtnboxmenu.offsetWidth + 8;
var menuHeight = nbtnboxmenu.offsetHeight + 8;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
if ((windowWidth - nbtnboxpos.x) < menuWidth) {
nbtnboxmenu.style.left = windowWidth - menuWidth + (nbtnboxpos.width * -0.05) + "px";
} else {
nbtnboxmenu.style.left = nbtnboxpos.x + (nbtnboxpos.width * -0.05) + "px";
}
if ((windowHeight - nbtnboxpos.y) < menuHeight) {
nbtnboxmenu.style.top = windowHeight - menuHeight - 5 + "px";
} else {
nbtnboxmenu.style.top = nbtnboxpos.y - 5 + "px";
}
}
}
}
(function () {
'use strict';
var css=[
'.nbtn-box { white-space: nowrap; display: inline-flex; }',
'.nbtn-icon { padding:.1rem .1rem; margin-left: .2rem; white-space: nowrap; opacity: 20%; }',
'.nbtn-icon:hover { opacity: 80%; }',
'.nbtn-context-menu { position: absolute !important; padding:2px; }',
'.nbtn-menu { margin: 0; list-style: none; display: flex; flex-direction: column; padding: 5px 0; }',
'.nbtn-menu > li { padding: 0px !important; border: none !important; font-size: 1em}',
'.nbtn-menu > li > a { text-decoration: unset; padding: 1px; width: 100%; display: flex; transition: 0.5s linear; -webkit-transition: 0.5s linear; -moz-transition: 0.5s linear; -ms-transition: 0.5s linear; -o-transition: 0.5s linear;}',
'.nbtn-menu > li > a > i { padding-right: 10px; }',
'.nbtn-menu > li.trash > a:hover { color: red; }',
]
var head = document.getElementsByTagName('head')[0];
if (head) {
var style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(css.join("\r\n")));
head.appendChild(style);
}
var nbtnboxmenu = document.createElement("div");
nbtnboxmenu.id = "nbtnboxmenu";
nbtnboxmenu.className = "card nbtn-context-menu";
nbtnboxmenu.style = "display: none";
var nbtnboxmenuul = nbtnboxmenu.appendChild(document.createElement("ul"));
nbtnboxmenuul.className="list-group nbtn-menu";
document.body.appendChild(nbtnboxmenu);
nbtnboxmenu.addEventListener('mouseleave', function (e) {
nbtnHideBox(e)
}, false);
var classes = ['table']
var i, j, k;
for (k = 0; k < classes.length; k++) {
var divs = document.getElementsByClassName(classes[k]);
for (i = 0; i < divs.length; i++) {
var links = divs[i].getElementsByTagName('a');
for (j = 0; j < links.length; j++) {
var link = links[j];
for (const view of Object.keys(nbtn_views)) {
var uri = link.getAttribute("href")
var parts = uri.split('/');
var id = parts[3];
var action = parts[4];
if (link.getAttribute("href").startsWith(view) && !isNaN(0 + id) && !action && link.getElementsByTagName('i').length == 0 && link.innerText.trim().length > 0) {
// url has to start with the nbtn_views key, and the id (3th part of the urlpath) has to be a number and the (4th partt of the urlpath) action has to be empty and there should be no <i> tag in the ahref and the ahref innerhtml is not empty.
var nbtnbox = link.appendChild(document.createElement("div"));
nbtnbox.className = "nbtn-box";
var nbtnspan = nbtnbox.appendChild(document.createElement("span"));
nbtnspan.id = "nbtnbox";
nbtnspan.className = "btn btn-sm nbtn-icon";
nbtnspan.title = "Actions";
var nbtnspani=nbtnspan.appendChild(document.createElement("i"));
nbtnspani.className="mdi mdi-menu";
link.style['white-space'] = 'nowrap';
nbtnbox.addEventListener('mouseover', function (e) {
nbtnShowbox(e)
}, false);
nbtnbox.url = link.href;
}
}
}
}
}
})(); |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
I made a javascript that creates a context menu to the links.
It started with a small Tampermonkey based script, because I saw that there were a lot of places to change the netbox code to add that button next to the links...
The menu is customizable for each link.
Currently, I 'hacked' it into my netbox by putting the JS file in the media folder and a <script> to the BANNER_BOTTOM
Wondering if this is a feature that could be coded natively in netbox. As the JS solution is pretty slow when adding the buttons next to the links..
Pieter
Beta Was this translation helpful? Give feedback.
All reactions