- Replace the device-image label background bar and text-shadow with NetBox's own technique: a black-stroke pass behind a white-fill pass of the same text, giving crisp readable labels over any image without a dark box behind them. - Add an "Images and labels / Images only / Labels only" selector above the elevation, mirroring the equivalent control on real NetBox rack elevations. The plain label is always in the markup; the selector only toggles the image and its over-image label, exactly like core NetBox does it. Choice persists per browser via localStorage and works without edit permissions. - Add a "Merge into concept" button to the real dcim Rack list: select two racks via the existing bulk-select checkboxes and it forwards them to the concept-merge page, pre-filled. New deploy.merge_racks_to_concept() combines two real racks' devices directly into one new, stacked blueprint without an intermediate per-rack copy step. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
48 lines
1.5 KiB
Python
48 lines
1.5 KiB
Python
from django.conf import settings
|
|
|
|
from netbox.plugins import PluginTemplateExtension
|
|
|
|
from .models import RackConcept
|
|
|
|
|
|
def _enabled():
|
|
return settings.PLUGINS_CONFIG.get('netbox_rack_concept', {}).get('enable_rack_tab', True)
|
|
|
|
|
|
class RackConceptButtons(PluginTemplateExtension):
|
|
"""
|
|
Adds "Copy to concept" to the button row of a rack, "Merge into concept" to the
|
|
rack list's toolbar, and lists concepts derived from a rack.
|
|
"""
|
|
models = ['dcim.rack']
|
|
|
|
def buttons(self):
|
|
if not _enabled():
|
|
return ''
|
|
if not self.context['request'].user.has_perm('netbox_rack_concept.add_rackconcept'):
|
|
return ''
|
|
return self.render('netbox_rack_concept/inc/rack_copy_button.html', extra_context={
|
|
'rack': self.context['object'],
|
|
})
|
|
|
|
def list_buttons(self):
|
|
if not _enabled():
|
|
return ''
|
|
if not self.context['request'].user.has_perm('netbox_rack_concept.add_rackconcept'):
|
|
return ''
|
|
return self.render('netbox_rack_concept/inc/rack_list_merge_button.html')
|
|
|
|
def right_page(self):
|
|
if not _enabled():
|
|
return ''
|
|
rack = self.context['object']
|
|
concepts = RackConcept.objects.restrict(self.context['request'].user, 'view').filter(source_rack=rack)
|
|
if not concepts:
|
|
return ''
|
|
return self.render('netbox_rack_concept/inc/rack_concepts_panel.html', extra_context={
|
|
'concepts': concepts,
|
|
})
|
|
|
|
|
|
template_extensions = [RackConceptButtons]
|