nautobot 2.4.14__py3-none-any.whl → 2.4.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (433) hide show
  1. nautobot/apps/choices.py +8 -0
  2. nautobot/apps/ui.py +14 -0
  3. nautobot/core/api/views.py +2 -0
  4. nautobot/core/choices.py +4 -0
  5. nautobot/core/filters.py +21 -41
  6. nautobot/core/management/commands/check_job_approval_status.py +47 -0
  7. nautobot/core/management/commands/generate_test_data.py +1 -1
  8. nautobot/core/management/commands/migrate.py +1 -1
  9. nautobot/core/models/tree_queries.py +17 -0
  10. nautobot/core/settings.py +2 -2
  11. nautobot/core/tables.py +25 -2
  12. nautobot/core/templates/base_django.html +1 -1
  13. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  14. nautobot/core/templates/generic/object_list.html +17 -20
  15. nautobot/core/templates/inc/breadcrumbs.html +14 -0
  16. nautobot/core/templatetags/buttons.py +2 -4
  17. nautobot/core/templatetags/helpers.py +29 -6
  18. nautobot/core/templatetags/ui_framework.py +21 -0
  19. nautobot/core/testing/filters.py +20 -3
  20. nautobot/core/testing/forms.py +1 -1
  21. nautobot/core/tests/integration/test_filters.py +2 -2
  22. nautobot/core/tests/test_breadcrumbs.py +366 -0
  23. nautobot/core/tests/test_commands.py +40 -0
  24. nautobot/core/tests/test_filters.py +51 -1
  25. nautobot/core/tests/test_forms.py +1 -1
  26. nautobot/core/tests/test_graphql.py +4 -4
  27. nautobot/core/tests/test_titles.py +183 -0
  28. nautobot/core/tests/test_tree_queries.py +30 -0
  29. nautobot/core/tests/test_views.py +2 -2
  30. nautobot/core/tests/test_views_utils.py +1 -1
  31. nautobot/core/ui/breadcrumbs.py +538 -0
  32. nautobot/core/ui/bulk_buttons.py +53 -0
  33. nautobot/core/ui/object_detail.py +31 -8
  34. nautobot/core/ui/titles.py +127 -0
  35. nautobot/core/ui/utils.py +25 -0
  36. nautobot/core/utils/migrations.py +1 -1
  37. nautobot/core/views/__init__.py +1 -1
  38. nautobot/core/views/mixins.py +26 -1
  39. nautobot/core/views/renderers.py +20 -2
  40. nautobot/core/views/utils.py +13 -12
  41. nautobot/dcim/api/serializers.py +9 -0
  42. nautobot/dcim/choices.py +53 -0
  43. nautobot/dcim/filters/__init__.py +15 -3
  44. nautobot/dcim/forms.py +120 -7
  45. nautobot/dcim/management/commands/trace_paths.py +1 -1
  46. nautobot/dcim/migrations/0072_alter_powerfeed_options_and_more.py +97 -0
  47. nautobot/dcim/models/device_component_templates.py +8 -0
  48. nautobot/dcim/models/device_components.py +31 -12
  49. nautobot/dcim/models/devices.py +1 -1
  50. nautobot/dcim/models/power.py +171 -10
  51. nautobot/dcim/models/racks.py +7 -4
  52. nautobot/dcim/tables/devices.py +2 -0
  53. nautobot/dcim/tables/devicetypes.py +1 -0
  54. nautobot/dcim/tables/power.py +30 -2
  55. nautobot/dcim/templates/dcim/device.html +2 -2
  56. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -214
  57. nautobot/dcim/templates/dcim/location_retrieve.html +2 -2
  58. nautobot/dcim/templates/dcim/powerfeed_edit.html +8 -0
  59. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -1
  60. nautobot/dcim/tests/integration/test_device_bulk_operations.py +61 -0
  61. nautobot/dcim/tests/test_api.py +24 -4
  62. nautobot/dcim/tests/test_filters.py +91 -13
  63. nautobot/dcim/tests/test_models.py +262 -0
  64. nautobot/dcim/tests/test_views.py +20 -12
  65. nautobot/dcim/utils.py +9 -0
  66. nautobot/dcim/views.py +390 -77
  67. nautobot/extras/factory.py +19 -20
  68. nautobot/extras/filters/__init__.py +3 -2
  69. nautobot/extras/filters/mixins.py +15 -1
  70. nautobot/extras/forms/__init__.py +2 -1
  71. nautobot/extras/forms/forms.py +62 -0
  72. nautobot/extras/managers.py +4 -1
  73. nautobot/extras/migrations/0125_jobresult_date_started.py +18 -0
  74. nautobot/extras/models/customfields.py +1 -2
  75. nautobot/extras/models/datasources.py +1 -2
  76. nautobot/extras/models/jobs.py +7 -3
  77. nautobot/extras/plugins/views.py +24 -1
  78. nautobot/extras/secrets/__init__.py +1 -1
  79. nautobot/extras/tables.py +9 -0
  80. nautobot/extras/templates/extras/customfield.html +2 -129
  81. nautobot/extras/templates/extras/customfield_edit.html +2 -108
  82. nautobot/extras/templates/extras/customfield_retrieve.html +129 -0
  83. nautobot/extras/templates/extras/customfield_update.html +108 -0
  84. nautobot/extras/templates/extras/inc/jobresult.html +7 -3
  85. nautobot/extras/templates/extras/jobresult.html +2 -155
  86. nautobot/extras/templates/extras/jobresult_retrieve.html +155 -0
  87. nautobot/extras/templates/extras/marketplace.html +5 -6
  88. nautobot/extras/templates/extras/note.html +2 -53
  89. nautobot/extras/templates/extras/note_retrieve.html +53 -0
  90. nautobot/extras/templates/extras/plugins_list.html +5 -6
  91. nautobot/extras/templatetags/custom_links.py +2 -2
  92. nautobot/extras/templatetags/job_buttons.py +1 -1
  93. nautobot/extras/templatetags/plugins.py +1 -1
  94. nautobot/extras/tests/integration/test_computedfields.py +2 -2
  95. nautobot/extras/tests/integration/test_customfields.py +14 -11
  96. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  97. nautobot/extras/tests/integration/test_notes.py +1 -1
  98. nautobot/extras/tests/integration/test_plugins.py +6 -6
  99. nautobot/extras/tests/integration/test_relationships.py +2 -2
  100. nautobot/extras/tests/test_filters.py +9 -0
  101. nautobot/extras/tests/test_forms.py +2 -2
  102. nautobot/extras/tests/test_plugins.py +2 -3
  103. nautobot/extras/tests/test_relationships.py +7 -7
  104. nautobot/extras/tests/test_views.py +172 -1
  105. nautobot/extras/urls.py +3 -59
  106. nautobot/extras/utils.py +1 -1
  107. nautobot/extras/views.py +77 -178
  108. nautobot/ipam/tables.py +8 -15
  109. nautobot/ipam/tests/migration/test_migrations.py +8 -8
  110. nautobot/ipam/tests/test_api.py +2 -2
  111. nautobot/ipam/tests/test_models.py +1 -1
  112. nautobot/project-static/docs/404.html +23 -0
  113. nautobot/project-static/docs/apps/index.html +23 -0
  114. nautobot/project-static/docs/apps/nautobot-apps.html +23 -0
  115. nautobot/project-static/docs/assets/_mkdocstrings.css +44 -6
  116. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +28 -0
  117. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +25 -0
  118. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +128 -20
  119. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +37 -4
  120. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +39 -6
  121. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +25 -0
  122. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +24 -0
  123. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +32 -5
  124. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +41 -8
  125. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +39 -7
  126. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +43 -10
  127. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +74 -59
  128. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +143 -28
  129. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +43 -12
  130. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +135 -53
  131. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +229 -36
  132. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +27 -1
  133. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +30 -1
  134. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +162 -18
  135. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +258 -51
  136. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5987 -2620
  137. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +25 -0
  138. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +154 -55
  139. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +150 -35
  140. nautobot/project-static/docs/development/apps/api/configuration-view.html +23 -0
  141. nautobot/project-static/docs/development/apps/api/database-backend-config.html +23 -0
  142. nautobot/project-static/docs/development/apps/api/models/django-admin.html +23 -0
  143. nautobot/project-static/docs/development/apps/api/models/global-search.html +23 -0
  144. nautobot/project-static/docs/development/apps/api/models/graphql.html +23 -0
  145. nautobot/project-static/docs/development/apps/api/models/index.html +23 -0
  146. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +23 -0
  147. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +23 -0
  148. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +23 -0
  149. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +23 -0
  150. nautobot/project-static/docs/development/apps/api/platform-features/index.html +23 -0
  151. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +23 -0
  152. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +23 -0
  153. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +23 -0
  154. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +23 -0
  155. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +23 -0
  156. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +23 -0
  157. nautobot/project-static/docs/development/apps/api/prometheus.html +23 -0
  158. nautobot/project-static/docs/development/apps/api/setup.html +23 -0
  159. nautobot/project-static/docs/development/apps/api/testing.html +23 -0
  160. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +23 -0
  161. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +23 -0
  162. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +23 -0
  163. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +23 -0
  164. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +23 -0
  165. nautobot/project-static/docs/development/apps/api/views/base-template.html +23 -0
  166. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +23 -0
  167. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +23 -0
  168. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +23 -0
  169. nautobot/project-static/docs/development/apps/api/views/index.html +23 -0
  170. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +23 -0
  171. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -2
  172. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +23 -0
  173. nautobot/project-static/docs/development/apps/api/views/notes.html +23 -0
  174. nautobot/project-static/docs/development/apps/api/views/rest-api.html +23 -0
  175. nautobot/project-static/docs/development/apps/api/views/urls.html +23 -0
  176. nautobot/project-static/docs/development/apps/index.html +23 -0
  177. nautobot/project-static/docs/development/apps/migration/code-updates.html +23 -0
  178. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +23 -0
  179. nautobot/project-static/docs/development/apps/migration/from-v1.html +23 -0
  180. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +23 -0
  181. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +23 -0
  182. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +23 -0
  183. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +23 -0
  184. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +26 -3
  185. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +10544 -0
  186. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +23 -0
  187. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +23 -0
  188. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +23 -0
  189. nautobot/project-static/docs/development/apps/porting-from-netbox.html +26 -3
  190. nautobot/project-static/docs/development/core/application-registry.html +23 -0
  191. nautobot/project-static/docs/development/core/best-practices.html +23 -0
  192. nautobot/project-static/docs/development/core/bootstrap-ui.html +23 -0
  193. nautobot/project-static/docs/development/core/caching.html +23 -0
  194. nautobot/project-static/docs/development/core/controllers.html +23 -0
  195. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +23 -0
  196. nautobot/project-static/docs/development/core/generic-views.html +23 -0
  197. nautobot/project-static/docs/development/core/getting-started.html +23 -0
  198. nautobot/project-static/docs/development/core/homepage.html +23 -0
  199. nautobot/project-static/docs/development/core/index.html +23 -0
  200. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +23 -0
  201. nautobot/project-static/docs/development/core/model-checklist.html +23 -0
  202. nautobot/project-static/docs/development/core/model-features.html +23 -0
  203. nautobot/project-static/docs/development/core/natural-keys.html +23 -0
  204. nautobot/project-static/docs/development/core/navigation-menu.html +23 -0
  205. nautobot/project-static/docs/development/core/release-checklist.html +23 -0
  206. nautobot/project-static/docs/development/core/role-internals.html +23 -0
  207. nautobot/project-static/docs/development/core/settings.html +23 -0
  208. nautobot/project-static/docs/development/core/style-guide.html +23 -0
  209. nautobot/project-static/docs/development/core/templates.html +23 -0
  210. nautobot/project-static/docs/development/core/testing.html +23 -0
  211. nautobot/project-static/docs/development/core/ui-component-framework.html +713 -255
  212. nautobot/project-static/docs/development/core/user-preferences.html +23 -0
  213. nautobot/project-static/docs/development/index.html +23 -0
  214. nautobot/project-static/docs/development/jobs/getting-started.html +23 -0
  215. nautobot/project-static/docs/development/jobs/index.html +23 -0
  216. nautobot/project-static/docs/development/jobs/installation.html +23 -0
  217. nautobot/project-static/docs/development/jobs/job-extensions.html +23 -0
  218. nautobot/project-static/docs/development/jobs/job-logging.html +23 -0
  219. nautobot/project-static/docs/development/jobs/job-patterns.html +23 -0
  220. nautobot/project-static/docs/development/jobs/job-structure.html +23 -0
  221. nautobot/project-static/docs/development/jobs/migration/from-v1.html +23 -0
  222. nautobot/project-static/docs/development/jobs/testing.html +23 -0
  223. nautobot/project-static/docs/index.html +23 -0
  224. nautobot/project-static/docs/media/development/core/ui-component-framework/breadcrumbs-titles-data-flow.png +0 -0
  225. nautobot/project-static/docs/media/power_distribution.png +0 -0
  226. nautobot/project-static/docs/objects.inv +0 -0
  227. nautobot/project-static/docs/overview/application_stack.html +23 -0
  228. nautobot/project-static/docs/overview/design_philosophy.html +23 -0
  229. nautobot/project-static/docs/release-notes/index.html +23 -0
  230. nautobot/project-static/docs/release-notes/version-1.0.html +23 -0
  231. nautobot/project-static/docs/release-notes/version-1.1.html +23 -0
  232. nautobot/project-static/docs/release-notes/version-1.2.html +23 -0
  233. nautobot/project-static/docs/release-notes/version-1.3.html +23 -0
  234. nautobot/project-static/docs/release-notes/version-1.4.html +23 -0
  235. nautobot/project-static/docs/release-notes/version-1.5.html +23 -0
  236. nautobot/project-static/docs/release-notes/version-1.6.html +23 -0
  237. nautobot/project-static/docs/release-notes/version-2.0.html +23 -0
  238. nautobot/project-static/docs/release-notes/version-2.1.html +23 -0
  239. nautobot/project-static/docs/release-notes/version-2.2.html +23 -0
  240. nautobot/project-static/docs/release-notes/version-2.3.html +23 -0
  241. nautobot/project-static/docs/release-notes/version-2.4.html +231 -0
  242. nautobot/project-static/docs/requirements.txt +2 -2
  243. nautobot/project-static/docs/search/search_index.json +1 -1
  244. nautobot/project-static/docs/sitemap.xml +303 -299
  245. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  246. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +23 -0
  247. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +23 -0
  248. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +23 -0
  249. nautobot/project-static/docs/user-guide/administration/configuration/index.html +23 -0
  250. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +23 -0
  251. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +23 -0
  252. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +23 -0
  253. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +23 -0
  254. nautobot/project-static/docs/user-guide/administration/guides/docker.html +23 -0
  255. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +23 -0
  256. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +23 -0
  257. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +23 -0
  258. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +23 -0
  259. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +23 -0
  260. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +23 -0
  261. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +23 -0
  262. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +23 -0
  263. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +23 -0
  264. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +23 -0
  265. nautobot/project-static/docs/user-guide/administration/installation/index.html +23 -0
  266. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +23 -0
  267. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +23 -0
  268. nautobot/project-static/docs/user-guide/administration/installation/services.html +23 -0
  269. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +23 -0
  270. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +23 -0
  271. nautobot/project-static/docs/user-guide/administration/security/index.html +23 -0
  272. nautobot/project-static/docs/user-guide/administration/security/notices.html +23 -0
  273. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +284 -219
  274. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +23 -0
  275. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +23 -0
  276. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +23 -0
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +23 -0
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +23 -0
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +23 -0
  280. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +23 -0
  281. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +23 -0
  282. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +23 -0
  283. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +23 -0
  284. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +23 -0
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +23 -0
  286. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +23 -0
  287. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +23 -0
  288. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +23 -0
  289. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +23 -0
  290. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +23 -0
  291. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +23 -0
  292. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +23 -0
  293. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +23 -0
  294. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +23 -0
  295. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +23 -0
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +23 -0
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +23 -0
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +23 -0
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +23 -0
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +23 -0
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +23 -0
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +23 -0
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +23 -0
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +23 -0
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +23 -0
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +23 -0
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +23 -0
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +23 -0
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +23 -0
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +23 -0
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +23 -0
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +23 -0
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +23 -0
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +23 -0
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +23 -0
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +23 -0
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +23 -0
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +23 -0
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +23 -0
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +23 -0
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +23 -0
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +23 -0
  323. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +23 -0
  324. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +305 -5
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +24 -1
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +23 -0
  327. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +136 -3
  328. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +41 -1
  329. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +40 -0
  330. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +23 -0
  331. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +23 -0
  332. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +23 -0
  333. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +23 -0
  334. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +23 -0
  335. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +23 -0
  336. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +23 -0
  337. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +23 -0
  338. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +23 -0
  339. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +23 -0
  340. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +23 -0
  341. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +23 -0
  342. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +23 -0
  343. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +23 -0
  344. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +23 -0
  345. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +23 -0
  346. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +23 -0
  347. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +23 -0
  348. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +23 -0
  349. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +23 -0
  350. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +23 -0
  351. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +23 -0
  352. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +23 -0
  353. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +23 -0
  354. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +23 -0
  355. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +23 -0
  356. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +23 -0
  357. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +23 -0
  358. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +23 -0
  359. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +23 -0
  360. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +23 -0
  361. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +23 -0
  362. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +23 -0
  363. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +23 -0
  364. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +23 -0
  365. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +23 -0
  366. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +23 -0
  367. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +23 -0
  368. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +23 -0
  369. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +23 -0
  370. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +23 -0
  371. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +23 -0
  372. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +23 -0
  373. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +23 -0
  374. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +23 -0
  375. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +23 -0
  376. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +23 -0
  377. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +23 -0
  378. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +23 -0
  379. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +23 -0
  380. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +23 -0
  381. nautobot/project-static/docs/user-guide/index.html +23 -0
  382. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +23 -0
  383. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +23 -0
  384. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +23 -0
  385. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +23 -0
  386. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +23 -0
  387. nautobot/project-static/docs/user-guide/platform-functionality/events.html +23 -0
  388. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +23 -0
  389. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +23 -0
  390. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +23 -0
  391. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +23 -0
  392. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +23 -0
  393. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +23 -0
  394. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +23 -0
  395. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +24 -1
  396. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +23 -0
  397. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +23 -0
  398. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +23 -0
  399. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +23 -0
  400. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +23 -0
  401. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +23 -0
  402. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +23 -0
  403. nautobot/project-static/docs/user-guide/platform-functionality/note.html +23 -0
  404. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +23 -0
  405. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +23 -0
  406. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +23 -0
  407. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +23 -0
  408. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +23 -0
  409. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +23 -0
  410. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +23 -0
  411. nautobot/project-static/docs/user-guide/platform-functionality/role.html +23 -0
  412. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +23 -0
  413. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +23 -0
  414. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +23 -0
  415. nautobot/project-static/docs/user-guide/platform-functionality/status.html +23 -0
  416. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +23 -0
  417. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +23 -0
  418. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +23 -0
  419. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +23 -0
  420. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +23 -0
  421. nautobot/users/tests/test_api.py +2 -2
  422. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -252
  423. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -75
  424. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +252 -0
  425. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +75 -0
  426. nautobot/virtualization/urls.py +3 -61
  427. nautobot/virtualization/views.py +48 -72
  428. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/METADATA +24 -24
  429. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/RECORD +433 -416
  430. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/LICENSE.txt +0 -0
  431. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/NOTICE +0 -0
  432. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/WHEEL +0 -0
  433. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,127 @@
1
+ from typing import Literal, Optional
2
+
3
+ from django.template import Context, Template
4
+ from django.utils.html import strip_tags
5
+
6
+ DEFAULT_TITLES: dict[str, str] = {
7
+ "list": "{{ verbose_name_plural|bettertitle }}",
8
+ "detail": "{{ object.display|default:object }}",
9
+ "retrieve": "{{ object.display|default:object }}",
10
+ "destroy": "Delete {{ verbose_name }}?",
11
+ "create": "Add a new {{ verbose_name }}",
12
+ "update": "Editing {{ verbose_name }} {{ object.display|default:object }}",
13
+ "bulk_destroy": "Delete {{ total_objs_to_delete }} {{ verbose_name_plural|bettertitle }}?",
14
+ "bulk_rename": "Renaming {{ selected_objects|length }} {{ verbose_name_plural|bettertitle }} on {{ parent_name }}",
15
+ "bulk_update": "Editing {{ objs_count }} {{ verbose_name_plural|bettertitle }}",
16
+ "changelog": "{{ object.display|default:object }} - Change Log",
17
+ "notes": "{{ object.display|default:object }} - Notes",
18
+ "approve": "Approve {{ verbose_name|bettertitle }}?",
19
+ "deny": "Deny {{ verbose_name|bettertitle }}?",
20
+ }
21
+
22
+ DEFAULT_PLUGINS = ["helpers"]
23
+
24
+ ModeType = Literal["html", "plain"]
25
+
26
+
27
+ class Titles:
28
+ """
29
+ Base class for document titles and page headings.
30
+
31
+ This class provides a mechanism to define per-action title templates.
32
+ Titles can be dynamically rendered using context variables and template tags using the Django template engine and context.
33
+ Use the `render()` method to obtain either rich (HTML) or plain (stripped of HTML) output.
34
+
35
+ There is a dedicated simple tag to render `Titles` passed in the `context['view_titles']`: `{% render_title mode="html" %}`
36
+
37
+ Attributes:
38
+ titles (dict[str, str]): Action-to-title-template mapping.
39
+ template_plugins (list[str]): List of Django template libraries to load before rendering.
40
+
41
+ Args:
42
+ template_plugins (Optional[list[str]]): Template libraries to load into rendering.
43
+ titles (dict): Action-to-template-string mappings that override or extend the defaults.
44
+ """
45
+
46
+ def __init__(self, template_plugins: Optional[list[str]] = None, titles: Optional[dict[str, str]] = None):
47
+ """
48
+ Keyword arguments passed can either add new action-title pair or override existing titles.
49
+
50
+ Args:
51
+ template_plugins (Optional[list[str]]): Extra Django template libraries to load before rendering.
52
+ titles (Optional[dict[str, str]]): Custom or overriding mappings from action to template string.
53
+ """
54
+ self.titles: dict[str, str] = DEFAULT_TITLES.copy()
55
+ if titles:
56
+ self.titles.update(**titles)
57
+
58
+ self.template_plugins: list[str] = DEFAULT_PLUGINS.copy()
59
+ if template_plugins:
60
+ self.template_plugins.extend(template_plugins)
61
+
62
+ def render(self, context: Context, mode: ModeType = "html") -> str:
63
+ """
64
+ Renders the title based on given context and current action.
65
+
66
+ If mode == "plain", the output will be stripped of HTML tags.
67
+
68
+ Make sure that needed context variables are in context and needed plugins are loaded.
69
+
70
+ Args:
71
+ context (Context): Render context.
72
+ mode (ModeType): Rendering mode: "html" or "plain".
73
+
74
+ Returns:
75
+ (str): HTML fragment or plain text, depending on `mode`.
76
+ """
77
+ with context.update(self.get_extra_context(context)):
78
+ template_str = self.get_template_str(context)
79
+ template = Template(self.template_plugins_str + template_str)
80
+ rendered_title = template.render(context)
81
+ if mode == "plain":
82
+ return strip_tags(rendered_title)
83
+ return rendered_title
84
+
85
+ def get_template_str(self, context: Context) -> str:
86
+ """
87
+ Determine the template string for the current action.
88
+
89
+ Args:
90
+ context (Context): Render context.
91
+
92
+ Returns:
93
+ str: The template string for the current action, or an empty string if not found.
94
+ """
95
+ action = context.get("view_action", "list")
96
+
97
+ template_str = self.titles.get(action)
98
+ if template_str:
99
+ return template_str
100
+
101
+ detail = context.get("detail", False)
102
+ if detail:
103
+ return self.titles.get("detail", "")
104
+
105
+ return ""
106
+
107
+ @property
108
+ def template_plugins_str(self) -> str:
109
+ """
110
+ Return a concatenated string of Django {% load ... %} tags for all template plugins.
111
+
112
+ Returns:
113
+ str: String containing {% load ... %} tags for the required template libraries.
114
+ """
115
+ return "".join(f"{{% load {plugin_name} %}}" for plugin_name in self.template_plugins)
116
+
117
+ def get_extra_context(self, context: Context) -> dict:
118
+ """
119
+ Provide additional data to include in the rendering context, based on the configuration of this component.
120
+
121
+ Args:
122
+ context (Context): The current template context.
123
+
124
+ Returns:
125
+ (dict): Additional context data.
126
+ """
127
+ return {}
nautobot/core/ui/utils.py CHANGED
@@ -1,3 +1,6 @@
1
+ from typing import Optional
2
+
3
+ from django.db.models import Model
1
4
  from django.template import Context
2
5
  from django.template.loader import get_template
3
6
 
@@ -34,3 +37,25 @@ def render_component_template(template_path: str, context: Context, **kwargs) ->
34
37
  """
35
38
  with context.update(kwargs):
36
39
  return get_template(template_path).render(flatten_context(context))
40
+
41
+
42
+ def get_absolute_url(value: Optional[Model]) -> str:
43
+ """
44
+ Function to retrieve just absolute url to the given model instance.
45
+
46
+ Args:
47
+ value (Optional[django.db.models.Model]): Instance of a Django model or None.
48
+
49
+ Returns:
50
+ (str): url to the object if it defines get_absolute_url(), empty string otherwise.
51
+ """
52
+ if value is None:
53
+ return ""
54
+
55
+ if hasattr(value, "get_absolute_url"):
56
+ try:
57
+ return value.get_absolute_url()
58
+ except AttributeError:
59
+ return ""
60
+
61
+ return ""
@@ -21,7 +21,7 @@ def check_for_duplicates_with_natural_key_fields_in_migration(model_class, natur
21
21
  if duplicate_records.exists():
22
22
  if len(natural_key_fields) > 1:
23
23
  print(
24
- f" Duplicate {model_class.__name__} attributes '{*natural_key_fields,}' detected: {list(duplicate_records.values_list(*natural_key_fields))}",
24
+ f" Duplicate {model_class.__name__} attributes '{(*natural_key_fields,)}' detected: {list(duplicate_records.values_list(*natural_key_fields))}",
25
25
  file=sys.stderr,
26
26
  )
27
27
  else:
@@ -70,7 +70,7 @@ class HomeView(AccessMixin, TemplateView):
70
70
  context[key] = data
71
71
 
72
72
  # Create standalone template
73
- path = f'{details["template_path"]}{details["custom_template"]}'
73
+ path = f"{details['template_path']}{details['custom_template']}"
74
74
  if os.path.isfile(path):
75
75
  with open(path, "r") as f:
76
76
  html = f.read()
@@ -41,6 +41,8 @@ from nautobot.core.forms import (
41
41
  restrict_form_fields,
42
42
  )
43
43
  from nautobot.core.jobs import BulkDeleteObjects, BulkEditObjects
44
+ from nautobot.core.ui.breadcrumbs import Breadcrumbs
45
+ from nautobot.core.ui.titles import Titles
44
46
  from nautobot.core.utils import filtering, lookup, permissions
45
47
  from nautobot.core.utils.requests import get_filterable_params_from_filter_params, normalize_querydict
46
48
  from nautobot.core.views.renderers import NautobotHTMLRenderer
@@ -242,6 +244,22 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
242
244
  # custom view attributes used for permission checks and handling
243
245
  custom_view_base_action = None
244
246
  custom_view_additional_permissions = None
247
+ view_titles = None
248
+ breadcrumbs = None
249
+
250
+ def get_view_titles(self):
251
+ return self.instantiate_if_needed(self.view_titles, Titles)
252
+
253
+ def get_breadcrumbs(self):
254
+ return self.instantiate_if_needed(self.breadcrumbs, Breadcrumbs)
255
+
256
+ @staticmethod
257
+ def instantiate_if_needed(attr, default_cls):
258
+ if attr is None:
259
+ return default_cls()
260
+ if isinstance(attr, type):
261
+ return attr()
262
+ return attr
245
263
 
246
264
  def get_permissions_for_model(self, model, actions):
247
265
  """
@@ -868,7 +886,7 @@ class ObjectEditViewMixin(NautobotViewSetMixin, mixins.CreateModelMixin, mixins.
868
886
  if hasattr(form, "save_note") and callable(form.save_note):
869
887
  form.save_note(instance=obj, user=request.user)
870
888
 
871
- msg = f'{"Created" if object_created else "Modified"} {queryset.model._meta.verbose_name}'
889
+ msg = f"{'Created' if object_created else 'Modified'} {queryset.model._meta.verbose_name}"
872
890
  self.logger.info(f"{msg} {obj} (PK: {obj.pk})")
873
891
  try:
874
892
  msg = format_html(
@@ -1142,6 +1160,9 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, Bu
1142
1160
  f"No {queryset.model._meta.verbose_name_plural} were selected for deletion.",
1143
1161
  )
1144
1162
  return redirect(self.get_return_url(request))
1163
+ # Hide actions column in the table for bulk destroy view
1164
+ if "actions" in table.columns:
1165
+ table.columns.hide("actions")
1145
1166
 
1146
1167
  data.update(
1147
1168
  {
@@ -1338,6 +1359,10 @@ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, Bulk
1338
1359
  f"No {queryset.model._meta.verbose_name_plural} were selected to update.",
1339
1360
  )
1340
1361
  return redirect(self.get_return_url(request))
1362
+
1363
+ # Hide actions column in the table for bulk update view
1364
+ if "actions" in table.columns:
1365
+ table.columns.hide("actions")
1341
1366
  data.update(
1342
1367
  {
1343
1368
  "table": table,
@@ -228,7 +228,7 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
228
228
  if view.filterset is not None:
229
229
  filterset_filters = view.filterset.filters
230
230
  else:
231
- filterset_filters = view.filterset.get_filters()
231
+ filterset_filters = view.filterset_class.get_filters()
232
232
  display_filter_params = [
233
233
  check_filter_for_display(filterset_filters, field_name, values)
234
234
  for field_name, values in view.filter_params.items()
@@ -279,6 +279,7 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
279
279
 
280
280
  context = {
281
281
  "content_type": content_type,
282
+ "model": model,
282
283
  "form": form,
283
284
  "filter_form": filter_form,
284
285
  "dynamic_filter_form": self.get_dynamic_filter_form(view, request, filterset_class=view.filterset_class),
@@ -294,7 +295,13 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
294
295
  "table_config_form": TableConfigForm(table=table) if table else None,
295
296
  "verbose_name": queryset.model._meta.verbose_name,
296
297
  "verbose_name_plural": queryset.model._meta.verbose_name_plural,
298
+ "view_action": view.action,
299
+ "detail": False,
297
300
  }
301
+
302
+ self._set_context_from_method(view, "get_view_titles", context, "view_titles")
303
+ self._set_context_from_method(view, "get_breadcrumbs", context, "breadcrumbs")
304
+
298
305
  if view.detail:
299
306
  # If we are in a retrieve related detail view (retrieve and custom actions).
300
307
  try:
@@ -316,7 +323,6 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
316
323
  new_changes_not_applied = view_changes_not_saved(request, view, self.saved_view)
317
324
  context.update(
318
325
  {
319
- "model": model,
320
326
  "current_saved_view": self.saved_view,
321
327
  "new_changes_not_applied": new_changes_not_applied,
322
328
  "action_buttons": valid_actions,
@@ -364,3 +370,15 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
364
370
  self.template = data.get("template", view.get_template_name())
365
371
 
366
372
  return super().render(data, accepted_media_type=accepted_media_type, renderer_context=renderer_context)
373
+
374
+ @staticmethod
375
+ def _set_context_from_method(
376
+ view,
377
+ view_function,
378
+ context,
379
+ context_key,
380
+ ):
381
+ try:
382
+ context[context_key] = getattr(view, view_function)()
383
+ except AttributeError:
384
+ context[context_key] = None
@@ -134,13 +134,13 @@ def get_csv_form_fields_from_serializer_class(serializer_class):
134
134
  "help_text": cf_form_field.help_text,
135
135
  }
136
136
  if cf.type == CustomFieldTypeChoices.TYPE_BOOLEAN:
137
- field_info["format"] = mark_safe("<code>true</code> or <code>false</code>") # noqa: S308
137
+ field_info["format"] = mark_safe("<code>true</code> or <code>false</code>")
138
138
  elif cf.type == CustomFieldTypeChoices.TYPE_DATE:
139
- field_info["format"] = mark_safe("<code>YYYY-MM-DD</code>") # noqa: S308
139
+ field_info["format"] = mark_safe("<code>YYYY-MM-DD</code>")
140
140
  elif cf.type == CustomFieldTypeChoices.TYPE_SELECT:
141
141
  field_info["choices"] = {value: value for value in cf.choices}
142
142
  elif cf.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
143
- field_info["format"] = mark_safe('<code>"value,value"</code>') # noqa: S308
143
+ field_info["format"] = mark_safe('<code>"value,value"</code>')
144
144
  field_info["choices"] = {value: value for value in cf.choices}
145
145
  fields.append(field_info)
146
146
  continue
@@ -153,29 +153,29 @@ def get_csv_form_fields_from_serializer_class(serializer_class):
153
153
  "help_text": field.help_text,
154
154
  }
155
155
  if isinstance(field, serializers.BooleanField):
156
- field_info["format"] = mark_safe("<code>true</code> or <code>false</code>") # noqa: S308
156
+ field_info["format"] = mark_safe("<code>true</code> or <code>false</code>")
157
157
  elif isinstance(field, serializers.DateField):
158
- field_info["format"] = mark_safe("<code>YYYY-MM-DD</code>") # noqa: S308
158
+ field_info["format"] = mark_safe("<code>YYYY-MM-DD</code>")
159
159
  elif isinstance(field, TimeZoneSerializerField):
160
- field_info["format"] = mark_safe( # noqa: S308
160
+ field_info["format"] = mark_safe(
161
161
  '<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">available options</a>'
162
162
  )
163
163
  elif isinstance(field, serializers.ManyRelatedField):
164
164
  if field.field_name == "tags":
165
- field_info["format"] = mark_safe('<code>"name,name"</code> or <code>"UUID,UUID"</code>') # noqa: S308
165
+ field_info["format"] = mark_safe('<code>"name,name"</code> or <code>"UUID,UUID"</code>')
166
166
  elif isinstance(field.child_relation, ContentTypeField):
167
- field_info["format"] = mark_safe('<code>"app_label.model,app_label.model"</code>') # noqa: S308
167
+ field_info["format"] = mark_safe('<code>"app_label.model,app_label.model"</code>')
168
168
  else:
169
169
  field_info["foreign_key"] = field.child_relation.queryset.model._meta.label_lower
170
- field_info["format"] = mark_safe('<code>"UUID,UUID"</code> or combination of fields') # noqa: S308
170
+ field_info["format"] = mark_safe('<code>"UUID,UUID"</code> or combination of fields')
171
171
  elif isinstance(field, serializers.RelatedField):
172
172
  if isinstance(field, ContentTypeField):
173
- field_info["format"] = mark_safe("<code>app_label.model</code>") # noqa: S308
173
+ field_info["format"] = mark_safe("<code>app_label.model</code>")
174
174
  else:
175
175
  field_info["foreign_key"] = field.queryset.model._meta.label_lower
176
- field_info["format"] = mark_safe("<code>UUID</code> or combination of fields") # noqa: S308
176
+ field_info["format"] = mark_safe("<code>UUID</code> or combination of fields")
177
177
  elif isinstance(field, (serializers.ListField, serializers.MultipleChoiceField)):
178
- field_info["format"] = mark_safe('<code>"value,value"</code>') # noqa: S308
178
+ field_info["format"] = mark_safe('<code>"value,value"</code>')
179
179
  elif isinstance(field, (serializers.DictField, serializers.JSONField)):
180
180
  pass # Not trivial to specify a format as it could be a JSON dict or a comma-separated string
181
181
 
@@ -348,6 +348,7 @@ def common_detail_view_context(request, instance):
348
348
  created_by, last_updated_by = get_created_and_last_updated_usernames_for_model(instance)
349
349
  context["created_by"] = created_by
350
350
  context["last_updated_by"] = last_updated_by
351
+ context["detail"] = True
351
352
 
352
353
  if getattr(instance, "is_contact_associable_model", False):
353
354
  paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
@@ -35,11 +35,14 @@ from nautobot.dcim.choices import (
35
35
  InterfaceRedundancyGroupProtocolChoices,
36
36
  InterfaceTypeChoices,
37
37
  PortTypeChoices,
38
+ PowerFeedBreakerPoleChoices,
38
39
  PowerFeedPhaseChoices,
39
40
  PowerFeedSupplyChoices,
40
41
  PowerFeedTypeChoices,
41
42
  PowerOutletFeedLegChoices,
42
43
  PowerOutletTypeChoices,
44
+ PowerPanelTypeChoices,
45
+ PowerPathChoices,
43
46
  PowerPortTypeChoices,
44
47
  RackDimensionUnitChoices,
45
48
  RackElevationDetailRenderChoices,
@@ -971,6 +974,8 @@ class VirtualChassisSerializer(TaggedModelSerializerMixin, NautobotModelSerializ
971
974
 
972
975
 
973
976
  class PowerPanelSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
977
+ panel_type = ChoiceField(choices=PowerPanelTypeChoices, allow_blank=True, required=False)
978
+ power_path = ChoiceField(choices=PowerPathChoices, allow_blank=True, required=False)
974
979
  power_feed_count = serializers.IntegerField(read_only=True)
975
980
 
976
981
  class Meta:
@@ -985,8 +990,12 @@ class PowerFeedSerializer(
985
990
  NautobotModelSerializer,
986
991
  ):
987
992
  type = ChoiceField(choices=PowerFeedTypeChoices, default=PowerFeedTypeChoices.TYPE_PRIMARY)
993
+ power_path = ChoiceField(choices=PowerPathChoices, allow_blank=True, required=False)
988
994
  supply = ChoiceField(choices=PowerFeedSupplyChoices, default=PowerFeedSupplyChoices.SUPPLY_AC)
989
995
  phase = ChoiceField(choices=PowerFeedPhaseChoices, default=PowerFeedPhaseChoices.PHASE_SINGLE)
996
+ breaker_pole_count = ChoiceField(
997
+ choices=PowerFeedBreakerPoleChoices, allow_blank=True, allow_null=True, required=False
998
+ )
990
999
 
991
1000
  class Meta:
992
1001
  model = PowerFeed
nautobot/dcim/choices.py CHANGED
@@ -1371,6 +1371,37 @@ class CableLengthUnitChoices(ChoiceSet):
1371
1371
  )
1372
1372
 
1373
1373
 
1374
+ #
1375
+ # Power Panels
1376
+ #
1377
+
1378
+
1379
+ class PowerPanelTypeChoices(ChoiceSet):
1380
+ TYPE_UTILITY = "utility"
1381
+ TYPE_GENERATOR = "generator"
1382
+ TYPE_SWITCHGEAR = "switchgear"
1383
+ TYPE_MDP = "mdp"
1384
+ TYPE_UPS = "ups"
1385
+ TYPE_TRANSFER_SWITCH = "transfer-switch"
1386
+ TYPE_PDU = "pdu"
1387
+ TYPE_PANELBOARD = "panelboard"
1388
+ TYPE_MLC = "mlc"
1389
+ TYPE_RPP = "rpp"
1390
+
1391
+ CHOICES = (
1392
+ (TYPE_UTILITY, "Utility"),
1393
+ (TYPE_GENERATOR, "Generator"),
1394
+ (TYPE_SWITCHGEAR, "Switchgear"),
1395
+ (TYPE_MDP, "Main Distribution Panel (MDP)"),
1396
+ (TYPE_UPS, "Uninterruptible Power Supply (UPS)"),
1397
+ (TYPE_TRANSFER_SWITCH, "Transfer Switch (TS)"),
1398
+ (TYPE_PDU, "Power Distribution Unit (PDU)"),
1399
+ (TYPE_PANELBOARD, "Panelboard"),
1400
+ (TYPE_MLC, "Mini Load Center (MLC)"),
1401
+ (TYPE_RPP, "Remote Power Panel (RPP)"),
1402
+ )
1403
+
1404
+
1374
1405
  #
1375
1406
  # PowerFeeds
1376
1407
  #
@@ -1405,6 +1436,16 @@ class PowerFeedTypeChoices(ChoiceSet):
1405
1436
  }
1406
1437
 
1407
1438
 
1439
+ class PowerPathChoices(ChoiceSet):
1440
+ PATH_A = "a"
1441
+ PATH_B = "b"
1442
+
1443
+ CHOICES = (
1444
+ (PATH_A, "Path A"),
1445
+ (PATH_B, "Path B"),
1446
+ )
1447
+
1448
+
1408
1449
  class PowerFeedSupplyChoices(ChoiceSet):
1409
1450
  SUPPLY_AC = "ac"
1410
1451
  SUPPLY_DC = "dc"
@@ -1425,6 +1466,18 @@ class PowerFeedPhaseChoices(ChoiceSet):
1425
1466
  )
1426
1467
 
1427
1468
 
1469
+ class PowerFeedBreakerPoleChoices(ChoiceSet):
1470
+ POLE_1 = 1
1471
+ POLE_2 = 2
1472
+ POLE_3 = 3
1473
+
1474
+ CHOICES = [
1475
+ (POLE_1, "1-Pole"),
1476
+ (POLE_2, "2-Pole"),
1477
+ (POLE_3, "3-Pole"),
1478
+ ]
1479
+
1480
+
1428
1481
  #
1429
1482
  # Device Redundancy Groups
1430
1483
  #
@@ -1639,10 +1639,14 @@ class PowerPanelFilterSet(LocatableModelFilterSetMixin, NautobotFilterSet):
1639
1639
  field_name="power_feeds",
1640
1640
  label="Has power feeds",
1641
1641
  )
1642
+ has_feeders = RelatedMembershipBooleanFilter(
1643
+ field_name="feeders",
1644
+ label="Has feeders",
1645
+ )
1642
1646
 
1643
1647
  class Meta:
1644
1648
  model = PowerPanel
1645
- fields = ["id", "name", "tags"]
1649
+ fields = ["id", "name", "panel_type", "power_path", "tags"]
1646
1650
 
1647
1651
 
1648
1652
  class PowerFeedFilterSet(
@@ -1652,8 +1656,7 @@ class PowerFeedFilterSet(
1652
1656
  StatusModelFilterSetMixin,
1653
1657
  ):
1654
1658
  q = SearchFilter(filter_predicates={"name": "icontains", "comments": "icontains"})
1655
- # TODO: Why is this not using TreeNodeMultiple...
1656
- location = NaturalKeyOrPKMultipleChoiceFilter(
1659
+ location = TreeNodeMultipleChoiceFilter(
1657
1660
  prefers_id=True,
1658
1661
  field_name="power_panel__location",
1659
1662
  queryset=Location.objects.all(),
@@ -1667,6 +1670,12 @@ class PowerFeedFilterSet(
1667
1670
  to_field_name="name",
1668
1671
  label="Power panel (name or ID)",
1669
1672
  )
1673
+ destination_panel = NaturalKeyOrPKMultipleChoiceFilter(
1674
+ prefers_id=True,
1675
+ queryset=PowerPanel.objects.all(),
1676
+ to_field_name="name",
1677
+ label="Destination panel (name or ID)",
1678
+ )
1670
1679
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1671
1680
  rack = NaturalKeyOrPKMultipleChoiceFilter(
1672
1681
  prefers_id=True,
@@ -1682,11 +1691,14 @@ class PowerFeedFilterSet(
1682
1691
  "name",
1683
1692
  "status",
1684
1693
  "type",
1694
+ "power_path",
1685
1695
  "supply",
1686
1696
  "phase",
1687
1697
  "voltage",
1688
1698
  "amperage",
1689
1699
  "max_utilization",
1700
+ "breaker_position",
1701
+ "breaker_pole_count",
1690
1702
  "comments",
1691
1703
  "available_power",
1692
1704
  "tags",