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,146 @@
1
+ from django.template import Context
2
+
3
+ from nautobot.core.templatetags import ui_framework
4
+ from nautobot.core.testing import TestCase
5
+ from nautobot.core.ui.breadcrumbs import Breadcrumbs
6
+ from nautobot.core.ui.titles import Titles
7
+
8
+
9
+ class NautobotTemplatetagsUIComponentsTest(TestCase):
10
+ """Tests template tags from ui_framework module."""
11
+
12
+ # ---------------------------
13
+ # render_title
14
+ # ---------------------------
15
+
16
+ def test_render_title_with_legacy_title_present(self):
17
+ context = Context(
18
+ {
19
+ "title": "Custom Title",
20
+ "view_titles": Titles(),
21
+ "verbose_name_plural": "Default Title",
22
+ }
23
+ )
24
+ output = ui_framework.render_title(context)
25
+
26
+ self.assertEqual(output, "Custom Title")
27
+
28
+ def test_render_title_with_view_titles_only(self):
29
+ context = Context(
30
+ {
31
+ "view_titles": Titles(),
32
+ "verbose_name_plural": "Default Title",
33
+ }
34
+ )
35
+ output = ui_framework.render_title(context)
36
+
37
+ self.assertEqual(output, "Default Title")
38
+
39
+ def test_render_title_with_invalid_view_titles(self):
40
+ class MyStuff:
41
+ pass
42
+
43
+ context = Context(
44
+ {
45
+ "view_titles": MyStuff(),
46
+ "verbose_name_plural": "Default Title",
47
+ }
48
+ )
49
+ output = ui_framework.render_title(context)
50
+
51
+ self.assertEqual(output, "")
52
+
53
+ def test_render_title_with_empty_context(self):
54
+ context = Context({})
55
+ output = ui_framework.render_title(context)
56
+
57
+ self.assertEqual(output, "")
58
+
59
+ # ---------------------------
60
+ # render_breadcrumbs
61
+ # ---------------------------
62
+
63
+ def test_render_breadcrumbs(self):
64
+ context = Context(
65
+ {
66
+ "list_url": "home",
67
+ "title": "New Home",
68
+ "view_action": "list",
69
+ "breadcrumbs": Breadcrumbs(),
70
+ }
71
+ )
72
+ output = ui_framework.render_breadcrumbs(context)
73
+
74
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">New Home</a></li></ol>')
75
+
76
+ def test_render_breadcrumbs_empty_context(self):
77
+ context = Context({})
78
+ output = ui_framework.render_breadcrumbs(context)
79
+
80
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"></ol>')
81
+
82
+ def test_render_breadcrumbs_with_legacy_breadcrumbs(self):
83
+ legacy_breadcrumbs = '<li><a href="/">Home</a></li>'
84
+ context = Context({})
85
+ output = ui_framework.render_breadcrumbs(context, legacy_breadcrumbs)
86
+
87
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">Home</a></li></ol>')
88
+
89
+ def test_render_breadcrumbs_with_legacy_and_block_breadcrumbs_the_same_with_breadcrumbs_class(self):
90
+ legacy_breadcrumbs = block_breadcrumbs = '<li><a href="/">Home</a></li>'
91
+ context = Context(
92
+ {
93
+ "list_url": "home",
94
+ "title": "New Home",
95
+ "view_action": "list",
96
+ "breadcrumbs": Breadcrumbs(),
97
+ }
98
+ )
99
+ output = ui_framework.render_breadcrumbs(context, legacy_breadcrumbs, block_breadcrumbs)
100
+
101
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">New Home</a></li></ol>')
102
+
103
+ def test_render_breadcrumbs_with_legacy_and_block_breadcrumbs_the_same_and_no_breadcrumbs_class(self):
104
+ legacy_breadcrumbs = block_breadcrumbs = '<li><a href="/">Home</a></li>'
105
+ context = Context({})
106
+ output = ui_framework.render_breadcrumbs(context, legacy_breadcrumbs, block_breadcrumbs)
107
+
108
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">Home</a></li></ol>')
109
+
110
+ def test_render_breadcrumbs_with_legacy_breadcrumbs_override(self):
111
+ legacy_breadcrumbs = '<li><a href="/">Home</a></li>'
112
+ block_breadcrumbs = '<li><a href="/">Override</a></li>'
113
+ context = Context(
114
+ {
115
+ "list_url": "home",
116
+ "title": "New Home",
117
+ "view_action": "list",
118
+ "breadcrumbs": Breadcrumbs(),
119
+ }
120
+ )
121
+ output = ui_framework.render_breadcrumbs(context, legacy_breadcrumbs, block_breadcrumbs)
122
+
123
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">Override</a></li></ol>')
124
+
125
+ def test_render_breadcrumbs_strips_tags(self):
126
+ legacy_breadcrumbs = """
127
+ <li>
128
+ <a href="/">Home</a>
129
+ </li>"""
130
+
131
+ block_breadcrumbs = """<li>
132
+
133
+ <a href="/">Home</a></li>
134
+ """
135
+
136
+ context = Context(
137
+ {
138
+ "list_url": "home",
139
+ "title": "New Home",
140
+ "view_action": "list",
141
+ "breadcrumbs": Breadcrumbs(),
142
+ }
143
+ )
144
+ output = ui_framework.render_breadcrumbs(context, legacy_breadcrumbs, block_breadcrumbs)
145
+
146
+ self.assertHTMLEqual(output, '<ol class="breadcrumb"><li><a href="/">New Home</a></li></ol>')
@@ -163,7 +163,7 @@ class TitlesTestCase(TestCase):
163
163
  """Test rendering when no view_action is provided."""
164
164
  context = Context({"verbose_name_plural": "devices"})
165
165
  result = self.titles.render(context)
166
- self.assertEqual(result, "Devices") # Should use list_action as default
166
+ self.assertEqual(result, "Devices") # Should use * action as default
167
167
 
168
168
  def test_get_extra_context(self):
169
169
  """Test that get_extra_context returns empty dict by default."""
@@ -173,7 +173,7 @@ class TitlesTestCase(TestCase):
173
173
 
174
174
  def test_get_extra_context_is_used_during_render(self):
175
175
  """Test that get_extra_context is being used to extend the context."""
176
- context = Context({})
176
+ context = Context({"view_action": "list"})
177
177
 
178
178
  class TitlesSubClass(Titles):
179
179
  def get_extra_context(self, context: Context) -> dict:
@@ -4,10 +4,25 @@ from unittest.mock import patch
4
4
 
5
5
  from django.template import Context
6
6
  from django.test import RequestFactory
7
+ from django.urls import reverse
7
8
 
9
+ from nautobot.cloud.models import CloudNetwork, CloudResourceType, CloudService
10
+ from nautobot.cloud.tables import CloudServiceTable
11
+ from nautobot.cloud.views import CloudResourceTypeUIViewSet
8
12
  from nautobot.core.templatetags.helpers import HTML_NONE
9
13
  from nautobot.core.testing import TestCase
10
- from nautobot.core.ui.object_detail import BaseTextPanel, DataTablePanel, ObjectsTablePanel, Panel
14
+ from nautobot.core.ui.object_detail import (
15
+ _ObjectDetailAdvancedTab,
16
+ _ObjectDetailMainTab,
17
+ BaseTextPanel,
18
+ DataTablePanel,
19
+ DistinctViewTab,
20
+ ObjectDetailContent,
21
+ ObjectFieldsPanel,
22
+ ObjectsTablePanel,
23
+ Panel,
24
+ SectionChoices,
25
+ )
11
26
  from nautobot.dcim.models import DeviceRedundancyGroup
12
27
  from nautobot.dcim.tables.devices import DeviceTable
13
28
 
@@ -68,6 +83,19 @@ class DataTablePanelTest(TestCase):
68
83
  )
69
84
 
70
85
 
86
+ class ObjectFieldsPanelTest(TestCase):
87
+ def test_get_data_ignore_nonexistent_fields(self):
88
+ panel = ObjectFieldsPanel(weight=100, fields=["name", "foo", "bar"], ignore_nonexistent_fields=True)
89
+ redundancy_group = DeviceRedundancyGroup.objects.first()
90
+ context = Context({"object": redundancy_group})
91
+ data = panel.get_data(context)
92
+ self.assertEqual(data, {"name": redundancy_group.name}) # no keys for nonexistent fields
93
+
94
+ panel = ObjectFieldsPanel(weight=100, fields=["name", "foo", "bar"], ignore_nonexistent_fields=False)
95
+ with self.assertRaises(AttributeError):
96
+ data = panel.get_data(context)
97
+
98
+
71
99
  class BaseTextPanelTest(TestCase):
72
100
  def test_init_set_object_params(self):
73
101
  # Test default settings
@@ -200,3 +228,162 @@ class ObjectsTablePanelTest(TestCase):
200
228
  panel.get_extra_context(context_data)
201
229
 
202
230
  self.assertIn("non-existent column `non_existent_column`", str(context.exception))
231
+
232
+
233
+ class ObjectDetailContentExtraTabsTest(TestCase):
234
+ """
235
+ Test suite for verifying the behavior of ObjectDetailContent when rendering default and extra tabs.
236
+ """
237
+
238
+ user_permissions = ["cloud.view_cloudresourcetype", "cloud.view_cloudservice", "cloud.view_cloudnetwork"]
239
+
240
+ def setUp(self):
241
+ super().setUp()
242
+ self.factory = RequestFactory()
243
+ self.request = self.factory.get("/")
244
+ self.request.user = self.user
245
+ self.default_tabs_id = ["main", "advanced", "contacts", "dynamic_groups", "object_metadata"]
246
+
247
+ def test_default_extra_tabs_exist(self):
248
+ """
249
+ Test the default set of tabs (main, advanced, contacts, dynamic_groups, object_metadata) is present.
250
+ """
251
+ content = ObjectDetailContent(
252
+ panels=[],
253
+ )
254
+
255
+ self.assertEqual(len(content.tabs), len(self.default_tabs_id))
256
+ tab_ids = [t.tab_id for t in content.tabs]
257
+ self.assertListEqual(tab_ids, self.default_tabs_id)
258
+
259
+ def test_extra_tabs_exist(self):
260
+ """
261
+ Test that extra tabs (e.g. "services") can be injected via the `extra_tabs` argument.
262
+ Validating that tab IDs are correctly combined when extra tabs are provided.
263
+ """
264
+ content = ObjectDetailContent(
265
+ panels=[],
266
+ extra_tabs=[
267
+ DistinctViewTab(
268
+ weight=1000,
269
+ tab_id="services",
270
+ label="Cloud Services",
271
+ url_name="cloud:cloudresourcetype_services",
272
+ related_object_attribute="cloud_services",
273
+ panels=(
274
+ ObjectsTablePanel(
275
+ section=SectionChoices.FULL_WIDTH,
276
+ weight=100,
277
+ table_class=CloudServiceTable,
278
+ table_filter="cloud_resource_type",
279
+ tab_id="services",
280
+ ),
281
+ ),
282
+ ),
283
+ ],
284
+ )
285
+
286
+ self.assertEqual(len(content.tabs), len(self.default_tabs_id) + 1)
287
+ tab_ids = [t.tab_id for t in content.tabs]
288
+ self.default_tabs_id.append("services")
289
+ self.assertListEqual(tab_ids, self.default_tabs_id)
290
+
291
+ def test_extra_tab_panel_context(self):
292
+ """
293
+ Confirming that extra tab panels produce the correct context,
294
+ including `url` and `body_content_table` populated with the expected related objects.
295
+ """
296
+ cloud_resource_type = CloudResourceType.objects.get_for_model(CloudNetwork)[0]
297
+ cloud_services = CloudService.objects.filter(cloud_resource_type=cloud_resource_type)
298
+
299
+ tab = DistinctViewTab(
300
+ weight=1000,
301
+ tab_id="services",
302
+ label="Cloud Services",
303
+ url_name="cloud:cloudresourcetype_services",
304
+ related_object_attribute="cloud_services",
305
+ panels=(
306
+ ObjectsTablePanel(
307
+ section=SectionChoices.FULL_WIDTH,
308
+ weight=100,
309
+ table_class=CloudServiceTable,
310
+ table_filter="cloud_resource_type",
311
+ tab_id="services",
312
+ ),
313
+ ),
314
+ )
315
+ context = {"request": self.request, "object": cloud_resource_type}
316
+ extra_context = tab.get_extra_context(context)
317
+ self.assertIn("url", extra_context)
318
+ self.assertTrue(extra_context["url"].endswith("/services/"))
319
+
320
+ panel = tab.panels[0]
321
+ panel_context = panel.get_extra_context(context)
322
+
323
+ self.assertIn("body_content_table", panel_context)
324
+ table = panel_context["body_content_table"]
325
+ self.assertQuerySetEqual(cloud_services, table.data)
326
+
327
+ def test_tab_conditional_rendering(self):
328
+ """
329
+ Assert default tabs render on the main detail view but not sub-views, while distinct-view-tabs do the reverse.
330
+ """
331
+ cloud_resource_type = CloudResourceType.objects.get_for_model(CloudNetwork)[0]
332
+ content = CloudResourceTypeUIViewSet.object_detail_content
333
+
334
+ # Main detail view renders all base tabs and no DistinctViewTabs
335
+ request = self.factory.get(cloud_resource_type.get_absolute_url())
336
+ request.user = self.user
337
+ context_data = {
338
+ "request": request,
339
+ "object": cloud_resource_type,
340
+ "settings": {},
341
+ "csrf_token": "",
342
+ "perms": [],
343
+ "created_by": self.request.user,
344
+ "last_updated_by": self.request.user,
345
+ "view_action": "retrieve",
346
+ "detail": True,
347
+ }
348
+ context = Context(context_data)
349
+ for tab in content.tabs:
350
+ if isinstance(tab, DistinctViewTab):
351
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
352
+ self.assertEqual(tab.render(context), "")
353
+ panel_render.assert_not_called()
354
+ elif isinstance(tab, (_ObjectDetailMainTab, _ObjectDetailAdvancedTab)): # other base tabs might not render
355
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
356
+ self.assertNotEqual(tab.render(context), "")
357
+ panel_render.assert_called()
358
+
359
+ # Distinct tab view renders its tab *only*
360
+ request = self.factory.get(reverse("cloud:cloudresourcetype_networks", kwargs={"pk": cloud_resource_type.pk}))
361
+ request.user = self.user
362
+ context_data["request"] = request
363
+ context_data["view_action"] = "networks"
364
+ context = Context(context_data)
365
+ for tab in content.tabs:
366
+ if isinstance(tab, DistinctViewTab) and tab.url_name == "cloud:cloudresourcetype_networks": # pylint: disable=no-member
367
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
368
+ self.assertNotEqual(tab.render(context), "")
369
+ panel_render.assert_called()
370
+ else:
371
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
372
+ self.assertEqual(tab.render(context), "")
373
+ panel_render.assert_not_called()
374
+
375
+ # Same, but for a different distinct view tab
376
+ request = self.factory.get(reverse("cloud:cloudresourcetype_services", kwargs={"pk": cloud_resource_type.pk}))
377
+ request.user = self.user
378
+ context_data["request"] = request
379
+ context_data["view_action"] = "services"
380
+ context = Context(context_data)
381
+ for tab in content.tabs:
382
+ if isinstance(tab, DistinctViewTab) and tab.url_name == "cloud:cloudresourcetype_services": # pylint: disable=no-member
383
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
384
+ self.assertNotEqual(tab.render(context), "")
385
+ panel_render.assert_called()
386
+ else:
387
+ with patch.object(tab.panels[0], "render", wraps=tab.panels[0].render) as panel_render:
388
+ self.assertEqual(tab.render(context), "")
389
+ panel_render.assert_not_called()
@@ -81,6 +81,41 @@ class NormalizeQueryDictTest(TestCase):
81
81
  {"name": ["Sample Status"], "content_types": ["dcim.device"]},
82
82
  )
83
83
 
84
+ self.assertDictEqual(
85
+ requests.normalize_querydict({"name": ["Sample Status"], "content_types": ["1"]}, form_class=StatusForm),
86
+ {"name": "Sample Status", "content_types": ["1"]},
87
+ )
88
+
89
+ self.assertDictEqual(
90
+ requests.normalize_querydict(
91
+ requests.convert_querydict_to_dict(QueryDict("name=Sample Status&content_types=1")),
92
+ form_class=StatusForm,
93
+ ),
94
+ {"name": "Sample Status", "content_types": ["1"]},
95
+ )
96
+
97
+
98
+ class ConvertQueryDictToDictTest(TestCase):
99
+ """
100
+ Validate convert_querydict_to_dict() utility function.
101
+ """
102
+
103
+ def test_convert_querydict_to_dict(self):
104
+ self.assertDictEqual(
105
+ requests.convert_querydict_to_dict(QueryDict("foo=1&bar=2&bar=3&baz=")),
106
+ {"foo": ["1"], "bar": ["2", "3"], "baz": [""]},
107
+ )
108
+
109
+ self.assertDictEqual(
110
+ requests.convert_querydict_to_dict(QueryDict("name=Sample Status&content_types=1")),
111
+ {"name": ["Sample Status"], "content_types": ["1"]},
112
+ )
113
+
114
+ self.assertDictEqual(
115
+ requests.convert_querydict_to_dict(QueryDict("name=Sample Status&content_types=dcim.device")),
116
+ {"name": ["Sample Status"], "content_types": ["dcim.device"]},
117
+ )
118
+
84
119
 
85
120
  class DeepMergeTest(TestCase):
86
121
  """
@@ -8,6 +8,7 @@ import urllib.parse
8
8
  from django.apps import apps
9
9
  from django.conf import settings
10
10
  from django.contrib.contenttypes.models import ContentType
11
+ from django.core.cache import cache
11
12
  from django.core.files.uploadedfile import SimpleUploadedFile
12
13
  from django.test import override_settings, RequestFactory
13
14
  from django.test.utils import override_script_prefix
@@ -23,6 +24,7 @@ from nautobot.core.testing.utils import extract_page_body
23
24
  from nautobot.core.utils.permissions import get_permission_for_model
24
25
  from nautobot.core.views import NautobotMetricsView
25
26
  from nautobot.core.views.mixins import GetReturnURLMixin
27
+ from nautobot.core.views.utils import METRICS_CACHE_KEY
26
28
  from nautobot.dcim.models.locations import Location
27
29
  from nautobot.extras.choices import CustomFieldTypeChoices
28
30
  from nautobot.extras.models import FileProxy, Status
@@ -566,6 +568,49 @@ class MetricsViewTestCase(TestCase):
566
568
  metric_names_with_app.remove(test_metric_name)
567
569
  self.assertSetEqual(metric_names_with_app, metric_names_without_app)
568
570
 
571
+ def test_enabled_metrics_cache_disabled(self):
572
+ """Assert that when cache is disabled the cache enabled function doesn't get called."""
573
+ with mock.patch("nautobot.core.views.utils.generate_latest_with_cache") as mock_generate_latest_with_cache:
574
+ self.query_and_parse_metrics()
575
+ self.assertTrue(mock_generate_latest_with_cache.call_count == 0)
576
+
577
+ @override_settings(METRICS_EXPERIMENTAL_CACHING_DURATION=30)
578
+ def test_enabled_metrics_cache_enabled(self):
579
+ """Assert that multiple calls to metrics with caching returns expected response."""
580
+ test_metric_name = "nautobot_example_metric_count"
581
+ metrics_with_app = self.query_and_parse_metrics()
582
+ metrics_with_app_cached = self.query_and_parse_metrics()
583
+ metric_names_with_app = {metric.name for metric in metrics_with_app}
584
+ metric_names_with_app_cached = {metric.name for metric in metrics_with_app_cached}
585
+ self.assertIn(test_metric_name, metric_names_with_app)
586
+ self.assertIn(test_metric_name, metric_names_with_app_cached)
587
+
588
+ # In some circumstances (e.g. if this test is run first) metrics_with_app may not have
589
+ # metrics from Django like total view counts. Since metrics_with_app_cached is called
590
+ # second, it should have everything that metrics_with_app has (plus potentially more).
591
+ # We at least want to ensure the cached version has everything the non-cached version has.
592
+ self.assertTrue(
593
+ metric_names_with_app.issubset(metric_names_with_app_cached),
594
+ msg="Cached metrics should be a superset of non-cached metrics.",
595
+ )
596
+ with mock.patch("nautobot.core.views.generate_latest_with_cache") as mock_generate_latest_with_cache:
597
+ self.query_and_parse_metrics()
598
+ self.query_and_parse_metrics()
599
+ self.assertEqual(mock_generate_latest_with_cache.call_count, 2)
600
+
601
+ from example_app.metrics import metric_example
602
+
603
+ cache.delete(METRICS_CACHE_KEY) # Ensure we start with a clean cache for the next part of the test
604
+ # Assert that the metric function only gets called once even though we scrape metrics twice
605
+
606
+ mock_metric_function = mock.Mock(name="mock_metric_function", side_effect=metric_example)
607
+ with mock.patch.dict("nautobot.core.views.registry", app_metrics=[mock_metric_function]):
608
+ self.query_and_parse_metrics()
609
+ first_call_count = mock_metric_function.call_count
610
+ self.query_and_parse_metrics()
611
+ second_call_count = mock_metric_function.call_count
612
+ self.assertEqual(first_call_count, second_call_count)
613
+
569
614
 
570
615
  class AuthenticateMetricsTestCase(APITestCase):
571
616
  def test_metrics_authentication(self):
@@ -0,0 +1,43 @@
1
+ from itertools import combinations
2
+
3
+ from nautobot.core.testing import TestCase
4
+ from nautobot.core.views import generic
5
+ from nautobot.dcim.models import Location
6
+
7
+
8
+ class TestViewsGeneric(TestCase):
9
+ def test_mro_resolve_for_generic_views(self):
10
+ """
11
+ Test if all the generic views can be used extend view class.
12
+
13
+ Tries to detect if there is no MRO issues according to the #7829.
14
+ """
15
+ generic_views = [
16
+ generic.GenericView,
17
+ generic.ObjectListView,
18
+ generic.ObjectView,
19
+ generic.ObjectEditView,
20
+ generic.ObjectDeleteView,
21
+ generic.BulkCreateView,
22
+ generic.ObjectImportView,
23
+ generic.BulkImportView,
24
+ generic.BulkEditView,
25
+ generic.BulkRenameView,
26
+ generic.BulkDeleteView,
27
+ generic.ComponentCreateView,
28
+ generic.BulkComponentCreateView,
29
+ ]
30
+ generic_views_pairs = combinations(generic_views, 2)
31
+
32
+ for base_view, extension_view in generic_views_pairs:
33
+ with self.subTest("Test different class inheritance."):
34
+
35
+ class MyMixin(base_view):
36
+ pass
37
+
38
+ # Defining this class will fail if there is MRO issue
39
+ # pylint: disable=unused-variable
40
+ class MyView(MyMixin, extension_view):
41
+ queryset = Location.objects.all()
42
+
43
+ # pylint: enable=unused-variable