Skip to content

[WIP] Related object tabs — PoC for discussion#482

Open
Kani999 wants to merge 6 commits intonetboxlabs:mainfrom
Kani999:feature/related-object-tabs
Open

[WIP] Related object tabs — PoC for discussion#482
Kani999 wants to merge 6 commits intonetboxlabs:mainfrom
Kani999:feature/related-object-tabs

Conversation

@Kani999
Copy link
Copy Markdown

@Kani999 Kani999 commented Apr 24, 2026

Summary

This is a Proof of Concept / Work in Progress — not ready for merge. The design and configuration approach need discussion before finalizing.

Integrates the standalone netbox-custom-objects-tab plugin into core netbox-custom-objects (ref: CESNET/netbox-custom-objects-tab#8).

Closes #26

What's implemented

  • Combined "Custom Objects" tab — automatically appears on detail pages of any NetBox object referenced by a Custom Object Type. Shows all linked custom objects with actions, tags, column config, and quick search. Always active, no configuration needed.
  • Per-COT typed tabs — opt-in dedicated tabs for specific Custom Object Types, with type-specific columns, per-field filters, and bulk actions. Configured via typed_tab_slugs in PLUGINS_CONFIG.
  • CO-to-CO support — custom objects referencing other custom objects also get tabs.
  • Plugin wiring (__init__.py), templates, and README documentation.

Open questions for discussion

  • Configuration approach: Currently typed tabs are enabled via typed_tab_slugs list in PLUGINS_CONFIG. Is this the right UX, or should this be a per-COT toggle in the admin UI?
  • Badge/count behavior: Badges use OR + distinct queries to avoid double-counting — are there performance concerns at scale?
  • Template/styling: Do the tab templates align with NetBox core conventions, or do they need adjustment?

Images

obrazek obrazek obrazek obrazek obrazek

Jan Krupa added 6 commits April 21, 2026 08:40
- Add tab_views.py with combined and typed tab view factories
- Combined tab shows all linked custom objects with actions, tags, column config, quick search
- Typed tabs show per-COT filtered view with bulk actions and per-field filters
- Auto-discover referenced models from app registry (never call get_model during registration)
- Support CO-to-CO tabs (custom objects referencing other custom objects)
- Badge callables use OR + distinct to avoid double-counting
- Add combined_tab.html and typed_tab.html templates
- Add typed_tab_slugs to default_settings in PluginConfig
- Call register_all_tabs() in ready() before super().ready()
- Call inject_co_urls() and deduplicate_registry() after super().ready()
- Add model_view_tabs to customobject.html for CO-to-CO tab support
- Fix JournalEntryTable and ObjectChangeTable: remove unsupported user kwarg
- Fix journal/changelog views to pass self.tab instead of string literals
- Add Related Object Tabs section explaining combined and typed tabs
- Document typed_tab_slugs PLUGINS_CONFIG setting with example
- Note that restart is required after config changes
- Replace _build_filterset_form with shared dynamic_forms.build_filterset_form_class
  (per prior PR netboxlabs#445 feedback / commit 26a39a5 invariant)
- Extract _build_link_q helper; removes copy-pasted Q loop from
  _count_for_type._badge and TypedTabView.get
- Drop CustomObjectType.objects.get(pk=cot_pk) refetch from typed-tab badge;
  use captured cot directly
- Narrow bare except Exception to (OperationalError, ProgrammingError) in
  _count_linked and _get_linked_objects
- prefetch_related('tags') in _get_linked_objects — kills per-row tag N+1
- Switch .restrict() try/except AttributeError to hasattr() guard; matches
  NetBox core pattern in netbox/views/generic/feature_views.py
- Fix stale module docstring: typed-tab opt-in is typed_tab_slugs in
  PLUGINS_CONFIG, not show_tab=True
Apply .restrict(user, 'view') to linked-CO querysets so users without
view permission on a referenced Custom Object model don't see its rows
rendered in the related-object tab bodies.

- _get_linked_objects now takes a user and restricts each per-model qs
  before filtering; the combined-tab view passes request.user.
- TypedTabView.get restricts dynamic_model.objects before the link-Q
  filter so the typed-tab body is also gated.

The combined-tab badge count can still include rows the user can't see;
the body render itself is now restricted.
Pass a permission string into ViewTab so NetBox's core tab template tag
skips the typed tab entirely for users without <app>.view_<model>
permission on the underlying Custom Object model. Previously the badge
count could include restricted rows while the body correctly hid them,
producing a badge-vs-empty-body mismatch.

The permission string is derived from the CO model resolved via
model_ct_map at registration time (cot.object_type_id -> model), so no
cot.get_model() call is introduced during tab registration.

The combined tab is left unguarded intentionally — it aggregates across
all CO types and is filtered per-row by the restrict() fix already in
place.
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


Jan Krupa seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto generation of tabs in other objects that lists related Custom Objects

2 participants