- Split the device detail page's single "Components" table into the
same seven tabs a real dcim.Device has, in the same order: Console
Ports, Console Server Ports, Power Ports, Power Outlets, Interfaces,
Front Ports, Rear Ports. Each tab is its own ObjectChildrenView
filtered by component_type (one ConceptComponent model backs all of
them, so this only needed the view/URL layer, not a schema change),
hidden when empty, exactly like core NetBox. Replace the ad hoc "Add
component" button with the same "Add Components" dropdown real
device pages use, one entry per type, each landing back on its own
tab.
- When copying a real rack into a concept (or merging two real racks
into one), automatically sync every copied device's components and
recreate, as ConceptCables, every real cable whose both ends land on
one of those devices - reading the same CableTermination data dcim
itself uses, so the copy comes out cabled internally the same as the
source. Cables reaching outside the copied rack(s), or multi-
termination trunk cables, are skipped and reported as a count in the
success message - the other end isn't part of the concept, so it
can't be represented. copy_rack_to_concept() and
merge_racks_to_concept() now return an extra cable_summary value;
updated all their callers (views and API).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Fix "images only" leaving plain labels visible on faces where a
device has no image for that side (e.g. no rear_image set): the
view selector now hides every plain label outright in that mode,
not just the ones an image happens to sit on top of.
- Remove the "Add planned device" button from the elevation card.
Empty units are now click targets themselves - clicking one opens
the add-device form pre-filled with that position and face, exactly
like a real rack's elevation. Occupancy is computed per unit per
face from the existing device blocks.
- Add cabling for concept devices: ConceptComponent (interfaces,
front/rear ports, power ports/outlets, console ports) and
ConceptCable (a connection between two components, restricted to
devices in the same concept). components.sync_components()
populates a device's components from its device type's templates,
including the front/rear port pass-through mapping copied from
DeviceType.port_mappings - so a device with front/rear port
templates (a patch panel being the common case) behaves exactly
like a real one, without hardcoding anything role-specific.
Placeholder devices without a device type get components added by
hand. Full CRUD views, tables, filtersets, API endpoints and a
"Connect" action wired in from the device detail page.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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>
- Fix elevation rendering bug: device blocks were drawn MARGIN px
further right than the rack frame/unit slots, causing them to
overlap and extend past the right border. All three now share one
RACK_X origin.
- Show the device type's front/rear image inside each elevation block
(clipped to the block, translucent label bar on top for legibility)
when one is set on the device type; falls back to a plain colour
block with text otherwise.
- Add "Merge" action to combine two concepts into one taller one (e.g.
two half-height racks stacked into a full-height rack): the top
concept's devices are shifted up by the bottom concept's height,
neither source is modified. Available from the plugin menu, from a
concept's detail page, and via POST /concepts/merge/.
- Copying a real rack into a concept can now target a different width,
height and/or starting unit than the source rack; devices that no
longer fit at the chosen size are skipped and reported as warnings
instead of aborting the copy.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DRF's RelatedField asserts queryset is not None (unless read_only) at
__init__ time, i.e. when the class body of the Serializer is
evaluated - not when the field is later used. The previous code passed
queryset=None and tried to patch it in the serializer's own __init__,
which never ran in time because construction of the field itself
already raised. Pass the real querysets directly at class-body level
instead, matching the standard DRF/NetBox pattern; the deferred
per-instance model imports are no longer needed since serializers are
only imported once all apps are ready anyway.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ButtonColorChoices is defined in netbox/netbox/choices.py, not
utilities/choices.py (which only has the generic ChoiceSet base).
Cross-checked every other NetBox-internal import in the plugin against
the actual v4.6.8 source (dcim, netbox, tenancy, utilities packages)
to rule out further path mistakes; all others were already correct.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
PluginConfig._load_resource() prepends self.__module__ (already
'netbox_rack_concept') to the configured path, so 'menu' and
'template_extensions' must be given relative to the plugin package
('navigation.menu', 'template_content.template_extensions'), not
prefixed with 'netbox_rack_concept.' again. The prefixed form made
Django try to import 'netbox_rack_concept.netbox_rack_concept...',
which doesn't exist, crashing manage.py on every command.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds instructions for installing and upgrading the plugin directly via
pip from git.mrblake.cc, including pinning a ref, wiring it into
local_requirements.txt for upgrade.sh, and the force-reinstall caveat
needed to pick up updates from an unversioned git URL.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Introduces a NetBox 4.6 plugin for planning rack layouts (RackConcept,
ConceptDevice) without creating real dcim.Rack/dcim.Device objects, so
blueprints never appear in rack/device lists, utilization reports, or
IPAM.
Features:
- Copy paths: real rack -> concept, concept -> concept (clone), and
concept -> one or more real racks (deploy, with name patterning and
dry-run support)
- Manual concept creation via a dedicated "Rack Concepts" nav menu
- Tenant and tenant group assignment on concepts and planned devices
- Partial-width device placement (1/1-1/4) with slot-based collision
detection, matching netbox_utilities' partial-width feature
- Custom drag-and-drop elevation (netbox-reorder-rack operates on real
Device querysets, which concepts don't have) with server-side
validation of every move
- Full REST API, filtering, CSV import, bulk edit, search integration
- Optional, config-driven interop with netbox_utilities (partial-width
field mapping) and netbox-reorder-rack, degrading gracefully when
either plugin is absent
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>