Commit Graph

15813 Commits

Author SHA1 Message Date
Mohamed Hossam 560d595ac3
Closes #22716: Restrict image sources to HTTP(S) and relative URLs 2026-08-18 11:08:46 -04:00
Martin Hauser 59c42dfd20
Fixes #22944: Display nested role hierarchy in Virtual Machine info panel (#22955) 2026-08-18 09:52:51 -05:00
Jason Novinger d38ace89ce
Fixes #22889: Render Config Revision banner fields in monospace (#22907)
Replace the obsolete Django admin `vLargeTextField` class with Tabler's
`font-monospace` utility for the four banner configuration parameters.

Define the widget styling in the parameter definitions, where the metaclass
constructs the form fields, and remove the ineffective `Meta.widgets`
overrides. Add regression coverage for all six code-oriented configuration
fields, including the two JSON fields that already use a monospace font.

Update the add-config-param skill to recommend `font-monospace` so future
textarea-backed parameters do not reintroduce the obsolete admin class.
2026-08-18 15:30:45 +02:00
Martin Hauser f35702728b
test(ui): Add test coverage for NestedObjectAttr
Adds comprehensive test cases for NestedObjectAttr including ancestor
traversal, max_depth limiting, null value handling, and linkify/colored
options. Uses Region model with MPTT hierarchy for testing nested
object rendering.

Closes #22956
2026-08-18 14:49:59 +02:00
Jeremy Stretch 9c163ba2dd Release v4.7.0-beta1 2026-08-17 13:34:29 -04:00
Jason Novinger 9ebc55c3a4
#18821: Pre-release QA (#22898)
Fixes #18821
2026-08-17 11:26:55 -05:00
Jeremy Stretch f12fe46486 Merge branch 'main' into feature
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 10:26:52 -04:00
Jeremy Stretch a148e2123b
Closes #22942: Upgrade to Django 6.1 (#22943) 2026-08-16 20:39:29 +02:00
Jeremy Stretch 6ecfa972fd #21025: Remove obsolete section from docs 2026-08-14 15:02:00 -04:00
bctiemann 5707c0e9cd
Merge pull request #22919 from netbox-community/19731-cleanup
#19731: Pre-release QA
2026-08-14 14:58:20 -04:00
Jeremy Stretch 3031430523 Consolidate various helper methods on ModuleBayTemplateImportForm into clean() 2026-08-14 14:40:18 -04:00
Jeremy Stretch 9e69498e07
Closes #22935: Deprecate Custom Scripts (#22936) 2026-08-14 20:35:44 +02:00
Jeremy Stretch e57ab760df Fix support for enable=false under DeviceBayTemplateImportForm 2026-08-14 14:27:49 -04:00
Jeremy Stretch 8bffd79360 Correct claim in documentation 2026-08-14 14:17:04 -04:00
Jeremy Stretch 9abbebe392 Add v4.7 release notes 2026-08-14 13:53:02 -04:00
Jeremy Stretch 334e2fa8a1 Closes #22095: Unpin social-auth-core 2026-08-14 13:51:42 -04:00
Martin Hauser f4fdd60e8d
#22592: Pre-release QA (#22920) 2026-08-14 11:09:53 -05:00
Brian Tiemann 6cfda2b49c Address automated review: documentation clarifications for module_bay_types
- Document that ModuleType.to_yaml() exports module_bay_types by name but
  the field isn't currently importable back through it (no ModuleTypeImportForm
  field survived the CSV-import revert).
- modulebaytemplate.md's note covered only the device-type-parented import
  path; ModuleBayTemplateImportForm is registered for both DeviceTypeImportView
  and ModuleTypeImportView, scoping to whichever parent type's manufacturer
  applies. Reworded to cover both, and added the "rejected rather than
  resolved" clause for a name matching only some other manufacturer's type.
- Clarified clean_module_bay_types()'s docstring: the "never a cross-manufacturer
  collision" guarantee holds only because ModularComponentTemplateModel.clean()
  rejects a template with neither device_type nor module_type before this
  method's result would ever be saved.
- Fixed a test docstring overstating symmetry between its two comparison arms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-14 11:39:19 -04:00
Brian Tiemann f65c72da9c Address review: drop module_bay_types CSV import and cross-manufacturer resolution
Per review, ditch dedupe_module_bay_types_by_manufacturer() and any import
logic that resolves module_bay_types by name alone across manufacturers.
ModuleBayType's unique constraint is (manufacturer, name), not name alone,
so resolving a bare name against an unscoped, potentially cross-manufacturer
pool -- guessing via a preference order, rejecting only on a genuine tie --
is not a reliable way to identify a specific object. CSV import forms have
no way to qualify an M2M reference beyond a bare name, so module_bay_types
is no longer exposed there at all (ModuleTypeImportForm, ModuleBayImportForm
in bulk_import.py): it's acceptable not to support this rather than resolve
it unreliably. This also reverts the netbox/tables/columns.py export_transform
API addition and the three tables' use of it, which existed only to make the
CSV round trip work.

The one import path that survives is ModuleBayTemplateImportForm (the YAML
device/module type "Import Components" flow), because it can reliably scope
module_bay_types' queryset to the parent device/module type's own
manufacturer plus global (manufacturer-less) types *before* resolving by
name -- so a name collision is never cross-manufacturer, only "this
manufacturer's own type vs. a global one of the same name," which
ModuleBayType's own uniqueness constraint makes unambiguous. A name matching
only some other manufacturer's type doesn't resolve at all, rather than
being coerced to an arbitrary guess.

Kept: the ModuleBayTemplateImportForm.enabled field/clean_enabled() fix
(default=True was previously lost on YAML re-import; unrelated to the
above), and to_yaml()'s export of module_bay_types on both ModuleType and
ModuleBayTemplate, plus the export_yaml() prefetch optimizations -- none of
these involve resolving an object's identity from an ambiguous attribute.

Trimmed the model docs to match: the modulebay.md and moduletype.md
paragraphs described capabilities (CSV import, cross-manufacturer YAML
import) that no longer exist and are removed; modulebaytemplate.md's note
is rewritten to describe the actual (manufacturer-or-global-scoped)
resolution behavior.
2026-08-14 11:00:25 -04:00
bctiemann 84d0cdad63
#20972: Pre-release QA (#22874)
Allow channel subinterfaces to retain a specific physical interface type
and rename conventionally named children when their parent is renamed.
Keep mirrored cable and path state consistent when channel bindings
change, avoid unnecessary path rebuilds, and apply the same rename
behavior to interface templates.
2026-08-14 16:37:59 +02:00
bctiemann 3793160eba
Merge pull request #22901 from netbox-community/20054-cleanup
#20054: Pre-release QA
2026-08-14 09:00:33 -04:00
Jeremy Stretch 5a4eabacad Employ discard_events_on_rollback() under AvailableObjectsView 2026-08-14 08:30:11 -04:00
Jeremy Stretch ca76dacbf3
#18159: Handle malformed paths and absent data in conditions (Pre-release QA) (#22911)
Distinguish absent values from malformed or unwalkable paths during
condition evaluation.

Preserve valid empty-list traversal, support changes in snapshot shape,
and reject snapshot attributes which are missing from both snapshots.

Normalize absent job payloads and ensure conditioned rules fail closed
when no payload is available. Add regression coverage and streamline the
related documentation and comments.
2026-08-14 10:09:05 +02:00
bctiemann 3666eeb859
Merge pull request #22921 from netbox-community/20285-beta-qa
#20285: Pre-release QA
2026-08-13 19:28:00 -04:00
Brian Tiemann e5c0d60d09 Fix UI regression: transform= changed the rendered column, not just CSV export
django-tables2's ManyToManyColumn.render() and NetBox's own value() override
both call self.transform() for each item -- there's no built-in way to give
CSV export a different representation than the rendered column. Setting
transform=lambda obj: obj.name on the three module_bay_types columns to fix
CSV export therefore also dropped the manufacturer prefix from the Bay Types
column in the Module Bays, Module Bay Templates, and Module Types list
views -- the opposite of what ModuleBayType.__str__() adds that prefix for.
Verified directly: with the old transform=, two same-named bay types from
different manufacturers render as visually identical "SFP28" list items.

Add export_transform to NetBox's ManyToManyColumn subclass, defaulting to
transform so existing columns are unaffected, and used only by value()
(export) rather than render() (UI). Switch the three columns to
export_transform=lambda obj: obj.name, leaving transform unset so render()
keeps str()'s manufacturer prefix.

Extended the existing round-trip test to also assert the rendered column
still includes the manufacturer name; confirmed it fails against the old
transform= approach and passes with export_transform=.
2026-08-13 16:08:31 -04:00
Brian Tiemann faafb1a11f Fix manufacturer-scoped bay type CSV export; tighten ambiguity tests; trim comments
- ModuleBayType.__str__() includes the manufacturer (e.g. "Cisco SFP28"),
  but the three module_bay_types ManyToManyColumn declarations had no
  transform, so django-tables2 defaulted to str() for CSV export while
  the import forms resolve by name alone. Verified directly: exporting
  a manufacturer-scoped bay type produced "Cisco SFP28", which then
  failed to re-import with "Object not found: Cisco SFP28" -- broken
  for exactly the case (manufacturer-scoped types) the preference/
  ambiguity machinery exists to serve. Set transform=lambda obj: obj.name
  on all three columns to match to_yaml(), and rewrote the existing
  round-trip test to use a manufacturer-scoped bay type instead of a
  global one, which is the only case that exercised str().

- The three ambiguity-refusal tests asserted only that the field
  errored, which a plain invalid_choice (e.g. from a queryset that
  excluded both candidates) would also satisfy -- masking a regression
  of the manufacturer scoping removed two commits ago. Tightened each to
  assert the error names both competing manufacturers.

- Corrected modulebay.md, which still described module_bay_types
  resolution as "scoped to" the device's manufacturer -- the behavior
  the prior commit removed as a bug; it's a preference, not a scope.

- Trimmed comments and docstrings introduced across this branch to a
  more proportionate length.

Deliberately out of scope for this PR (tracked as follow-up
considerations, not fixed here): an escape hatch for a bay type name
that's genuinely ambiguous across manufacturers with no local match
(would require a new wire-format convention), and ModuleType.to_yaml()
not exporting a module-bays section at all (a separate, pre-existing
asymmetry, larger than this PR's scope).
2026-08-13 15:21:59 -04:00
Brian Tiemann dfde52df05 Fix CSVModelMultipleChoiceField's own export/import round trip; docs; hardening
- CSVModelMultipleChoiceField.clean() split on a bare comma with no
  whitespace stripping, but ManyToManyColumn's default CSV export
  separator is ", " (comma + space) -- so re-importing NetBox's own CSV
  export of any multi-value column using this field (module_bay_types
  among others, since this is a shared utility field) failed with
  "Object not found:  <value>" on every value after the first. Verified
  directly against ModuleTypeTable's actual export value before fixing.
  Also cast to str() before splitting: a YAML-bound caller (as opposed to
  a CSV cell, always a string) can pass a non-string scalar, which
  previously raised an unhandled AttributeError instead of a form error.

- Docs for module bay type resolution still described the pre-a3b5e4b
  fallback ("then any remaining candidate"); updated to describe the
  refusal behavior that replaced it. Added a matching note to
  modulebay.md, which had none.

- dedupe_module_bay_types_by_manufacturer() collapses candidates by pk
  within each name group before computing preference, so a caller
  passing a duplicate row in a raw list -- the signature accepts "an
  iterable," not just a queryset -- can't manufacture a same-manufacturer
  tie that would then crash on None.manufacturer.name. Unreachable via
  the three current callers today (each resolves from a queryset,
  which can't contain a row twice), but cheap to make the helper safe
  standalone.

- Fixed a stale test docstring contrasting the two import forms' field
  types by a distinction (plain vs. CSV multiple-choice field) that no
  longer exists since both were aligned to CSVModelMultipleChoiceField.

- Added ambiguity-refusal coverage at the other two call sites
  (ModuleBayTemplateImportForm, ModuleBayImportForm) -- previously only
  ModuleTypeImportForm was covered for this path.

Also found independently while verifying the above: ModuleTypeListView
.export_yaml() prefetched modulebaytemplates__module_bay_types, but
ModuleType.to_yaml() -- unlike DeviceType.to_yaml() -- never reads
self.modulebaytemplates at all (a separate, pre-existing, out-of-scope
gap: ModuleType.to_yaml() doesn't export a nested module-bays section).
That prefetch was dead weight, adding a query with no corresponding
saving. Removed it, and with it the now-meaningless "bay count doesn't
affect query count" test (nothing in ModuleType.to_yaml() ever varied
with bay count to begin with), replacing it with an exact-delta
assertion isolating what the one relevant prefetch (module_bay_types
on the module type itself) actually saves.
2026-08-13 14:25:36 -04:00
Jeremy Stretch 93f16a536d
Fixes #22923: Fix post-exception cleanup under event_tracking() (#22926) 2026-08-13 19:56:23 +02:00
Martin Hauser fd4953d772 ci(release): Pin metadata tooling to match publishing action
Pin `twine` and `packaging` versions in build job to match bundled
versions in `gh-action-pypi-publish` v1.14.2.
Enforce Core Metadata 2.4 in wheel and sdist targets with verification
in validation scripts.
2026-08-13 13:56:15 -04:00
Martin Hauser 752dc33ba6 ci(release): Pin metadata tooling to match publishing action
Pin `twine` and `packaging` versions in build job to match bundled
versions in `gh-action-pypi-publish` v1.14.2.
Enforce Core Metadata 2.4 in wheel and sdist targets with verification
in validation scripts.

Fixes #22903
2026-08-13 13:54:09 -04:00
Brian Tiemann a3b5e4b30d Refuse genuinely ambiguous bay-type names; close the ModuleBay CSV gap
- dedupe_module_bay_types_by_manufacturer()'s lowest preference tier (a
  bay type belonging to some manufacturer other than the importing
  type's own) previously picked whichever candidate happened to sort
  first when two or more *different* foreign manufacturers shared a
  name. Verified directly: importing 'SFP28' for a Juniper module type,
  with only Cisco's and Arista's same-named types in the database (no
  Juniper or global one), silently linked to Arista's -- a wrong FK with
  no signal to the importer. The permissive fix from the last round only
  needs this tier to be reachable for the single-candidate case, not
  tolerant of a genuine tie; now raises ValidationError, attributed to
  module_bay_types, naming the competing manufacturers.

- ModuleBayTemplateImportForm.module_bay_types was a plain
  ModelMultipleChoiceField (list only), while ModuleTypeImportForm's
  otherwise-identical field is a CSVModelMultipleChoiceField (list or
  comma-separated string), so `module_bay_types: SFP28` was accepted at
  the module-type level and rejected under `module-bays:` within the
  same YAML document. Switched to CSVModelMultipleChoiceField in both,
  which costs nothing here since it passes lists through unchanged.

- ModuleBayImportForm (CSV import for real ModuleBay instances, as
  opposed to ModuleBayTemplateImportForm's templates) still had no
  module_bay_types support -- the same class of round-trip gap this PR
  exists to close, on the instance side rather than the template side.
  Added it, scoped via the importing device's own device_type.manufacturer.

- The ModuleType prefetch query-count test only varied bay count (module
  type count fixed at 1), so it couldn't detect a regression in the
  module_bay_types prefetch on ModuleType itself -- confirmed directly:
  the test stayed green with that prefetch removed entirely. Varying
  module type count instead doesn't work either, since to_yaml() touches
  several other per-instance relations (manufacturer, port_mappings, ...)
  that legitimately scale with row count regardless of this fix and swamp
  an exact-equality comparison -- hit this myself on the first attempt.
  Replaced with a with/without-prefetch comparison on the identical
  queryset, which isolates the saving without that confound; verified it
  fails when the prefetch is removed and passes when it's present.
2026-08-13 13:29:53 -04:00
Jason Novinger 07d92c9501 #20285: Collapse consecutive ports into ranges in port_mappings_list
port_mappings_list rendered one token per port, so a service exposing a
large contiguous range (e.g. tcp/8000-8100) filled the list column and
detail panel with hundreds of tokens. Collapse consecutive ports within a
protocol into a range for display, matching the compact form the
pre-multi-protocol Service model rendered via array_to_string().
2026-08-13 11:54:38 -05:00
Jason Novinger af59d71642 #20285: Accept port ranges in the service port_mappings CSV import
The port-mappings CSV column expanded only comma-separated individual
protocol/port pairs, while the edit form's port field already accepted
hyphen ranges (e.g. tcp/8000-8010). Route the CSV column through the same
expand_port_mapping() helper so both entry paths accept identical port
syntax. Parsing uses the shared split_port_mapping() helper, and the
blank-protocol error is worded to fit every entry path rather than only the
form widget's dropdown.
2026-08-13 11:53:58 -05:00
Brian Tiemann ec98245ebd Add regression coverage for the CSV (comma-separated string) import path
ModuleTypeImportForm.module_bay_types uses CSVModelMultipleChoiceField
specifically because this form also serves plain CSV bulk import, where the
cell value arrives as a string rather than a list -- unlike
ModuleBayTemplateImportForm.module_bay_types, which only ever binds from a
YAML-parsed list. Every existing test exercised the list-binding path only;
verified the comma-separated-string path directly before adding permanent
coverage for it, including the empty-string case.
2026-08-13 11:34:57 -04:00
Brian Tiemann 6f3c53791b Fix regression: manufacturer scoping made cross-manufacturer bay types unimportable
The manufacturer-or-null queryset scoping added to disambiguate a name shared
by a global and a manufacturer-scoped ModuleBayType went further than
intended: it also excluded a *different* manufacturer's bay type entirely.
The UI (ModuleTypeForm/ModuleBayTemplateForm) and REST API place no such
restriction -- a third-party module may legitimately declare compatibility
with another manufacturer's proprietary bay type. Confirmed the regression
directly: creating that assignment via ModuleTypeForm succeeds, but
exporting it and re-importing the same YAML failed with
"Object not found: SFP28", making valid existing data unimportable -- worse
than the bug this feature exists to fix.

Remove the queryset scoping entirely and instead make
dedupe_module_bay_types_by_manufacturer() manufacturer-aware: given the
target manufacturer, it now prefers (in order) an exact match, then a global
type, then any remaining candidate, resolved from an unscoped queryset in
clean() rather than a sibling clean_<field>() mutating the field's queryset.
This also drops the Meta.fields-ordering dependency those methods required.

Also, from the same review round:
- Test asserting Django's literal English error string now asserts the
  error code instead, so it survives wording changes/translation.
- The prefetch query-count test moved from test_models.py (which doesn't
  otherwise touch views) to test_views.py, and strengthened from "prefetch
  saves at least one query" to "query count is constant regardless of bay
  count" -- the actual invariant. Added equivalent coverage for
  ModuleTypeListView, which the prior version didn't test at all.
- Corrected the export_yaml() prefetch comments to not imply the other
  ~11 relations to_yaml() touches are also covered -- they aren't, and
  weren't before this feature either.
- Updated the model docs to describe the new (permissive, cross-manufacturer
  allowed) behavior instead of the old (restrictive) one they described a
  commit ago.

Adds regression tests importing a bay type belonging to a different
manufacturer than the importing device/module type, through both
ModuleBayTemplateImportForm and ModuleTypeImportForm.
2026-08-13 11:04:47 -04:00
Brian Tiemann 63045d8551 Address review: dead code, ModuleType's own side of the round trip, N+1
- clean_module_bay_types()'s two ValidationErrors were unreachable:
  ModelMultipleChoiceField.clean() already raises before the clean_<name>
  hook runs on a non-list or an unresolvable name, per Django's
  BaseForm._clean_fields(). Simplify to dedupe from cleaned_data (already
  scoped and validated) via a shared dedupe_module_bay_types_by_manufacturer()
  helper in dcim/utils.py, used by both ModuleBayTemplateImportForm and the
  new ModuleTypeImportForm.module_bay_types below. This also drops the
  self.data access that ignored the form prefix, broke on a QueryDict, and
  re-queried once per name.

- ModuleType.module_bay_types (the module's own side of the bay/module
  compatibility intersection) was still missing from the YAML round trip.
  Add it to ModuleType.to_yaml() and ModuleTypeImportForm, mirroring
  ModuleBayTemplateImportForm's manufacturer-scoping and dedup.

- ModuleBayTemplate.to_yaml() emitted enabled but the import form didn't
  accept it, so it silently reset to False (not the model's default=True)
  on any dict-bound re-import. Add it with the same
  clean_enabled()-defaults-to-True pattern already used by
  ModuleBayImportForm's CSV import.

- Prefetch module_bay_types in DeviceTypeListView/ModuleTypeListView's
  export_yaml() so bulk YAML export doesn't add one query per module bay
  template across the exported queryset.

- Document the manufacturer-preference precedence rule in the model docs,
  since export emits a bare name and import can resolve a colliding one to
  either a global or manufacturer-specific type.

Adds regression tests for the module_type-scoped path, the enabled
round trip, an export/import round trip, export ordering, the new
ModuleTypeImportForm coverage, and the prefetch fix.
2026-08-13 09:31:34 -04:00
Brian Tiemann 508e2eaba2 Resolve module_bay_types by name deterministically, not via blind filter
ModuleBayType's unique constraint is on (manufacturer, name), not name
alone, so a global type and a manufacturer-scoped type can legally share
the same name. The manufacturer-or-null queryset scoping added for
ModuleBayTemplateImportForm.module_bay_types left both rows in the
filtered queryset in that case, and ModelMultipleChoiceField's default
name-based lookup silently attached both instead of just the one
referenced -- confirmed by reproducing it directly against the form.

Add clean_module_bay_types() to resolve each submitted name explicitly,
preferring a manufacturer-specific match over a global one, and raising a
clear error for an unresolvable name instead of silently under- or
over-matching. Also factor clean_device_type/clean_module_type's
duplicated scoping logic into a shared helper.
2026-08-13 08:21:47 -04:00
Brian Tiemann 157a30ecd7 #19731: Support module_bay_types in device/module type YAML import and export
Follow-up QA for the ModuleBayType feature added in #22648.

ModuleBayTemplate.to_yaml() omitted module_bay_types, and
ModuleBayTemplateImportForm (used by the DeviceType/ModuleType YAML
"Import Components" flow) didn't expose the field either, so bay-type
constraints could never be defined as part of a device type's YAML
definition -- only assigned by hand, one bay at a time, after import.

Add module_bay_types (by name) to the import form, scoped to the parent
device/module type's manufacturer (or global types) via clean_device_type/
clean_module_type, mirroring the existing scoping pattern used elsewhere in
this form for power_port/cooling_intake. Add it to to_yaml()'s output
symmetrically.
2026-08-13 07:50:59 -04:00
github-actions 0171c0ce5a Update source translation strings 2026-08-13 05:30:28 +00:00
Sri Chandraja Reddy Allala e9405d8f47
Fixes #22683: Prevent server errors when bulk import validation references an omitted field (#22784)
During partial bulk updates, fields omitted from the CSV are removed
from the import form before validation. Model validation can still
return an error for one of these fields, causing Django to raise a
ValueError instead of displaying the validation error.

Remap errors for absent fields to prefixed non-field errors on
NetBoxModelImportForm while preserving their codes, parameters, lazy
pluralization, and literal percent values. Genuine non-field errors
remain unchanged.

Add form-level and view-level regression coverage for mixed and
parameterized errors and for the reported interface bulk-update
workflow, including verification that invalid updates leave the object
unchanged.
2026-08-12 23:22:52 +02:00
bctiemann f89d3b1f20
Closes #22909: Tolerate an undefined column in the deferred search flush (#22910) 2026-08-12 13:23:51 -05:00
Jeremy Stretch d6ba2ae51e Misc cleanup 2026-08-12 13:48:34 -04:00
Jason Novinger feffda99d7
#22447: Pre-release QA (#22908)
* Fixes #22447: Pre-release QA

Add the missing `cooling_outflow` GraphQL filter on CoolingIntake, so an
intake can be filtered by its upstream outflow. CoolingOutflow already
exposes the reverse `cooling_intake` filter and the REST filterset already
carries `cooling_outflow_id`; the GraphQL intake filter was the only side
missing it.

Correct the CoolingIntake docstring, which referenced a direct CoolingFeed
relationship that does not exist. The serving feed is derived from the
device's rack, not stored on the intake.

* Fixes #22447: Pre-release QA (filter form + table parity)

Address the same-class gaps surfaced in review, all mirror images of the
intake/outflow filter parity already fixed:

Add the `cooling_intake_id` filter to CoolingOutflowFilterForm and
CoolingOutflowTemplateFilterForm. The underlying filtersets already carried
`cooling_intake_id` and GraphQL supported it, but the list-view filter panel
did not expose it, so an outflow could not be filtered by its downstream
intake from the UI.

Add `cooling_outflow` to the default columns on CoolingIntakeTable and
DeviceCoolingIntakeTable. The outflow tables already default-show
`cooling_intake`; the intake tables hid the reverse, so the same relationship
displayed inconsistently between the two sides.

Note in the CoolingIntake docstring why CoolingIntakeTemplate has no
upstream-outflow field: an intake's outflow normally lives on a different
device (a CDU), which a device-type template cannot express.
2026-08-12 09:57:00 -07:00
Jeremy Stretch bfb665ccb9
#15289: Pre-release QA (#22897)
* Add support for liquid cooling components

* Include sample of offending components when module move is disallowed

* Use settings.BULK_UPDATE_CHUNK_SIZE for batch_size

* Adopt review feedback
2026-08-12 09:46:50 -07:00
Jeremy Stretch 42df031c06 Map QueryDict to dict inside get_non_list_response() 2026-08-12 11:25:29 -04:00
Jeremy Stretch b9f13c6c75 Use a consistent structure for field errors 2026-08-12 11:20:45 -04:00
Jason Novinger 99f441b090
Closes #15165: Pre-release QA (#22888)
Move the `HTMXSelect` configuration for `InterfaceForm` and
`VMInterfaceForm` onto their explicitly declared `mode` fields so that
changing the 802.1Q mode again refreshes the dependent VLAN fields.

Make `HTMXSelect` description-aware, isolate copied description mappings,
and fix the existing shadowed `VirtualChassisForm.master` widget. Remove
other ineffective `ModelForm.Meta` entries.

Add regression coverage for partial and full-form HTMX swaps, together
with a repository-wide guard against declared fields shadowing supported
`ModelForm.Meta` options.
2026-08-12 12:21:23 +02:00
github-actions f903cbf41d Update source translation strings 2026-08-12 05:29:58 +00:00
bctiemann 4592e7a339
Merge pull request #22904 from netbox-community/19821-gfk-field-qa-tests
#19821: Pre-release QA
2026-08-11 19:18:34 -04:00
bctiemann a08d9f13fc
Merge pull request #22867 from netbox-community/22812-script-delete-memory-exhaustion
Closes #22812: Avoid loading all jobs into memory when deleting a JobsMixin object
2026-08-11 19:17:15 -04:00