Highlight active Journal/Changelog tab on CO detail pages (#15)#16
Merged
Merged
Conversation
Upstream CustomObjectJournalView / CustomObjectChangeLogView render the
journal/changelog pages with the literal strings "journal"/"changelog"
in the template context as the active-tab marker. NetBox's
{% model_view_tabs %} tag (utilities/templatetags/tabs.py) compares the
active_tab context value against a ViewTab *object* on each registered
view, so the string-vs-object comparison is always False — no tab ever
got the `active` class. Verified still present on netbox-custom-objects
0.5.0 and 0.5.1 under NetBox 4.6.1.
Fix: render Journal and Changelog as hardcoded <li> blocks in the CO
detail template (string equality matches the upstream context contract)
and introduce a new {% plugin_extra_tabs %} tag that mirrors
model_view_tabs but skips the journal/changelog actions, so the
auto-registered (extras feature_views) Journal/Changelog views from
NetBox don't render as duplicate inert tabs.
Tab order is Primary → combined/typed → Journal → Changelog, which
matches the natural ViewTab weight ordering and keeps the layout
stable if upstream later switches to `tab=self.tab` and we can drop
the hardcoding.
Patch release bundling the fix for Journal/Changelog active-tab highlighting on Custom Object detail pages (#15). No API or behaviour changes outside the tab-rendering path; safe drop-in upgrade from 2.4.0 on NetBox 4.5–4.6 with netbox-custom-objects 0.5.x.
Track upstream netbox-custom-objects v0.5.1 release. No plugin code-logic changes needed (existing queries already filter by instance.pk, sidestepping upstream issue #508; M2M through-model path_infos repair from #483 lands inside CustomObjectType.get_model which we call per request). Folded under the existing 2.4.1 CHANGELOG entry rather than a new release — same-day metadata refinement, version stays 2.4.1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #15. On Custom Object detail pages, clicking the Journal or Changelog tab loaded the right page but never highlighted the clicked tab as active. Disabling this plugin made the active marker work again — root cause was on our side.
CustomObjectJournalView/CustomObjectChangeLogView(netbox_custom_objects/views.py) callrender(..., {"tab": "journal"})/{"tab": "changelog"}— the active-tab marker in context is a string. NetBox's{% model_view_tabs %}(utilities/templatetags/tabs.py:53) computesis_active = active_tab == tabwheretabis aViewTabobject, so the comparison is always False and theactiveclass is never emitted. Verified still present onnetboxlabs-netbox-custom-objects0.5.0 and 0.5.1 with NetBox 4.6.1.<li>blocks (string equality works) and introduce a new{% plugin_extra_tabs %}template tag that mirrorsmodel_view_tabsbut skips thejournal/changelogactions — required becausenetbox/models/features.py:737-742auto-registersObjectJournalView/ObjectChangeLogViewinregistry['views']for every ChangeLoggedModel subclass, including dynamic CO models, so without the filter we'd render duplicate inert tabs.tab=self.taband we drop the hardcoding.Files
netbox_custom_objects_tab/templatetags/__init__.py(new, empty)netbox_custom_objects_tab/templatetags/custom_object_tab_tags.py(new —{% plugin_extra_tabs %}tag)netbox_custom_objects_tab/templates/netbox_custom_objects/customobject.html(load tag, replacemodel_view_tabswith hardcoded Journal/Changelog +plugin_extra_tabs)CLAUDE.md(gotcha documenting the string-vs-ViewTab issue)Test plan
AppConfig.ready())nav-link active…/<pk>/journal/, Journal anchor hasnav-link active, primary/Changelog do not…/<pk>/changelog/, Changelog anchor hasnav-link active, primary/Journal do notJournal/Changelogentries in<ul class="nav nav-tabs">(DevTools console:[...document.querySelectorAll('ul.nav.nav-tabs a.nav-link')].map(a => a.textContent.trim())shows each label once)dcim.devicedetail page, click Journal/Changelog → active state still works (our template override is scoped tonetbox_custom_objects/customobject.htmlonly)ruff check netbox_custom_objects_tab/ && ruff format --check netbox_custom_objects_tab/cleanUpstream follow-up (not in this PR)
The cleaner fix lives in
netbox-custom-objectsitself —CustomObjectJournalView.get()/CustomObjectChangeLogView.get()should pass"tab": self.tabinstead of the string literal. Worth filing as a one-line PR againstnetboxlabs/netbox-custom-objects; once merged, we can delete the hardcoded<li>blocks and theplugin_extra_tabstag and go back to a single{% model_view_tabs object %}. Until then this workaround carries the weight.Additional change folded into this PR: track netbox-custom-objects v0.5.1
After this branch opened, upstream
netbox-custom-objectsv0.5.1 shipped. Floor bumps folded in (commit5428c13) since they share the same release artifact (2.4.1):PluginConfig.min_version:4.5.0→4.5.2(mirrors upstream's NetBox floor bump in netboxlabs/netbox-custom-objects#511 — keeps both gates consistent so a NetBox 4.5.0/4.5.1 host can't end up with our plugin loading while upstream refuses to start).PluginConfig.ready():>= 0.5.0→>= 0.5.1(message text only; the behavioural probe still keys off the 0.5.0is_polymorphicschema sentinel, since no field added in 0.5.1 is a reliable runtime marker).Requirements+ 2.4.xCompatibilityrow updated.[2.4.1] - 2026-05-25block as### Changed(same-day metadata refinement, no version bump).No plugin code-logic changes were needed. Our query helpers (
combined.py::_iter_linked_fields,typed.py::_build_q_for_field) already filter byinstance.pk(int) rather than by model instance, so upstream's #508 rewrite ofCustomObjectLink.left_page()fromfilter(**{field.name: target_obj})tofilter(**{f"{field.name}_id": target_obj.pk})doesn't affect us. The M2Mpath_infosrepair from #483 is applied insideCustomObjectType.get_model(), which we call per request — inherited for free.Additional test plan items
netbox-custom-objects0.5.1pip install 'netbox-custom-objects==0.5.0'→ startup aborts withImproperlyConfiguredpointing at>=0.5.1. Re-install 0.5.1 to restore.