nautobot 2.4.17__py3-none-any.whl → 2.4.19__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 (627) hide show
  1. nautobot/apps/ui.py +6 -0
  2. nautobot/apps/views.py +2 -0
  3. nautobot/circuits/tables.py +1 -1
  4. nautobot/circuits/templates/circuits/circuit_create.html +7 -7
  5. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -5
  6. nautobot/circuits/templates/circuits/circuittermination_create.html +26 -26
  7. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -8
  8. nautobot/circuits/templates/circuits/inc/circuit_termination.html +20 -20
  9. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +3 -3
  10. nautobot/circuits/templates/circuits/inc/circuit_termination_speed_fragment.html +9 -0
  11. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +1 -3
  12. nautobot/circuits/tests/integration/test_circuit.py +2 -2
  13. nautobot/circuits/views.py +49 -15
  14. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +1 -4
  15. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
  16. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +1 -3
  17. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +1 -5
  18. nautobot/cloud/views.py +45 -0
  19. nautobot/core/filters.py +2 -2
  20. nautobot/core/graphql/generators.py +5 -2
  21. nautobot/core/jobs/bulk_actions.py +48 -85
  22. nautobot/core/models/querysets.py +2 -1
  23. nautobot/core/settings.py +1 -0
  24. nautobot/core/settings.yaml +9 -0
  25. nautobot/core/tables.py +21 -23
  26. nautobot/core/templates/40x.html +15 -15
  27. nautobot/core/templates/500.html +21 -21
  28. nautobot/core/templates/admin/app_index.html +8 -8
  29. nautobot/core/templates/admin/base.html +104 -104
  30. nautobot/core/templates/admin/change_form.html +65 -65
  31. nautobot/core/templates/admin/change_list.html +60 -60
  32. nautobot/core/templates/admin/change_list_results.html +39 -39
  33. nautobot/core/templates/admin/config/config.html +47 -47
  34. nautobot/core/templates/admin/delete_confirmation.html +47 -47
  35. nautobot/core/templates/admin/edit_inline/stacked.html +124 -124
  36. nautobot/core/templates/admin/edit_inline/tabular.html +60 -60
  37. nautobot/core/templates/admin/includes/fieldset.html +4 -4
  38. nautobot/core/templates/admin/index.html +60 -60
  39. nautobot/core/templates/admin/prepopulated_fields_js.html +18 -18
  40. nautobot/core/templates/admin/submit_line.html +4 -4
  41. nautobot/core/templates/base_django.html +46 -46
  42. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +8 -8
  43. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +8 -8
  44. nautobot/core/templates/buttons/export.html +3 -3
  45. nautobot/core/templates/components/breadcrumbs.html +19 -0
  46. nautobot/core/templates/components/button/default.html +3 -3
  47. nautobot/core/templates/components/button/dropdown.html +7 -7
  48. nautobot/core/templates/components/button/formbutton.html +4 -4
  49. nautobot/core/templates/components/panel/body_content_data_table.html +1 -1
  50. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +3 -0
  51. nautobot/core/templates/components/panel/footer_content_table.html +3 -1
  52. nautobot/core/templates/components/panel/header_extra_content_table.html +10 -1
  53. nautobot/core/templates/components/tab/content_wrapper.html +1 -1
  54. nautobot/core/templates/components/tab/label_wrapper.html +1 -1
  55. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +10 -3
  56. nautobot/core/templates/generic/object_bulk_add_component.html +40 -40
  57. nautobot/core/templates/generic/object_bulk_create.html +3 -3
  58. nautobot/core/templates/generic/object_bulk_destroy.html +6 -6
  59. nautobot/core/templates/generic/object_bulk_update.html +52 -52
  60. nautobot/core/templates/generic/object_changelog.html +0 -2
  61. nautobot/core/templates/generic/object_import.html +33 -33
  62. nautobot/core/templates/generic/object_list.html +271 -268
  63. nautobot/core/templates/generic/object_notes.html +0 -2
  64. nautobot/core/templates/generic/object_retrieve.html +264 -257
  65. nautobot/core/templates/graphene/graphiql.html +127 -127
  66. nautobot/core/templates/home.html +62 -62
  67. nautobot/core/templates/inc/computed_fields/panel_data.html +13 -13
  68. nautobot/core/templates/inc/created_updated.html +8 -8
  69. nautobot/core/templates/inc/custom_fields/panel_data.html +13 -13
  70. nautobot/core/templates/inc/dynamic_groups_panel.html +11 -11
  71. nautobot/core/templates/inc/footer.html +19 -19
  72. nautobot/core/templates/inc/javascript.html +1 -1
  73. nautobot/core/templates/inc/media.html +46 -46
  74. nautobot/core/templates/inc/nav_menu.html +1 -1
  75. nautobot/core/templates/inc/relationships_table_rows.html +22 -22
  76. nautobot/core/templates/inc/tenant_table_row.html +1 -1
  77. nautobot/core/templates/login.html +77 -77
  78. nautobot/core/templates/media_failure.html +38 -38
  79. nautobot/core/templates/panel_table.html +1 -1
  80. nautobot/core/templates/rest_framework/api.html +3 -3
  81. nautobot/core/templates/search.html +1 -1
  82. nautobot/core/templates/swagger_ui.html +9 -9
  83. nautobot/core/templates/utilities/confirmation_form.html +18 -18
  84. nautobot/core/templates/utilities/render_field.html +1 -1
  85. nautobot/core/templates/utilities/render_jinja2.html +43 -43
  86. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +56 -56
  87. nautobot/core/templates/utilities/templatetags/utilization_graph.html +1 -1
  88. nautobot/core/templates/utilities/theme_preview.html +799 -799
  89. nautobot/core/templates/utilities/worker_status.html +122 -122
  90. nautobot/core/templates/widgets/clearable_file.html +3 -3
  91. nautobot/core/templates/widgets/sluginput.html +1 -1
  92. nautobot/core/templatetags/buttons.py +8 -2
  93. nautobot/core/templatetags/helpers.py +24 -0
  94. nautobot/core/templatetags/ui_framework.py +40 -5
  95. nautobot/core/testing/filters.py +37 -21
  96. nautobot/core/testing/integration.py +7 -4
  97. nautobot/core/testing/views.py +49 -5
  98. nautobot/core/tests/test_breadcrumbs.py +78 -4
  99. nautobot/core/tests/test_commands.py +7 -4
  100. nautobot/core/tests/test_graphql.py +20 -5
  101. nautobot/core/tests/test_jobs.py +34 -21
  102. nautobot/core/tests/test_tables.py +43 -6
  103. nautobot/core/tests/test_templatetags_ui_framework.py +146 -0
  104. nautobot/core/tests/test_titles.py +2 -2
  105. nautobot/core/tests/test_ui.py +188 -1
  106. nautobot/core/tests/test_utils.py +35 -0
  107. nautobot/core/tests/test_views.py +45 -0
  108. nautobot/core/tests/test_views_generic.py +43 -0
  109. nautobot/core/tests/test_views_utils.py +239 -5
  110. nautobot/core/ui/breadcrumbs.py +220 -28
  111. nautobot/core/ui/bulk_buttons.py +8 -0
  112. nautobot/core/ui/object_detail.py +181 -60
  113. nautobot/core/ui/titles.py +10 -5
  114. nautobot/core/utils/requests.py +27 -2
  115. nautobot/core/views/__init__.py +24 -3
  116. nautobot/core/views/generic.py +70 -35
  117. nautobot/core/views/mixins.py +226 -122
  118. nautobot/core/views/utils.py +270 -1
  119. nautobot/dcim/api/serializers.py +8 -2
  120. nautobot/dcim/constants.py +1 -0
  121. nautobot/dcim/factory.py +4 -3
  122. nautobot/dcim/filters/mixins.py +1 -2
  123. nautobot/dcim/forms.py +5 -1
  124. nautobot/dcim/migrations/0074_alter_rack_u_height.py +21 -0
  125. nautobot/dcim/models/devices.py +30 -1
  126. nautobot/dcim/models/racks.py +2 -2
  127. nautobot/dcim/tables/__init__.py +2 -0
  128. nautobot/dcim/tables/devices.py +24 -0
  129. nautobot/dcim/tables/power.py +2 -2
  130. nautobot/dcim/templates/dcim/cable.html +53 -53
  131. nautobot/dcim/templates/dcim/cable_connect.html +182 -182
  132. nautobot/dcim/templates/dcim/cable_trace.html +1 -1
  133. nautobot/dcim/templates/dcim/console_port_connection_list.html +5 -5
  134. nautobot/dcim/templates/dcim/consoleport.html +86 -86
  135. nautobot/dcim/templates/dcim/consoleserverport.html +86 -86
  136. nautobot/dcim/templates/dcim/controller_create.html +34 -34
  137. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -68
  138. nautobot/dcim/templates/dcim/device/base.html +1 -114
  139. nautobot/dcim/templates/dcim/device/config.html +17 -17
  140. nautobot/dcim/templates/dcim/device/consoleports.html +1 -52
  141. nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -52
  142. nautobot/dcim/templates/dcim/device/devicebays.html +1 -48
  143. nautobot/dcim/templates/dcim/device/frontports.html +1 -52
  144. nautobot/dcim/templates/dcim/device/interfaces.html +1 -56
  145. nautobot/dcim/templates/dcim/device/inventory.html +1 -48
  146. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +64 -64
  147. nautobot/dcim/templates/dcim/device/modulebays.html +1 -48
  148. nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -52
  149. nautobot/dcim/templates/dcim/device/powerports.html +1 -52
  150. nautobot/dcim/templates/dcim/device/rearports.html +1 -52
  151. nautobot/dcim/templates/dcim/device/status.html +66 -66
  152. nautobot/dcim/templates/dcim/device/wireless.html +1 -72
  153. nautobot/dcim/templates/dcim/device.html +4 -422
  154. nautobot/dcim/templates/dcim/device_component.html +0 -19
  155. nautobot/dcim/templates/dcim/device_component_add.html +25 -25
  156. nautobot/dcim/templates/dcim/device_create.html +229 -0
  157. nautobot/dcim/templates/dcim/device_edit.html +2 -227
  158. nautobot/dcim/templates/dcim/devicebay.html +41 -41
  159. nautobot/dcim/templates/dcim/devicebay_populate.html +32 -32
  160. nautobot/dcim/templates/dcim/devicetype_component_add.html +28 -28
  161. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -3
  162. nautobot/dcim/templates/dcim/frontport.html +84 -84
  163. nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
  164. nautobot/dcim/templates/dcim/inc/device_interface_filter.html +8 -0
  165. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +1 -15
  166. nautobot/dcim/templates/dcim/inc/location_hierarchy.html +22 -22
  167. nautobot/dcim/templates/dcim/interface.html +206 -206
  168. nautobot/dcim/templates/dcim/interface_connection_list.html +5 -5
  169. nautobot/dcim/templates/dcim/interfaceredundancygroupassociation_create.html +6 -6
  170. nautobot/dcim/templates/dcim/inventoryitem.html +44 -44
  171. nautobot/dcim/templates/dcim/inventoryitem_add.html +32 -32
  172. nautobot/dcim/templates/dcim/inventoryitem_edit.html +22 -22
  173. nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +46 -46
  174. nautobot/dcim/templates/dcim/location_retrieve.html +1 -7
  175. nautobot/dcim/templates/dcim/locationtype.html +1 -6
  176. nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -7
  177. nautobot/dcim/templates/dcim/module/base.html +85 -85
  178. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  179. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  180. nautobot/dcim/templates/dcim/module_retrieve.html +52 -52
  181. nautobot/dcim/templates/dcim/module_update.html +61 -61
  182. nautobot/dcim/templates/dcim/modulebay_destroy.html +1 -1
  183. nautobot/dcim/templates/dcim/modulebay_retrieve.html +83 -99
  184. nautobot/dcim/templates/dcim/modulebay_update.html +33 -33
  185. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  186. nautobot/dcim/templates/dcim/moduletype_retrieve.html +140 -144
  187. nautobot/dcim/templates/dcim/platform_create.html +38 -38
  188. nautobot/dcim/templates/dcim/power_port_connection_list.html +5 -5
  189. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -8
  190. nautobot/dcim/templates/dcim/poweroutlet.html +85 -85
  191. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +1 -8
  192. nautobot/dcim/templates/dcim/powerport.html +91 -91
  193. nautobot/dcim/templates/dcim/rack_elevation_list.html +18 -18
  194. nautobot/dcim/templates/dcim/rack_retrieve.html +264 -274
  195. nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -3
  196. nautobot/dcim/templates/dcim/rearport.html +78 -78
  197. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +1 -50
  198. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -5
  199. nautobot/dcim/tests/integration/test_device_bulk_operations.py +3 -2
  200. nautobot/dcim/tests/integration/test_location_bulk_operations.py +6 -2
  201. nautobot/dcim/tests/test_api.py +33 -1
  202. nautobot/dcim/tests/test_views.py +189 -4
  203. nautobot/dcim/ui.py +29 -0
  204. nautobot/dcim/urls.py +1 -109
  205. nautobot/dcim/utils.py +30 -0
  206. nautobot/dcim/views.py +1149 -550
  207. nautobot/extras/filters/mixins.py +1 -1
  208. nautobot/extras/forms/forms.py +15 -0
  209. nautobot/extras/models/groups.py +10 -1
  210. nautobot/extras/models/jobs.py +2 -2
  211. nautobot/extras/plugins/views.py +18 -5
  212. nautobot/extras/tables.py +24 -2
  213. nautobot/extras/templates/extras/computedfield_edit.html +4 -4
  214. nautobot/extras/templates/extras/configcontext_update.html +1 -1
  215. nautobot/extras/templates/extras/configcontextschema_retrieve.html +32 -32
  216. nautobot/extras/templates/extras/customfield_retrieve.html +1 -128
  217. nautobot/extras/templates/extras/customfield_update.html +23 -23
  218. nautobot/extras/templates/extras/dynamicgroup.html +2 -99
  219. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -199
  220. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +99 -0
  221. nautobot/extras/templates/extras/dynamicgroup_update.html +199 -0
  222. nautobot/extras/templates/extras/gitrepository.html +2 -82
  223. nautobot/extras/templates/extras/gitrepository_list.html +10 -10
  224. nautobot/extras/templates/extras/gitrepository_object_edit.html +2 -13
  225. nautobot/extras/templates/extras/gitrepository_retrieve.html +82 -0
  226. nautobot/extras/templates/extras/gitrepository_update.html +13 -0
  227. nautobot/extras/templates/extras/graphqlquery_retrieve.html +73 -73
  228. nautobot/extras/templates/extras/inc/configcontext_format.html +2 -2
  229. nautobot/extras/templates/extras/inc/job_table.html +10 -10
  230. nautobot/extras/templates/extras/inc/jobresult.html +21 -21
  231. nautobot/extras/templates/extras/inc/jobresult_js.html +6 -6
  232. nautobot/extras/templates/extras/inc/tags_panel.html +10 -10
  233. nautobot/extras/templates/extras/job.html +64 -64
  234. nautobot/extras/templates/extras/job_approval_request.html +9 -9
  235. nautobot/extras/templates/extras/job_bulk_edit.html +13 -13
  236. nautobot/extras/templates/extras/job_edit.html +45 -45
  237. nautobot/extras/templates/extras/job_list.html +4 -4
  238. nautobot/extras/templates/extras/jobresult_retrieve.html +0 -25
  239. nautobot/extras/templates/extras/marketplace.html +101 -101
  240. nautobot/extras/templates/extras/metadatatype_create.html +20 -20
  241. nautobot/extras/templates/extras/note_retrieve.html +0 -52
  242. nautobot/extras/templates/extras/object_assign_contact_or_team.html +18 -18
  243. nautobot/extras/templates/extras/object_configcontext.html +1 -3
  244. nautobot/extras/templates/extras/objectchange.html +2 -165
  245. nautobot/extras/templates/extras/objectchange_retrieve.html +165 -0
  246. nautobot/extras/templates/extras/plugin_detail.html +44 -48
  247. nautobot/extras/templates/extras/plugins_list.html +9 -11
  248. nautobot/extras/templates/extras/plugins_tiles.html +26 -26
  249. nautobot/extras/templates/extras/relationship_edit.html +4 -4
  250. nautobot/extras/templates/extras/role_retrieve.html +13 -13
  251. nautobot/extras/templates/extras/scheduled_jobs_approval_queue_list.html +21 -21
  252. nautobot/extras/templates/extras/scheduledjob.html +128 -128
  253. nautobot/extras/templates/extras/secret_create.html +53 -53
  254. nautobot/extras/templates/extras/secretsgroup_update.html +13 -13
  255. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +3 -3
  256. nautobot/extras/templates/extras/webhook.html +79 -79
  257. nautobot/extras/tests/integration/test_relationships.py +6 -6
  258. nautobot/extras/tests/test_dynamicgroups.py +73 -18
  259. nautobot/extras/tests/test_filters.py +1 -1
  260. nautobot/extras/tests/test_jobs.py +2 -0
  261. nautobot/extras/tests/test_views.py +8 -3
  262. nautobot/extras/urls.py +3 -97
  263. nautobot/extras/views.py +524 -456
  264. nautobot/ipam/filters.py +2 -2
  265. nautobot/ipam/migrations/0053_alter_vrfdeviceassignment_options_and_more.py +20 -0
  266. nautobot/ipam/models.py +34 -0
  267. nautobot/ipam/querysets.py +3 -3
  268. nautobot/ipam/signals.py +6 -1
  269. nautobot/ipam/tables.py +3 -1
  270. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +4 -0
  271. nautobot/ipam/templates/ipam/inc/toggle_available.html +8 -8
  272. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +4 -4
  273. nautobot/ipam/templates/ipam/ipaddress.html +119 -123
  274. nautobot/ipam/templates/ipam/ipaddress_assign.html +10 -10
  275. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -1
  276. nautobot/ipam/templates/ipam/ipaddress_merge.html +180 -180
  277. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +48 -48
  278. nautobot/ipam/templates/ipam/prefix.html +2 -115
  279. nautobot/ipam/templates/ipam/prefix_create.html +34 -0
  280. nautobot/ipam/templates/ipam/prefix_edit.html +1 -34
  281. nautobot/ipam/templates/ipam/prefix_retrieve.html +3 -0
  282. nautobot/ipam/templates/ipam/service_retrieve.html +1 -6
  283. nautobot/ipam/templates/ipam/vlan_retrieve.html +1 -7
  284. nautobot/ipam/templates/ipam/vrf_edit.html +1 -1
  285. nautobot/ipam/tests/test_api.py +5 -0
  286. nautobot/ipam/tests/test_models.py +387 -0
  287. nautobot/ipam/tests/test_querysets.py +46 -0
  288. nautobot/ipam/tests/test_views.py +34 -0
  289. nautobot/ipam/ui.py +145 -0
  290. nautobot/ipam/urls.py +1 -46
  291. nautobot/ipam/utils/__init__.py +26 -0
  292. nautobot/ipam/utils/migrations.py +1 -1
  293. nautobot/ipam/views.py +234 -112
  294. nautobot/project-static/docs/404.html +11 -11
  295. nautobot/project-static/docs/apps/index.html +11 -11
  296. nautobot/project-static/docs/apps/nautobot-apps.html +11 -11
  297. nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js → bundle.f55a23d4.min.js} +2 -2
  298. nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js.map → bundle.f55a23d4.min.js.map} +2 -2
  299. nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css → main.e53b48f4.min.css} +1 -1
  300. nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css.map → main.e53b48f4.min.css.map} +1 -1
  301. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +11 -11
  302. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +11 -11
  303. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +11 -11
  304. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +11 -11
  305. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +11 -11
  306. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +11 -11
  307. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +11 -11
  308. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +11 -11
  309. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +11 -11
  310. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +11 -11
  311. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +11 -11
  312. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +11 -11
  313. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +11 -11
  314. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +11 -11
  315. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +11 -11
  316. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +11 -11
  317. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +11 -11
  318. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +11 -11
  319. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +11 -11
  320. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +83 -11
  321. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1265 -281
  322. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +11 -11
  323. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +12 -12
  324. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +452 -29
  325. nautobot/project-static/docs/development/apps/api/configuration-view.html +11 -11
  326. nautobot/project-static/docs/development/apps/api/database-backend-config.html +11 -11
  327. nautobot/project-static/docs/development/apps/api/models/django-admin.html +11 -11
  328. nautobot/project-static/docs/development/apps/api/models/global-search.html +11 -11
  329. nautobot/project-static/docs/development/apps/api/models/graphql.html +11 -11
  330. nautobot/project-static/docs/development/apps/api/models/index.html +11 -11
  331. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +12 -12
  332. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +11 -11
  333. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +11 -11
  334. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +11 -11
  335. nautobot/project-static/docs/development/apps/api/platform-features/index.html +11 -11
  336. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +11 -11
  337. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +11 -11
  338. nautobot/project-static/docs/development/apps/api/platform-features/prepopulating-data.html +11 -11
  339. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +11 -11
  340. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +11 -11
  341. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +11 -11
  342. nautobot/project-static/docs/development/apps/api/prometheus.html +11 -11
  343. nautobot/project-static/docs/development/apps/api/setup.html +11 -11
  344. nautobot/project-static/docs/development/apps/api/testing.html +11 -11
  345. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +11 -11
  346. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +11 -11
  347. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +11 -11
  348. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +11 -11
  349. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +11 -11
  350. nautobot/project-static/docs/development/apps/api/views/base-template.html +11 -11
  351. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +11 -11
  352. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +11 -11
  353. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +11 -11
  354. nautobot/project-static/docs/development/apps/api/views/index.html +11 -11
  355. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +11 -11
  356. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +11 -11
  357. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +11 -11
  358. nautobot/project-static/docs/development/apps/api/views/notes.html +11 -11
  359. nautobot/project-static/docs/development/apps/api/views/rest-api.html +11 -11
  360. nautobot/project-static/docs/development/apps/api/views/urls.html +11 -11
  361. nautobot/project-static/docs/development/apps/index.html +11 -11
  362. nautobot/project-static/docs/development/apps/migration/code-updates.html +11 -11
  363. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +11 -11
  364. nautobot/project-static/docs/development/apps/migration/from-v1.html +11 -11
  365. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +11 -11
  366. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +11 -11
  367. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +11 -11
  368. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +11 -11
  369. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +11 -11
  370. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +11 -11
  371. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +11 -11
  372. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +11 -11
  373. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +11 -11
  374. nautobot/project-static/docs/development/apps/porting-from-netbox.html +11 -11
  375. nautobot/project-static/docs/development/core/application-registry.html +11 -11
  376. nautobot/project-static/docs/development/core/best-practices.html +11 -11
  377. nautobot/project-static/docs/development/core/bootstrap-ui.html +11 -11
  378. nautobot/project-static/docs/development/core/caching.html +11 -11
  379. nautobot/project-static/docs/development/core/controllers.html +11 -11
  380. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +11 -11
  381. nautobot/project-static/docs/development/core/generic-views.html +11 -11
  382. nautobot/project-static/docs/development/core/getting-started.html +50 -63
  383. nautobot/project-static/docs/development/core/homepage.html +11 -11
  384. nautobot/project-static/docs/development/core/index.html +11 -11
  385. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +11 -11
  386. nautobot/project-static/docs/development/core/model-checklist.html +11 -11
  387. nautobot/project-static/docs/development/core/model-features.html +11 -11
  388. nautobot/project-static/docs/development/core/natural-keys.html +11 -11
  389. nautobot/project-static/docs/development/core/navigation-menu.html +11 -11
  390. nautobot/project-static/docs/development/core/release-checklist.html +11 -11
  391. nautobot/project-static/docs/development/core/role-internals.html +11 -11
  392. nautobot/project-static/docs/development/core/settings.html +11 -11
  393. nautobot/project-static/docs/development/core/style-guide.html +15 -11
  394. nautobot/project-static/docs/development/core/templates.html +11 -11
  395. nautobot/project-static/docs/development/core/testing.html +11 -11
  396. nautobot/project-static/docs/development/core/ui-component-framework.html +17 -22
  397. nautobot/project-static/docs/development/core/user-preferences.html +11 -11
  398. nautobot/project-static/docs/development/index.html +11 -11
  399. nautobot/project-static/docs/development/jobs/getting-started.html +11 -11
  400. nautobot/project-static/docs/development/jobs/index.html +11 -11
  401. nautobot/project-static/docs/development/jobs/installation.html +11 -11
  402. nautobot/project-static/docs/development/jobs/job-extensions.html +11 -11
  403. nautobot/project-static/docs/development/jobs/job-logging.html +11 -11
  404. nautobot/project-static/docs/development/jobs/job-patterns.html +11 -11
  405. nautobot/project-static/docs/development/jobs/job-structure.html +11 -11
  406. nautobot/project-static/docs/development/jobs/migration/from-v1.html +11 -11
  407. nautobot/project-static/docs/development/jobs/testing.html +11 -11
  408. nautobot/project-static/docs/index.html +11 -11
  409. nautobot/project-static/docs/objects.inv +0 -0
  410. nautobot/project-static/docs/overview/application_stack.html +11 -11
  411. nautobot/project-static/docs/overview/design_philosophy.html +11 -11
  412. nautobot/project-static/docs/release-notes/index.html +11 -11
  413. nautobot/project-static/docs/release-notes/version-1.0.html +11 -11
  414. nautobot/project-static/docs/release-notes/version-1.1.html +11 -11
  415. nautobot/project-static/docs/release-notes/version-1.2.html +11 -11
  416. nautobot/project-static/docs/release-notes/version-1.3.html +11 -11
  417. nautobot/project-static/docs/release-notes/version-1.4.html +11 -11
  418. nautobot/project-static/docs/release-notes/version-1.5.html +11 -11
  419. nautobot/project-static/docs/release-notes/version-1.6.html +11 -11
  420. nautobot/project-static/docs/release-notes/version-2.0.html +11 -11
  421. nautobot/project-static/docs/release-notes/version-2.1.html +11 -11
  422. nautobot/project-static/docs/release-notes/version-2.2.html +11 -11
  423. nautobot/project-static/docs/release-notes/version-2.3.html +11 -11
  424. nautobot/project-static/docs/release-notes/version-2.4.html +418 -11
  425. nautobot/project-static/docs/search/search_index.json +1 -1
  426. nautobot/project-static/docs/sitemap.xml +300 -300
  427. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  428. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +11 -11
  429. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +11 -11
  430. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +11 -11
  431. nautobot/project-static/docs/user-guide/administration/configuration/index.html +11 -11
  432. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +11 -11
  433. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +38 -11
  434. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +11 -11
  435. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +89 -14
  436. nautobot/project-static/docs/user-guide/administration/guides/docker.html +11 -11
  437. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +11 -11
  438. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +11 -11
  439. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +11 -11
  440. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +11 -11
  441. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +11 -11
  442. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +11 -11
  443. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +11 -11
  444. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +11 -11
  445. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +11 -11
  446. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +11 -11
  447. nautobot/project-static/docs/user-guide/administration/installation/index.html +11 -11
  448. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +11 -11
  449. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +11 -11
  450. nautobot/project-static/docs/user-guide/administration/installation/services.html +11 -11
  451. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +11 -11
  452. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +11 -11
  453. nautobot/project-static/docs/user-guide/administration/security/index.html +11 -11
  454. nautobot/project-static/docs/user-guide/administration/security/notices.html +11 -11
  455. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +11 -11
  456. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +11 -11
  457. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +11 -11
  458. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +11 -11
  459. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +11 -11
  460. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +11 -11
  461. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +11 -11
  462. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +11 -11
  463. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +11 -11
  464. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +11 -11
  465. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +11 -11
  466. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +11 -11
  467. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +11 -11
  468. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +11 -11
  469. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +11 -11
  470. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +11 -11
  471. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +11 -11
  472. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +11 -11
  473. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +11 -11
  474. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +11 -11
  475. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +11 -11
  476. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +11 -11
  477. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +11 -11
  478. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +11 -11
  479. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +11 -11
  480. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +11 -11
  481. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +11 -11
  482. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +11 -11
  483. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -11
  484. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +11 -11
  485. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +11 -11
  486. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +11 -11
  487. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +11 -11
  488. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +11 -11
  489. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +11 -11
  490. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +11 -11
  491. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +11 -11
  492. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +11 -11
  493. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +11 -11
  494. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +11 -11
  495. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +11 -11
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +11 -11
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +11 -11
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +11 -11
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +11 -11
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +11 -11
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +11 -11
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +11 -11
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +11 -11
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +11 -11
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +11 -11
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +11 -11
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +11 -11
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +11 -11
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +11 -11
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +11 -11
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +11 -11
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +11 -11
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +11 -11
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +11 -11
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +11 -11
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +11 -11
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +11 -11
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +11 -11
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +11 -11
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +11 -11
  521. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +11 -11
  522. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +11 -11
  523. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +11 -11
  524. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +11 -11
  525. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +11 -11
  526. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +11 -11
  527. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +11 -11
  528. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +11 -11
  529. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +11 -11
  530. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +11 -11
  531. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +11 -11
  532. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +11 -11
  533. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +11 -11
  534. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +11 -11
  535. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +11 -11
  536. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +11 -11
  537. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +11 -11
  538. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +11 -11
  539. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +11 -11
  540. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +11 -11
  541. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +11 -11
  542. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +11 -11
  543. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +11 -11
  544. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +11 -11
  545. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +11 -11
  546. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
  547. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +11 -11
  548. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +11 -11
  549. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +11 -11
  550. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +11 -11
  551. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +11 -11
  552. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +11 -11
  553. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +11 -11
  554. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +11 -11
  555. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -11
  556. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +11 -11
  557. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +11 -11
  558. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +11 -11
  559. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +11 -11
  560. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +11 -11
  561. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +11 -11
  562. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +11 -11
  563. nautobot/project-static/docs/user-guide/index.html +11 -11
  564. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +11 -11
  565. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +11 -11
  566. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +11 -11
  567. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +11 -11
  568. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +11 -11
  569. nautobot/project-static/docs/user-guide/platform-functionality/events.html +11 -11
  570. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +11 -11
  571. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +11 -11
  572. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +11 -11
  573. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +11 -11
  574. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +11 -11
  575. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +11 -11
  576. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +11 -11
  577. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +11 -11
  578. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +11 -11
  579. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +11 -11
  580. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +11 -11
  581. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +11 -11
  582. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +11 -11
  583. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +11 -11
  584. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +11 -11
  585. nautobot/project-static/docs/user-guide/platform-functionality/note.html +11 -11
  586. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +11 -11
  587. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +11 -11
  588. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +11 -11
  589. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +11 -11
  590. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +11 -11
  591. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +11 -11
  592. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +11 -11
  593. nautobot/project-static/docs/user-guide/platform-functionality/role.html +11 -11
  594. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +11 -11
  595. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +11 -11
  596. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +11 -11
  597. nautobot/project-static/docs/user-guide/platform-functionality/status.html +11 -11
  598. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +11 -11
  599. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +11 -11
  600. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +11 -11
  601. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +11 -11
  602. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +11 -11
  603. nautobot/project-static/img/nautobot_icon.svg +32 -34
  604. nautobot/project-static/js/table_sorting_indicator.js +0 -2
  605. nautobot/tenancy/templates/tenancy/tenant.html +1 -7
  606. nautobot/tenancy/views.py +13 -0
  607. nautobot/users/templates/users/api_tokens.html +4 -4
  608. nautobot/users/templates/users/base.html +28 -28
  609. nautobot/virtualization/templates/virtualization/cluster.html +64 -64
  610. nautobot/virtualization/templates/virtualization/inc/virtualmachine_vminterface_filter.html +8 -0
  611. nautobot/virtualization/templates/virtualization/virtualmachine_component_add.html +25 -25
  612. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +1 -251
  613. nautobot/virtualization/templates/virtualization/vminterface.html +70 -70
  614. nautobot/virtualization/urls.py +0 -12
  615. nautobot/virtualization/views.py +158 -54
  616. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +13 -13
  617. nautobot/wireless/tests/integration/test_radio_profile.py +1 -1
  618. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/METADATA +4 -4
  619. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/RECORD +623 -607
  620. nautobot/core/templates/inc/breadcrumbs.html +0 -14
  621. nautobot/ipam/templates/ipam/prefix_ipaddresses.html +0 -11
  622. nautobot/ipam/templates/ipam/prefix_prefixes.html +0 -11
  623. nautobot/project-static/docs/requirements.txt +0 -14
  624. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/LICENSE.txt +0 -0
  625. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/NOTICE +0 -0
  626. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/WHEEL +0 -0
  627. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,34 @@
1
+ {% extends 'generic/object_create.html' %}
2
+ {% load form_helpers %}
3
+
4
+ {% block form %}
5
+ <div class="panel panel-default">
6
+ <div class="panel-heading"><strong>Prefix</strong></div>
7
+ <div class="panel-body">
8
+ {% render_field form.prefix %}
9
+ {% render_field form.namespace %}
10
+ {% render_field form.type %}
11
+ {% render_field form.status %}
12
+ {% render_field form.role %}
13
+ {% render_field form.rir %}
14
+ {% render_field form.date_allocated %}
15
+ {% render_field form.description %}
16
+ </div>
17
+ </div>
18
+ <div class="panel panel-default">
19
+ <div class="panel-heading"><strong>VRF Assignment</strong></div>
20
+ <div class="panel-body">
21
+ {% render_field form.vrfs %}
22
+ </div>
23
+ </div>
24
+ <div class="panel panel-default">
25
+ <div class="panel-heading"><strong>Location/VLAN Assignment</strong></div>
26
+ <div class="panel-body">
27
+ {% render_field form.locations %}
28
+ {% render_field form.vlan_group %}
29
+ {% render_field form.vlan %}
30
+ </div>
31
+ </div>
32
+ {% include 'inc/tenancy_form_panel.html' %}
33
+ {% include 'inc/extras_features_edit_form_fields.html' %}
34
+ {% endblock %}
@@ -1,34 +1 @@
1
- {% extends 'generic/object_create.html' %}
2
- {% load form_helpers %}
3
-
4
- {% block form %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading"><strong>Prefix</strong></div>
7
- <div class="panel-body">
8
- {% render_field form.prefix %}
9
- {% render_field form.namespace %}
10
- {% render_field form.type %}
11
- {% render_field form.status %}
12
- {% render_field form.role %}
13
- {% render_field form.rir %}
14
- {% render_field form.date_allocated %}
15
- {% render_field form.description %}
16
- </div>
17
- </div>
18
- <div class="panel panel-default">
19
- <div class="panel-heading"><strong>VRF Assignment</strong></div>
20
- <div class="panel-body">
21
- {% render_field form.vrfs %}
22
- </div>
23
- </div>
24
- <div class="panel panel-default">
25
- <div class="panel-heading"><strong>Location/VLAN Assignment</strong></div>
26
- <div class="panel-body">
27
- {% render_field form.locations %}
28
- {% render_field form.vlan_group %}
29
- {% render_field form.vlan %}
30
- </div>
31
- </div>
32
- {% include 'inc/tenancy_form_panel.html' %}
33
- {% include 'inc/extras_features_edit_form_fields.html' %}
34
- {% endblock %}
1
+ {% extends 'ipam/prefix_create.html' %}
@@ -0,0 +1,3 @@
1
+
2
+ {% extends 'generic/object_retrieve.html' %}
3
+ {% load helpers %}
@@ -1,7 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_breadcrumbs %}
5
- <li>{{ object.parent|hyperlinked_object }}</li>
6
- {% endblock extra_breadcrumbs %}
7
-
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,8 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_breadcrumbs %}
5
- {% if object.vlan_group %}
6
- <li><a href="{% url 'ipam:vlan_list' %}?vlan_group={{ object.vlan_group.name }}">{{ object.vlan_group }}</a></li>
7
- {% endif %}
8
- {% endblock extra_breadcrumbs %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -7,7 +7,7 @@
7
7
  <div class="panel-body">
8
8
  {% render_field form.name %}
9
9
  {% render_field form.namespace %}
10
- {% render_field form.rd %}
10
+ {% render_field form.rd %}
11
11
  {% render_field form.status %}
12
12
  {% render_field form.description %}
13
13
  </div>
@@ -413,6 +413,11 @@ class PrefixTest(APIViewTestCases.APIViewTestCase):
413
413
  }
414
414
  cls.choices_fields = ["type"]
415
415
 
416
+ # Generic `test_update_object()` will grab and update the first Prefix
417
+ first_pfx = Prefix.objects.first()
418
+ cls.update_data = cls.create_data[0].copy()
419
+ cls.update_data["namespace"] = first_pfx.namespace.pk # can't change network and namespace in the same update
420
+
416
421
  def test_legacy_api_behavior(self):
417
422
  """
418
423
  Tests for the 2.0/2.1 REST API of Prefixes.
@@ -284,6 +284,393 @@ class IPAddressToInterfaceTest(TestCase):
284
284
  self.assertEqual(remaining_assignments.count(), 1)
285
285
  self.assertIn(assignment_nested_module, remaining_assignments)
286
286
 
287
+ def test_ip_address_to_interface_delete_signal_no_save_when_device_has_no_primary_ips(self):
288
+ """
289
+ Test that Device is not saved when removing an IP from an interface and the device
290
+ has no primary IPs assigned.
291
+ """
292
+ # Create an IP address
293
+ ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
294
+
295
+ # Assign IP to interface
296
+ assignment_device_int1 = IPAddressToInterface.objects.create(interface=self.test_int1, ip_address=ip_addr)
297
+
298
+ # Mock the device save method to verify it's not called
299
+ with patch.object(self.test_device, "save") as mock_save:
300
+ # Remove the IP assignment from interface - this should NOT trigger a device save
301
+ assignment_device_int1.delete()
302
+
303
+ # Assert save was not called since no primary IPs were affected
304
+ mock_save.assert_not_called()
305
+
306
+ def test_ip_address_to_interface_delete_signal_no_save_when_removing_non_primary_ip_from_device(self):
307
+ """
308
+ Test that Device is not saved when removing an IP from an interface and the IP
309
+ is not the device's primary IP.
310
+ """
311
+ # Test removing non-primary IPv4 assignment
312
+ with self.subTest("IPv4 non-primary IP removal"):
313
+ # Create IPv4 addresses
314
+ primary_ipv4_addr = IPAddress.objects.create(
315
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
316
+ )
317
+ other_ipv4_addr = IPAddress.objects.create(
318
+ address="192.0.2.2/24", status=self.status, namespace=self.namespace
319
+ )
320
+
321
+ # Assign primary IP to interface first (required before setting as primary)
322
+ IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv4_addr)
323
+
324
+ # Set it as the device's primary IP
325
+ self.test_device.primary_ip4 = primary_ipv4_addr
326
+ self.test_device.save()
327
+
328
+ # Assign the other IP to a different interface
329
+ assignment_other_ipv4 = IPAddressToInterface.objects.create(
330
+ interface=self.test_int1, ip_address=other_ipv4_addr
331
+ )
332
+
333
+ with patch.object(self.test_device, "save") as mock_save:
334
+ assignment_other_ipv4.delete()
335
+ mock_save.assert_not_called()
336
+
337
+ # Test removing non-primary IPv6 assignment
338
+ with self.subTest("IPv6 non-primary IP removal"):
339
+ # Create IPv6 prefix first
340
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
341
+
342
+ # Create IPv6 addresses
343
+ primary_ipv6_addr = IPAddress.objects.create(
344
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
345
+ )
346
+ other_ipv6_addr = IPAddress.objects.create(
347
+ address="2001:db8::2/64", status=self.status, namespace=self.namespace
348
+ )
349
+
350
+ # Assign primary IP to interface first (required before setting as primary)
351
+ IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv6_addr)
352
+
353
+ # Set it as the device's primary IP
354
+ self.test_device.primary_ip6 = primary_ipv6_addr
355
+ self.test_device.save()
356
+
357
+ # Assign the other IP to a different interface
358
+ assignment_other_ipv6 = IPAddressToInterface.objects.create(
359
+ interface=self.test_int1, ip_address=other_ipv6_addr
360
+ )
361
+
362
+ with patch.object(self.test_device, "save") as mock_save:
363
+ assignment_other_ipv6.delete()
364
+ mock_save.assert_not_called()
365
+
366
+ def test_ip_address_to_interface_delete_signal_save_when_removing_primary_ip_from_device(self):
367
+ """
368
+ Test that Device is saved when removing an IP from an interface and the IP is the device's
369
+ primary IP and no other assignments exist.
370
+ """
371
+ # Test removing primary IPv4 assignment
372
+ with self.subTest("IPv4 primary IP removal"):
373
+ # Create primary IPv4 address
374
+ primary_ipv4_addr = IPAddress.objects.create(
375
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
376
+ )
377
+
378
+ # Assign primary IPv4 to an interface first
379
+ assignment_primary_ipv4 = IPAddressToInterface.objects.create(
380
+ interface=self.test_int1, ip_address=primary_ipv4_addr
381
+ )
382
+
383
+ # Set it as the device's primary IP
384
+ self.test_device.primary_ip4 = primary_ipv4_addr
385
+ self.test_device.save()
386
+
387
+ # Mock the device save method to verify it's called
388
+ with patch.object(self.test_device, "save") as mock_save:
389
+ # Remove the primary IP assignment - this SHOULD trigger a device save
390
+ assignment_primary_ipv4.delete()
391
+
392
+ # Assert save was called to nullify primary_ip4
393
+ mock_save.assert_called_once()
394
+
395
+ # Test removing primary IPv6 assignment
396
+ with self.subTest("IPv6 primary IP removal"):
397
+ # Create IPv6 prefix first
398
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
399
+
400
+ # Create primary IPv6 address
401
+ primary_ipv6_addr = IPAddress.objects.create(
402
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
403
+ )
404
+
405
+ # Assign primary IPv6 to an interface first
406
+ assignment_primary_ipv6 = IPAddressToInterface.objects.create(
407
+ interface=self.test_int1, ip_address=primary_ipv6_addr
408
+ )
409
+
410
+ # Set it as the device's primary IP
411
+ self.test_device.primary_ip6 = primary_ipv6_addr
412
+ self.test_device.save()
413
+
414
+ # Mock the device save method to verify it's called
415
+ with patch.object(self.test_device, "save") as mock_save:
416
+ # Remove the primary IP assignment - this SHOULD trigger a device save
417
+ assignment_primary_ipv6.delete()
418
+
419
+ # Assert save was called to nullify primary_ip6
420
+ mock_save.assert_called_once()
421
+
422
+ def test_ip_address_to_interface_delete_signal_no_save_when_device_primary_ip_has_multiple_assignments(self):
423
+ """
424
+ Test that Device is not saved when removing an IP from an interface and the IP is the device's
425
+ primary IP but is assigned to other interfaces on that device.
426
+ """
427
+ # Test IPv4 primary IP with multiple assignments
428
+ with self.subTest("IPv4 primary IP with multiple assignments"):
429
+ # Create primary IPv4 address
430
+ primary_ipv4_addr = IPAddress.objects.create(
431
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
432
+ )
433
+ # Assign primary IPv4 to multiple interfaces
434
+ assignment_ipv4_int1 = IPAddressToInterface.objects.create(
435
+ interface=self.test_int1, ip_address=primary_ipv4_addr
436
+ )
437
+ IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv4_addr)
438
+
439
+ # Set it as the device's primary IP
440
+ self.test_device.primary_ip4 = primary_ipv4_addr
441
+ self.test_device.save()
442
+
443
+ # Mock the device save method to verify it's not called
444
+ with patch.object(self.test_device, "save") as mock_save:
445
+ # Remove primary IP from one interface - should NOT trigger save since other assignment exists
446
+ assignment_ipv4_int1.delete()
447
+
448
+ # Assert save was not called since IP is still assigned to test_int2
449
+ mock_save.assert_not_called()
450
+
451
+ # Test IPv6 primary IP with multiple assignments
452
+ with self.subTest("IPv6 primary IP with multiple assignments"):
453
+ # Create IPv6 prefix first
454
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
455
+
456
+ # Create primary IPv6 address
457
+ primary_ipv6_addr = IPAddress.objects.create(
458
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
459
+ )
460
+
461
+ # Assign primary IPv6 to multiple interfaces
462
+ assignment_ipv6_int1 = IPAddressToInterface.objects.create(
463
+ interface=self.test_int1, ip_address=primary_ipv6_addr
464
+ )
465
+ IPAddressToInterface.objects.create(interface=self.test_int2, ip_address=primary_ipv6_addr)
466
+
467
+ # Set it as the device's primary IP
468
+ self.test_device.primary_ip6 = primary_ipv6_addr
469
+ self.test_device.save()
470
+
471
+ # Mock the device save method to verify it's not called
472
+ with patch.object(self.test_device, "save") as mock_save:
473
+ # Remove primary IP from one interface - should NOT trigger save since other assignment exists
474
+ assignment_ipv6_int1.delete()
475
+
476
+ # Assert save was not called since IP is still assigned to test_int2
477
+ mock_save.assert_not_called()
478
+
479
+ def test_ip_address_to_interface_delete_signal_no_save_when_vm_has_no_primary_ips(self):
480
+ """
481
+ Test that VM is not saved when removing an IP from a VM interface and the VM
482
+ has no primary IPs assigned.
483
+ """
484
+ # Create an IP address
485
+ ip_addr = IPAddress.objects.create(address="192.0.2.1/24", status=self.status, namespace=self.namespace)
486
+
487
+ # VM has no primary IPs by default (both are None)
488
+
489
+ # Assign IP to VM interface
490
+ assignment_vm_int1 = IPAddressToInterface.objects.create(vm_interface=self.test_vmint1, ip_address=ip_addr)
491
+
492
+ # Mock the VM save method to verify it's not called
493
+ with patch.object(self.test_vm, "save") as mock_save:
494
+ # Remove the IP assignment from VM interface - this should NOT trigger a VM save
495
+ assignment_vm_int1.delete()
496
+
497
+ # Assert save was not called since no primary IPs were affected
498
+ mock_save.assert_not_called()
499
+
500
+ def test_ip_address_to_interface_delete_signal_no_save_when_removing_non_primary_ip_from_vm(self):
501
+ """
502
+ Test that VM is not saved when removing an IP from a VM interface and the IP
503
+ is not the VM's primary IP.
504
+ """
505
+ # Test removing non-primary IPv4 assignment
506
+ with self.subTest("IPv4 non-primary IP removal"):
507
+ # Create IPv4 addresses
508
+ primary_ipv4_addr = IPAddress.objects.create(
509
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
510
+ )
511
+ other_ipv4_addr = IPAddress.objects.create(
512
+ address="192.0.2.2/24", status=self.status, namespace=self.namespace
513
+ )
514
+
515
+ # Assign primary IP to VM interface first (required before setting as primary)
516
+ IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv4_addr)
517
+
518
+ # Set it as the VM's primary IP
519
+ self.test_vm.primary_ip4 = primary_ipv4_addr
520
+ self.test_vm.save()
521
+
522
+ # Assign the other IP to a different VM interface
523
+ assignment_vm_int1 = IPAddressToInterface.objects.create(
524
+ vm_interface=self.test_vmint1, ip_address=other_ipv4_addr
525
+ )
526
+
527
+ with patch.object(self.test_vm, "save") as mock_save:
528
+ assignment_vm_int1.delete()
529
+ mock_save.assert_not_called()
530
+
531
+ # Test removing non-primary IPv6 assignment
532
+ with self.subTest("IPv6 non-primary IP removal"):
533
+ # Create IPv6 prefix first
534
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
535
+
536
+ # Create IPv6 addresses
537
+ primary_ipv6_addr = IPAddress.objects.create(
538
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
539
+ )
540
+ other_ipv6_addr = IPAddress.objects.create(
541
+ address="2001:db8::2/64", status=self.status, namespace=self.namespace
542
+ )
543
+
544
+ # Assign primary IP to VM interface first (required before setting as primary)
545
+ IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv6_addr)
546
+
547
+ # Set it as the VM's primary IP
548
+ self.test_vm.primary_ip6 = primary_ipv6_addr
549
+ self.test_vm.save()
550
+
551
+ # Assign the other IP to a different VM interface
552
+ assignment_vm_int1 = IPAddressToInterface.objects.create(
553
+ vm_interface=self.test_vmint1, ip_address=other_ipv6_addr
554
+ )
555
+
556
+ with patch.object(self.test_vm, "save") as mock_save:
557
+ assignment_vm_int1.delete()
558
+ mock_save.assert_not_called()
559
+
560
+ def test_ip_address_to_interface_delete_signal_save_when_removing_primary_ip_from_vm(self):
561
+ """
562
+ Test that VM is saved when removing an IP from a VM interface and the IP is the VM's
563
+ primary IP and no other assignments exist.
564
+ """
565
+ # Test removing primary IPv4 assignment
566
+ with self.subTest("IPv4 primary IP removal"):
567
+ # Create primary IPv4 address
568
+ primary_ipv4_addr = IPAddress.objects.create(
569
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
570
+ )
571
+
572
+ # Assign primary IPv4 to VM interface first
573
+ assignment_primary_ipv4 = IPAddressToInterface.objects.create(
574
+ vm_interface=self.test_vmint1, ip_address=primary_ipv4_addr
575
+ )
576
+
577
+ # Set it as the VM's primary IP
578
+ self.test_vm.primary_ip4 = primary_ipv4_addr
579
+ self.test_vm.save()
580
+
581
+ # Mock the VM save method to verify it's called
582
+ with patch.object(self.test_vm, "save") as mock_save:
583
+ # Remove the primary IP assignment - this SHOULD trigger a VM save
584
+ assignment_primary_ipv4.delete()
585
+
586
+ # Assert save was called to nullify primary_ip4
587
+ mock_save.assert_called_once()
588
+
589
+ # Test removing primary IPv6 assignment
590
+ with self.subTest("IPv6 primary IP removal"):
591
+ # Create IPv6 prefix first
592
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
593
+
594
+ # Create primary IPv6 address
595
+ primary_ipv6_addr = IPAddress.objects.create(
596
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
597
+ )
598
+
599
+ # Assign primary IPv6 to VM interface first
600
+ assignment_primary_ipv6 = IPAddressToInterface.objects.create(
601
+ vm_interface=self.test_vmint1, ip_address=primary_ipv6_addr
602
+ )
603
+
604
+ # Set it as the VM's primary IP
605
+ self.test_vm.primary_ip6 = primary_ipv6_addr
606
+ self.test_vm.save()
607
+
608
+ # Mock the VM save method to verify it's called
609
+ with patch.object(self.test_vm, "save") as mock_save:
610
+ # Remove the primary IP assignment - this SHOULD trigger a VM save
611
+ assignment_primary_ipv6.delete()
612
+
613
+ # Assert save was called to nullify primary_ip6
614
+ mock_save.assert_called_once()
615
+
616
+ def test_ip_address_to_interface_delete_signal_no_save_when_vm_primary_ip_has_multiple_assignments(self):
617
+ """
618
+ Test that VM is not saved when removing an IP from a VM interface and the IP is the VM's
619
+ primary IP but is assigned to other VM interfaces on that VM.
620
+ """
621
+ # Test IPv4 primary IP with multiple assignments
622
+ with self.subTest("IPv4 primary IP with multiple assignments"):
623
+ # Create primary IPv4 address
624
+ primary_ipv4_addr = IPAddress.objects.create(
625
+ address="192.0.2.1/24", status=self.status, namespace=self.namespace
626
+ )
627
+
628
+ # Assign primary IPv4 to multiple VM interfaces
629
+ assignment_ipv4_vmint1 = IPAddressToInterface.objects.create(
630
+ vm_interface=self.test_vmint1, ip_address=primary_ipv4_addr
631
+ )
632
+ IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv4_addr)
633
+
634
+ # Set it as the VM's primary IP
635
+ self.test_vm.primary_ip4 = primary_ipv4_addr
636
+ self.test_vm.save()
637
+
638
+ # Mock the VM save method to verify it's not called
639
+ with patch.object(self.test_vm, "save") as mock_save:
640
+ # Remove primary IP from one VM interface - should NOT trigger save since other assignment exists
641
+ assignment_ipv4_vmint1.delete()
642
+
643
+ # Assert save was not called since IP is still assigned to test_vmint2
644
+ mock_save.assert_not_called()
645
+
646
+ # Test IPv6 primary IP with multiple assignments
647
+ with self.subTest("IPv6 primary IP with multiple assignments"):
648
+ # Create IPv6 prefix first
649
+ Prefix.objects.create(prefix="2001:db8::/64", status=self.status, namespace=self.namespace)
650
+
651
+ # Create primary IPv6 address
652
+ primary_ipv6_addr = IPAddress.objects.create(
653
+ address="2001:db8::1/64", status=self.status, namespace=self.namespace
654
+ )
655
+
656
+ # Assign primary IPv6 to multiple VM interfaces
657
+ assignment_ipv6_vmint1 = IPAddressToInterface.objects.create(
658
+ vm_interface=self.test_vmint1, ip_address=primary_ipv6_addr
659
+ )
660
+ IPAddressToInterface.objects.create(vm_interface=self.test_vmint2, ip_address=primary_ipv6_addr)
661
+
662
+ # Set it as the VM's primary IP
663
+ self.test_vm.primary_ip6 = primary_ipv6_addr
664
+ self.test_vm.save()
665
+
666
+ # Mock the VM save method to verify it's not called
667
+ with patch.object(self.test_vm, "save") as mock_save:
668
+ # Remove primary IP from one VM interface - should NOT trigger save since other assignment exists
669
+ assignment_ipv6_vmint1.delete()
670
+
671
+ # Assert save was not called since IP is still assigned to test_vmint2
672
+ mock_save.assert_not_called()
673
+
287
674
 
288
675
  class TestVarbinaryIPField(TestCase):
289
676
  """Tests for `nautobot.ipam.fields.VarbinaryIPField`."""
@@ -802,6 +802,23 @@ class PrefixQuerysetTestCase(TestCase):
802
802
  status=self.status,
803
803
  )
804
804
 
805
+ # same but for IPv6
806
+ container_v6 = netaddr.IPNetwork("2001:db8::/120")
807
+ Prefix.objects.create(
808
+ prefix=container_v6,
809
+ type=choices.PrefixTypeChoices.TYPE_CONTAINER,
810
+ namespace=namespace,
811
+ status=self.status,
812
+ )
813
+ for prefix_length in range(121, 129):
814
+ network = list(container_v6.subnet(prefix_length))[1]
815
+ Prefix.objects.create(
816
+ prefix=network,
817
+ type=choices.PrefixTypeChoices.TYPE_NETWORK,
818
+ namespace=namespace,
819
+ status=self.status,
820
+ )
821
+
805
822
  for last_octet in range(1, 255):
806
823
  ip = netaddr.IPAddress(f"10.0.0.{last_octet}")
807
824
  expected_prefix_length = 33 - len(bin(last_octet)[2:]) # [1] = 32, [2,3] = 31, [4,5,6,7] = 30, etc.
@@ -819,3 +836,32 @@ class PrefixQuerysetTestCase(TestCase):
819
836
  .order_by("-prefix_length")
820
837
  .first(),
821
838
  )
839
+
840
+ ip = netaddr.IPAddress(f"2001:db8::{last_octet:x}")
841
+ expected_prefix_length = 129 - len(bin(last_octet)[2:]) # [1] = 128, [2,3] = 127, [4,5,6,7] = 126, etc.
842
+ with self.subTest(ip=ip, expected_prefix_length=expected_prefix_length):
843
+ closest_parent = Prefix.objects.filter(namespace=namespace).get_closest_parent(ip, include_self=True)
844
+ expected_parent = list(container_v6.subnet(expected_prefix_length))[1]
845
+ self.assertEqual(closest_parent.prefix, expected_parent)
846
+ self.assertEqual(
847
+ closest_parent,
848
+ Prefix.objects.filter(
849
+ network__lte=ip.value,
850
+ broadcast__gte=ip.value,
851
+ namespace=namespace,
852
+ )
853
+ .order_by("-prefix_length")
854
+ .first(),
855
+ )
856
+
857
+ slash32 = Prefix.objects.create(prefix="10.1.1.154/32", namespace=namespace, status=self.status)
858
+ slash31 = Prefix.objects.create(prefix="10.1.1.154/31", namespace=namespace, status=self.status)
859
+ slash30 = Prefix.objects.create(prefix="10.1.1.154/30", namespace=namespace, status=self.status)
860
+ self.assertEqual(slash31, Prefix.objects.get_closest_parent(slash32.prefix))
861
+ self.assertEqual(slash30, Prefix.objects.get_closest_parent(slash31.prefix))
862
+
863
+ slash126 = Prefix.objects.create(prefix="::1/126", namespace=namespace, status=self.status)
864
+ slash127 = Prefix.objects.create(prefix="::1/127", namespace=namespace, status=self.status)
865
+ slash128 = Prefix.objects.create(prefix="::1/128", namespace=namespace, status=self.status)
866
+ self.assertEqual(slash126, Prefix.objects.get_closest_parent(slash127.prefix))
867
+ self.assertEqual(slash127, Prefix.objects.get_closest_parent(slash128.prefix))
@@ -303,6 +303,8 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
303
303
  status=ip_status,
304
304
  namespace=self.namespace,
305
305
  )
306
+ # add this permission to can test button Add an IP Address
307
+ self.add_permissions("ipam.add_ipaddress")
306
308
  url = reverse("ipam:prefix_ipaddresses", args=(instance.pk,))
307
309
  response = self.client.get(url)
308
310
  self.assertHttpStatus(response, 200)
@@ -314,6 +316,35 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
314
316
  f'<li role="presentation" class="active"><a href="{url}">IP Addresses <span class="badge">2</span></a></li>'
315
317
  )
316
318
  self.assertInHTML(ip_address_tab, content)
319
+ # Checks if the button is in the content.
320
+ self.assertInHTML("""<span class="mdi mdi-plus-thick" aria-hidden="true"></span>Add an IP Address""", content)
321
+
322
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
323
+ def test_prefix_child_prefixes_table_list(self):
324
+ instance = Prefix.objects.create(
325
+ prefix="5.5.10.0/23",
326
+ namespace=self.namespace,
327
+ type=PrefixTypeChoices.TYPE_NETWORK,
328
+ status=self.statuses[1],
329
+ )
330
+ Prefix.objects.create(
331
+ prefix="5.5.10.0/30",
332
+ namespace=self.namespace,
333
+ type=PrefixTypeChoices.TYPE_POOL,
334
+ status=self.statuses[1],
335
+ )
336
+ # add this permission to can test button Add Child Prefix
337
+ self.add_permissions("ipam.add_prefix")
338
+ url = reverse("ipam:prefix_prefixes", args=(instance.pk,))
339
+ response = self.client.get(url)
340
+ self.assertHttpStatus(response, 200)
341
+ content = extract_page_body(response.content.decode(response.charset))
342
+ # This validates that both parent prefix and child prefix IPAddresses are present in parent prefix IPAddresses list
343
+ self.assertIn("5.5.10.0/30", strip_tags(content))
344
+ ip_address_tab = f'<li role="presentation" class="active"><a href="{url}">Child Prefixes <span class="badge">1</span></a></li>'
345
+ self.assertInHTML(ip_address_tab, content)
346
+ # Checks if the button is in the content.
347
+ self.assertInHTML("""<span class="mdi mdi-plus-thick" aria-hidden="true"></span>Add Child Prefix""", content)
317
348
 
318
349
 
319
350
  class IPAddressTestCase(ViewTestCases.PrimaryObjectViewTestCase):
@@ -1036,6 +1067,9 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1036
1067
 
1037
1068
  class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1038
1069
  model = Service
1070
+ allowed_number_of_tree_queries_per_view_type = {
1071
+ "retrieve": 1,
1072
+ }
1039
1073
 
1040
1074
  @classmethod
1041
1075
  def setUpTestData(cls):