Fix single {module} token rejection at nested module bay depth#21740
Conversation
|
@claude /review |
|
Claude finished @arthanson's task in 2m 36s —— View job PR Review: Fix single {module} token rejection at nested module bay depth
OverviewThis PR fixes a valid bug (#20474): installing a module type with a single Code CorrectnessForm fix ( The new logic is correct: token_count = template.name.count(MODULE_TOKEN)
if token_count == 1:
resolved_name = resolved_name.replace(MODULE_TOKEN, module_bays[-1].position)
elif token_count == len(module_bays):
for mb in module_bays:
resolved_name = resolved_name.replace(MODULE_TOKEN, mb.position, 1)
else:
raise forms.ValidationError(...)
Bonus fix: The old loop used Model refactor ( The
Since the old form would have rejected this case entirely, this path was only reachable by bypassing the form. The new behavior (immediate parent) is more intuitive and consistent with the form fix. Worth documenting in the commit message or inline comment, since future readers may not realize Potential Issues1. Form validation not covered by the regression test The regression test in If someone breaks the form fix in 2. Inconsistency: model doesn't validate token count for multi-token case (pre-existing, not introduced here)
3. Error message doesn't hint at single-token exception (minor UX) When a user provides 2 tokens at depth 3, they'd see: "Cannot install module with placeholder values in a module bay tree 3 in tree but 2 placeholders given." They might wonder why 1 token would work fine. Mentioning in the error message (or the model field Test QualityThe test in Gaps to consider:
SummaryThe fix is correct and the refactoring is an improvement. The key concern is that the regression test doesn't exercise the actual user-facing failure mode (the form validation path), so the form fix in |
|
@mrmrcoleman can you fix the merge conflicts with main, otherwise good to go. |
…#20474) A module type with a single {module} placeholder in component template names could not be installed in a nested module bay (depth > 1) because the form validation required an exact match between the token count and the tree depth. This resolves the issue by treating a single {module} token as a reference to the immediate parent bay's position, regardless of nesting depth. Multi-token behavior is unchanged. Refactors resolve_name() and resolve_label() into a shared _resolve_module_placeholder() helper to eliminate duplication. Fixes: netbox-community#20474
1cf73a0 to
7459424
Compare
…ommunity#20474) - Rebase on latest main to resolve merge conflicts - Extract shared module bay traversal and {module} token resolution into dcim/utils.py (get_module_bay_positions, resolve_module_placeholder) - Update ModuleCommonForm, ModularComponentTemplateModel, and ModuleBayTemplate to use shared utility functions - Add {module} token validation to ModuleSerializer.validate() so the API enforces the same rules as the UI form - Remove duplicated _get_module_bay_tree (form) and _get_module_tree (model) methods in favor of the shared routine
…ommunity#20474) - Rebase on latest main to resolve merge conflicts - Extract shared module bay traversal and {module} token resolution into dcim/utils.py (get_module_bay_positions, resolve_module_placeholder) - Update ModuleCommonForm, ModularComponentTemplateModel, and ModuleBayTemplate to use shared utility functions - Add {module} token validation to ModuleSerializer.validate() so the API enforces the same rules as the UI form - Remove duplicated _get_module_bay_tree (form) and _get_module_tree (model) methods in favor of the shared routine
7459424 to
dbc2f4c
Compare
Fixes: #20474
Summary
Fixes a bug where installing a module type with a single
{module}placeholder into a nested module bay (depth > 1) was rejected with: "Cannot install module with placeholder values in a module bay tree 2 in tree but 1 placeholders given."{module}token now resolves to the immediate parent bay's position regardless of nesting depth{module}behavior is unchanged (token count must still match tree depth)resolve_name()andresolve_label()into a shared_resolve_module_placeholder()helper to eliminate duplicationChanges
dcim/forms/common.py{module}token resolves to parent bay position instead of erroring; multi-token validation unchangeddcim/models/device_component_templates.pyresolve_name()/resolve_label()into shared_resolve_module_placeholder()with same single-token logicdcim/tests/test_models.py{module}SFP module installs at depth 2 and resolves to parent positionTesting
All existing dcim model and form tests pass (59 tests). Added one regression test that reproduces the exact scenario from #20474:
SFP {module}interface template into depth 2SFP 2(parent bay position) instead of raising aValidationError