Only display the saved filter dropdown in table controls when a filter
form is present and includes a filter_id field. This prevents rendering
an empty or non-functional dropdown when saved filters are unavailable.
Render navigation menu buttons with the secondary ghost style when their
color is unset or set to the default choice.
This fixes plugin menu buttons, which default to "default" rather than
None, while preserving explicitly configured button colors.
Replace the grouped button wrapper with a semantic
`dropdown-item-buttons` container and render sidebar action buttons with
the `btn-ghost` style while preserving existing color support.
Scope dropdown item link styles to direct child anchors so nested action
buttons keep their intended styling, and reveal the buttons on hover,
active, and focus-within states.
* refactor(forms): Add GenericObjectChoiceField
Replace separate scope_type/scope and parent_object_type/parent field
pairs with unified GenericObjectChoiceField. Introduce
GenericObjectFormMixin to handle GFK descriptor initialization and
assignment.
This removes redundant HTMX/queryset setup logic from ScopedForm,
VLANGroupForm, and ServiceForm by delegating GFK presentation to a
single reusable field and mixin pair. Field query param references now
use `$scope_object_id` instead of `$scope` to match the subwidget name.
Fixes#19821
* fix(forms): Skip validation on HTMX bulk-edit dependent field refresh
Render bulk-edit form unbound when an HTMX request changes a dependent
field (e.g. content type) without clicking Apply. This prevents
validation errors from surfacing before the user submits.
Cache ContentType lookups in GenericObjectChoiceField and sync widget
references before setting queryset to ensure choices land on the
rendered subwidget.
* fix(ipam): Update scope query params for GenericObjectChoiceField
Change available-prefix Add links to use `scope_content_type` and
`scope_object_id` query parameters instead of `scope_type` and `scope`.
This aligns with the GenericObjectChoiceField subwidget naming
introduced in the earlier refactor.
* refactor(models): Simplify GFK handling in clone_fields
Replace `scope_type`/`scope_id` pairs with bare `scope` GFK names in
clone_fields across models. Update CloningMixin to emit GFK subwidget
parameters (`scope_content_type`, `scope_object_id`) directly when a
GenericForeignKey appears in clone_fields.
* Update pre-populated links
---------
Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
Move the device/VM lookup ahead of is_primary/is_oob handling and only
process those flags when a parent device or VM exists.
This avoids dereferencing None for explicit falsy CSV values such as
"false", which are not covered by the column-absent checks in
clean_is_primary() and clean_is_oob(). This also keeps the behavior
aligned with MACAddressImportForm.
Reject duplicate ScriptModule uploads before writing to storage to
prevent failed uploads from corrupting existing files. Add existence
check in cleanup path to avoid deleting files referenced by concurrent
uploads that won the race.
Fixes#22543
Introduce Breakout1C8Px8C1PCableProfile to map a single 8-position
connector to eight single-position connectors. Add profile choice,
registration, and bidirectional link peer tests for the new breakout.
Fixes#22279
Defer CachedValue updates from post_save/post_delete signal handlers to a
SearchCacheJob that runs after the surrounding transaction commits. Coalesce
pending updates per database alias and savepoint scope, preserving rollback
semantics while reducing synchronous write latency.
When no worker is available, or Redis cannot be reached during dispatch, apply
the update inline so existing single-process installs continue to behave
correctly. Replay the originating database alias during deferred reads and
writes so cache updates remain routed to the schema that emitted the signal.
Keep deferral private to CachedValueSearchBackend so custom SEARCH_BACKEND
implementations continue to use the existing synchronous cache/remove contract.
Move the job runner to search/jobs.py and keep the CachedValue-specific update
logic on the backend.
Document the eventual consistency of global search results and add coverage for
coalescing, rollback/savepoint behavior, worker dispatch, inline fallback,
deleted objects, and the custom backend contract.
- humanize_duration: guard on 'is None' instead of falsiness so
timedelta(0) renders as '0s' rather than blank
- execution_time filter: add label= for consistency with sibling filters
Adds a nullable DurationField computed as completed - started, set in
Job.terminate(). Exposes it as an orderable table column, detail-panel
attr, REST API field, and UI/API range filters (execution_time__gte /
execution_time__lte).
A plain stored field (not a GeneratedField) keeps the migration
metadata-only, avoiding a full table rewrite on core_job.
Add post_save signal handler to update cached virtual_chassis field for
member Devices when a VirtualChassis is renamed. Skip updates for
creates, raw saves, or targeted saves excluding the name field.
Fixes stale search cache entries after VirtualChassis name changes.
Fixes#22489
RestrictedQuerySet.restrict() and IsSuperuser short-circuited on is_superuser
without checking is_active, so a deactivated superuser was granted the full
superuser bypass. restrict() in particular fails open, returning the
unrestricted queryset. Both now also require is_active, matching the existing
guard in ObjectPermissionMixin.has_perm.
Apply object-level view restrictions when nested Serializers resolve
related objects from REST API write input. Nested create and update
operations now resolve related objects from a permission-restricted
queryset, causing hidden related objects to fail validation the same as
nonexistent objects.
Fixes#21988