Skip to content

Refactor detail views to the UI Component Framework (#196) - #395

Open
jvanderaa wants to merge 1 commit into
developfrom
uicomponents-nautobot3
Open

Refactor detail views to the UI Component Framework (#196)#395
jvanderaa wants to merge 1 commit into
developfrom
uicomponents-nautobot3

Conversation

@jvanderaa

Copy link
Copy Markdown
Collaborator

Closes #196.

Re-homes the UI Component Framework refactor onto develop. The original work is @Pavan-183's (#350) and he is credited as co-author; this PR adapts it to Nautobot 3, incorporates review feedback, and adds test coverage.

Why this targets develop rather than the integration branch

#350 was merged into the u/pavan-uicomponents-easy-kc integration branch. That branch pins nautobot = ">=2.4.16,<3.0.0" and was cut before Nautobot 3.0 shipped, so it can no longer be tested against a supported Nautobot — its CI stable legs fail at import with ImportError: cannot import name 'PluginCustomValidator' (renamed to CustomValidator in Nautobot 3), in files unrelated to the refactor.

Nautobot 2 support lives on ltm-2.4; develop and main are Nautobot 3 only. So there is no Nautobot 2 obligation for this change, and the stale imports simply disappear by building on develop, which already carries the migrated versions of those files.

The refactor itself is still needed — develop had not independently migrated. Its detail views still used get_extra_context() and all four *_retrieve.html templates were still present.

What this does

  • Moves the CircuitMaintenance, CircuitImpact, Note, RawNotification, and NotificationSource detail views to declarative ObjectDetailContent panels.
  • Deletes the four custom *_retrieve.html templates and note.html, which the framework now renders. parsednotification.html is kept — ParsedNotificationView is still a plain ObjectView.
  • Adds table columns and a ParsedNotificationTable for the new panels.

Nautobot 3 adaptations (not in the original)

  • Imports come from the public nautobot.apps.ui surface rather than nautobot.core.ui.object_detail / nautobot.core.ui.choices. All the components are exported there, and app development standards prefer nautobot.apps.*.
  • enable_related_link=False on the ParsedNotification panel. ParsedNotification is detail-only — urls.py defines no list route — so the panel's badge link had no URL to resolve to and logged a warning on every Circuit Maintenance page view. Nautobot 3 enforces this via test_body_content_table_list_url, which failed until this was set. This is a genuine bug the 2.4-era branch could not surface.

Review feedback incorporated from #350

  • validate_source no longer raises on OAuth sources. Source.test_authentication() deliberately re-raises RedirectAuthorize for OAuth sources (e.g. Gmail) needing consent. The refactor caught only (AttributeError, TypeError, ValueError), so it escaped as an unhandled 500 — and the "Validate Authentication" button links straight to that action. It now catches RedirectAuthorize and redirects to the provider consent flow, logs ValueError failures with exc_info=True, and reports the outcome via a messages flash plus a redirect to the detail view. This replaces the temporary scaffolding that rendered the legacy template with three hand-built empty tables.
    • The pre-refactor code also honored a return_url GET parameter and redirected to it. That is intentionally not restored — redirecting to a user-supplied URL is an open-redirect risk. The redirect always goes to the object's own detail page.
  • Removed a dead CustomMaintenanceFieldsPanel whose computed notification_provider value was never read.
  • Removed duplicated serializer_class / table_class / action_buttons declarations on RawNotificationUIViewSet.
  • Narrowed over-broad exception handling in NotificationObjectFieldsPanel.get_data to ValueError and restored logging on the failure path.
  • Addressed @gsnider2195's and @glennmatthews' notes from Refactored UIComponents Updated as per the previous comments #350 (ButtonActionColorChoices for the Validate button, no out-of-scope view churn).

Deliberately excluded

  • Pavan's forms.py change swapped CircuitMaintenanceBulkEditForm's bases to (NautobotBulkEditForm, TagsBulkEditFormMixin). Mixins belong before the base form class, so develop's existing order is kept.
  • develop intentionally removed custom_view_additional_permissions from the validate_source action; that removal is preserved rather than reverted.
  • Cosmetic template churn from the original branch (quote style, named {% endblock %}, stripped trailing newlines) is omitted to keep the diff reviewable.

Testing

  • Full suite: 294/296, then test_views 196 OK (31 skipped) after the enable_related_link fix.
  • The one remaining failure is test_basics.TestVersion ('3.0.1a0' != '3.1.2a0'), which reproduces identically on a pristine develop checkout — a stale app version in the local container image, unrelated to this change.
  • ruff check and ruff format --check clean.
  • Adds test_validate_view_redirect_authorize, a regression test for the OAuth path, and updates the two existing validate tests for the redirect-and-flash behavior.

Supersedes

Screenshots

Detail-view rendering is unchanged in intent but now driven by panels rather than templates. Happy to attach before/after captures of the Circuit Maintenance, Notification Source, and Raw Notification detail pages if that would help review.

Re-homes the UIComponent refactor from the u/pavan-uicomponents-easy-kc
integration branch onto develop. That branch pinned nautobot >=2.4.16,<3.0.0
and predated Nautobot 3.0, so it could no longer be tested against a
supported Nautobot; Nautobot 2 support lives on ltm-2.4, not develop.

- Move CircuitMaintenance, CircuitImpact, Note, RawNotification, and
  NotificationSource detail views to declarative ObjectDetailContent panels
  and drop the custom *_retrieve.html templates and the now-unused note.html.
- Import the UI components from the public nautobot.apps.ui surface rather
  than nautobot.core.ui.*, per app development standards.
- Disable the related-object badge link on the ParsedNotification panel;
  ParsedNotification is detail-only, so no list URL exists to link to. This
  is enforced by Nautobot 3's test_body_content_table_list_url.
- Handle RedirectAuthorize in validate_source so OAuth sources redirect to
  the provider consent flow instead of raising, log ValueError failures, and
  report the result via a messages flash and a redirect to the detail view.
- Add table columns for the new panels, and a regression test for the OAuth
  validate path.

Co-authored-by: Pavan-183 <pavan.pulicherla@networktocode.com>
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  nautobot_circuit_maintenance
  tables.py
  views.py 337-341, 347-350, 432-441, 454-459, 529-537
Project Total  

This report was generated by python-coverage-comment-action

Comment on lines 75 to 77
maintenance = tables.Column(linkify=True)
circuit = tables.Column(linkify=True)
impact = tables.Column(linkify=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove maintenance and circuit columns? They're no longer in Meta.fields - intentional?

circuit = tables.Column(linkify=True)
impact = tables.Column(linkify=True)

cid = tables.Column(accessor="circuit.cid", verbose_name="ID", linkify=True)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IIRC the . pattern in accessors is deprecated by django-tables2, which prefers __ instead.

"title",
"last_updated",
"comment",
) # pylint:disable=nb-use-fields-all

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unneeded comment?

Comment on lines +164 to +165
raw_notification_source = tables.Column(accessor="raw_notification.source", verbose_name="Source")
stamp = tables.Column(accessor="raw_notification.stamp", verbose_name="Received")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Missing from Meta.fields? Remove?

ObjectView,
)
from nautobot.circuits.models import Circuit
from nautobot.core.choices import ButtonActionColorChoices

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

importable from nautobot.apps.choices (preferred)

)
from nautobot.circuits.models import Circuit
from nautobot.core.choices import ButtonActionColorChoices
from nautobot.core.templatetags import helpers

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

import individual template tags from nautobot.apps.templatetags instead.

Comment on lines +337 to +341
elif not isinstance(value, (bytes, bytearray)):
try:
value = bytes(value or b"")
except (TypeError, ValueError):
value = b""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

possible to add test coverage for this?

Comment on lines +430 to +431
setattr(instance, "account", source.get_account_id())
setattr(instance, "source_type", source.__class__.__name__)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not obvious to me why we need to use setattr() here and below, versus just directly assigning instance.account = source.get_account_id(), etc.

Comment on lines +454 to +459
items = []
for val in value:
items.append(helpers.hyperlinked_object(val))
if not items:
return helpers.HTML_NONE
return format_html(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add test coverage? LInes 457-458 look unnecessary/unreachable to me.

nautobot-bot pushed a commit that referenced this pull request Aug 10, 2026
…r Tool

## [nautobot-app-v2.7.3 (2026-08-07)](https://github.com/nautobot/cookiecutter-nautobot-app/releases/tag/nautobot-app-v2.7.3)

### Changed

- [#395](nautobot/cookiecutter-nautobot-app#395) - Added `target` and `recursive` options to `invoke pylint` tasks.
- [#396](nautobot/cookiecutter-nautobot-app#396) - Added a `--diff` option to the `invoke ruff` tasks.
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.

Switch to Object Detail View

2 participants