Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #17954 - Handle CircuitTerminations in Cable Bulk Import #17995

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

jsenecal
Copy link
Contributor

Fixes: #17954

Add Support for Bulk Importing Cables Connected to Circuits

This pull request enhances the bulk import functionality for cables by allowing users to specify circuits as termination points on either side of a cable. Previously, only devices could be specified for cable terminations during bulk import which didn't allow for Cables to be connected to Circuit Terminations properly.

Key Changes:

  • Added Fields for Circuit Terminations:

    • Introduced side_a_circuit and side_b_circuit fields in the CableImportForm within dcim/forms/bulk_import.py.
    • These fields are optional and conditional, allowing users to specify a Circuit ID (cid) as a termination point.
  • Updated CableImportForm Validation Logic:

    • Modified the _clean_side method in CableImportForm to handle cases where a circuit is specified instead of a device.
    • Added validation to ensure that both a device and a circuit cannot be specified simultaneously for the same side.
    • Ensured that the termination object is correctly retrieved based on whether a device or circuit is provided.
    • Added checks to prevent connecting to a circuit termination that is already connected to a Provider Network.
  • Enhanced Bulk Import Template:

    • Updated bulk_import.html to display a "Conditional" tag for fields that are conditionally required, improving user experience during the import process.
  • Extended CSV Field Functionality:

    • Modified CSVModelChoiceField in utilities/forms/fields/csv.py to accept a conditional parameter.
    • This parameter is used to indicate fields that are conditionally required based on other form fields.

Benefits:

  • Improved Flexibility: Users can now bulk import cables that connect directly to circuits, not just devices.
  • Enhanced User Experience: Clearer form validation messages and template indicators help prevent import errors.
  • Increased Efficiency: Streamlines the process of importing large numbers of cables connected to circuits.

Usage Notes:

  • When importing, specify either a device or a circuit for each side of the cable—not both.
  • Ensure that the circuit terminations are not already connected to a Provider Network to avoid validation errors.

@jsenecal jsenecal force-pushed the 17954_cable_bulk_import_circuit_terminations branch from 48b1c7b to 2721455 Compare November 12, 2024 20:45
termination_object = model.objects.get(device=device, name=name)

# Should never happen as we return None above if we don't have a device or circuit
assert device or circuit
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the things we came up to in another PR, is asserts are not a guaranteed thing since it requires python to be compiled with debug=true.

I am actually going to defer to Jeremy on whether we want to stick with asserts or not.

queryset=Circuit.objects.all(),
to_field_name='cid',
required=False,
conditional=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment re: conditional below

@@ -1189,8 +1200,18 @@ class CableImportForm(NetBoxModelImportForm):
label=_('Side B device'),
queryset=Device.objects.all(),
to_field_name='name',
required=False,
conditional=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment re: conditional below

queryset=Circuit.objects.all(),
to_field_name='cid',
required=False,
conditional=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment re: conditional below

@@ -1171,8 +1172,18 @@ class CableImportForm(NetBoxModelImportForm):
label=_('Side A device'),
queryset=Device.objects.all(),
to_field_name='name',
required=False,
conditional=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment re: conditional below

Comment on lines +132 to +133
{% elif field.conditional %}
<span class="badge bg-yellow text-yellow-fg" >{% trans "Conditional" %}</span>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment re: conditional below

Comment on lines +60 to +64
def __init__(self, conditional=False, *args, **kwargs):
# Used to display tags for fields that are conditionally required
self.conditional = conditional
super().__init__(*args, **kwargs)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not myself prepared to make a decision on whether this is something we should consider introducing.

That said, I think that if this is something we want to persue further, there should be a FR for it and a related PR as I am sure there is more then just this.

For example, it marks it as a conditionally required value but do we want to enrich that further by telling the end-user which fields are part of this conditional group?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your input. I did consider enriching the frontend to indicate which fields are part of the conditional group when adding the conditional attribute. However, I felt that this might be out of scope for this particular issue. The main goal here was to provide a way to mark those fields as conditionally required in the frontend. without altering much of the existing functionality.

I'm open to exploring further enhancements to improve user guidance on conditional fields, possibly in a separate feature request if needed.

@jeremystretch
Copy link
Member

As mentioned in the comments on #17954, this limitation also impacts power feeds. IMO we should solve for both circuit terminations and power feeds here.

Instead of introducing additional fields, I'll suggest rename side_x_device to side_x_parent, and repurposing it to indicate the parent object (circuit, device, or power panel) depending on the selected type of termination for each side.

@jsenecal
Copy link
Contributor Author

jsenecal commented Dec 10, 2024

As mentioned in the comments on #17954, this limitation also impacts power feeds. IMO we should solve for both circuit terminations and power feeds here.

I did not tackle the other one as I wanted a consensus on the methodology first. I don't mind fixing both the same way.

Instead of introducing additional fields, I'll suggest rename side_x_device to side_x_parent, and repurposing it to indicate the parent object (circuit, device, or power panel) depending on the selected type of termination for each side.

Do you suggest that we design a replacement for CSVModelChoiceField? I don't know of a current CSV*Field that allows for a dynamic lookup like the one you suggest here @jeremystretch; Also, the accessor is different for each ContentType, which makes me wonder how to properly convey its usage.

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.

Cable bulk import when importing circuit terminations
3 participants