nautobot 2.3.10__py3-none-any.whl → 2.3.12__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 (524) hide show
  1. nautobot/apps/utils.py +2 -0
  2. nautobot/cloud/tables.py +1 -0
  3. nautobot/core/forms/forms.py +5 -1
  4. nautobot/core/settings.py +26 -0
  5. nautobot/core/settings.yaml +31 -0
  6. nautobot/core/tables.py +88 -22
  7. nautobot/core/templates/generic/object_bulk_destroy.html +12 -3
  8. nautobot/core/templates/generic/object_bulk_update.html +4 -2
  9. nautobot/core/templates/generic/object_create.html +1 -1
  10. nautobot/core/templates/generic/object_notes.html +1 -1
  11. nautobot/core/templates/generic/object_retrieve.html +1 -1
  12. nautobot/core/templates/rest_framework/api.html +3 -0
  13. nautobot/core/testing/api.py +3 -1
  14. nautobot/core/testing/integration.py +64 -0
  15. nautobot/core/testing/views.py +48 -31
  16. nautobot/core/tests/integration/test_app_navbar.py +3 -3
  17. nautobot/core/tests/integration/test_navbar.py +1 -1
  18. nautobot/core/tests/test_csv.py +3 -0
  19. nautobot/core/tests/test_utils.py +25 -5
  20. nautobot/core/utils/lookup.py +35 -0
  21. nautobot/core/views/generic.py +50 -39
  22. nautobot/core/views/mixins.py +97 -43
  23. nautobot/core/views/renderers.py +8 -5
  24. nautobot/dcim/choices.py +6 -0
  25. nautobot/dcim/tables/devices.py +5 -6
  26. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -1
  27. nautobot/dcim/templates/dcim/device/base.html +1 -1
  28. nautobot/dcim/templates/dcim/device_component_add.html +8 -8
  29. nautobot/dcim/templates/dcim/virtualchassis_add_member.html +2 -2
  30. nautobot/dcim/templates/dcim/virtualchassis_edit.html +2 -2
  31. nautobot/dcim/tests/integration/test_create_device.py +86 -0
  32. nautobot/extras/group_sync.py +42 -0
  33. nautobot/extras/models/metadata.py +1 -0
  34. nautobot/extras/models/models.py +1 -1
  35. nautobot/extras/plugins/__init__.py +2 -1
  36. nautobot/extras/tables.py +1 -0
  37. nautobot/extras/templates/extras/inc/job_table.html +1 -1
  38. nautobot/extras/tests/test_relationships.py +1 -0
  39. nautobot/extras/tests/test_views.py +0 -2
  40. nautobot/extras/views.py +1 -2
  41. nautobot/ipam/factory.py +3 -0
  42. nautobot/ipam/filters.py +5 -0
  43. nautobot/ipam/forms.py +17 -0
  44. nautobot/ipam/models.py +2 -1
  45. nautobot/ipam/signals.py +2 -2
  46. nautobot/ipam/tables.py +6 -13
  47. nautobot/ipam/templates/ipam/ipaddress_assign.html +2 -2
  48. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -1
  49. nautobot/ipam/tests/test_models.py +113 -1
  50. nautobot/ipam/tests/test_views.py +39 -5
  51. nautobot/project-static/docs/404.html +10 -10
  52. nautobot/project-static/docs/additional-features/caching.html +1 -2
  53. nautobot/project-static/docs/additional-features/change-logging.html +1 -2
  54. nautobot/project-static/docs/additional-features/config-contexts.html +1 -2
  55. nautobot/project-static/docs/additional-features/healthcheck.html +1 -2
  56. nautobot/project-static/docs/additional-features/jobs.html +1 -2
  57. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1 -2
  58. nautobot/project-static/docs/administration/celery-queues.html +1 -2
  59. nautobot/project-static/docs/administration/nautobot-server.html +1 -2
  60. nautobot/project-static/docs/administration/nautobot-shell.html +1 -2
  61. nautobot/project-static/docs/administration/permissions.html +1 -2
  62. nautobot/project-static/docs/administration/replicating-nautobot.html +1 -2
  63. nautobot/project-static/docs/apps/index.html +10 -10
  64. nautobot/project-static/docs/apps/migrating-jobs-from-nautobot-v1.html +1 -2
  65. nautobot/project-static/docs/apps/nautobot-apps.html +10 -10
  66. nautobot/project-static/docs/assets/stylesheets/main.6f8fc17f.min.css +1 -0
  67. nautobot/project-static/docs/assets/stylesheets/main.6f8fc17f.min.css.map +1 -0
  68. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +10 -10
  69. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +10 -10
  70. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +10 -10
  71. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +10 -10
  72. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +10 -10
  73. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +10 -10
  74. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +10 -10
  75. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +10 -10
  76. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +10 -10
  77. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +10 -10
  78. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +10 -10
  79. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +10 -10
  80. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +10 -10
  81. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +10 -10
  82. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +10 -10
  83. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +10 -10
  84. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +10 -10
  85. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +141 -16
  86. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +185 -10
  87. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +10 -10
  88. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +10 -10
  89. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +104 -10
  90. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +14 -14
  91. nautobot/project-static/docs/configuration/authentication/ldap.html +1 -2
  92. nautobot/project-static/docs/configuration/authentication/remote.html +1 -2
  93. nautobot/project-static/docs/configuration/authentication/sso.html +1 -2
  94. nautobot/project-static/docs/configuration/index.html +1 -2
  95. nautobot/project-static/docs/configuration/optional-settings.html +1 -2
  96. nautobot/project-static/docs/configuration/required-settings.html +1 -2
  97. nautobot/project-static/docs/core-functionality/circuits.html +1 -2
  98. nautobot/project-static/docs/core-functionality/device-types.html +1 -2
  99. nautobot/project-static/docs/core-functionality/devices.html +1 -2
  100. nautobot/project-static/docs/core-functionality/ipam.html +1 -2
  101. nautobot/project-static/docs/core-functionality/power.html +1 -2
  102. nautobot/project-static/docs/core-functionality/secrets.html +1 -2
  103. nautobot/project-static/docs/core-functionality/services.html +1 -2
  104. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1 -2
  105. nautobot/project-static/docs/core-functionality/tenancy.html +1 -2
  106. nautobot/project-static/docs/core-functionality/virtualization.html +1 -2
  107. nautobot/project-static/docs/core-functionality/vlans.html +1 -2
  108. nautobot/project-static/docs/development/application-registry.html +1 -2
  109. nautobot/project-static/docs/development/apps/api/configuration-view.html +10 -10
  110. nautobot/project-static/docs/development/apps/api/database-backend-config.html +10 -10
  111. nautobot/project-static/docs/development/apps/api/models/django-admin.html +10 -10
  112. nautobot/project-static/docs/development/apps/api/models/global-search.html +10 -10
  113. nautobot/project-static/docs/development/apps/api/models/graphql.html +10 -10
  114. nautobot/project-static/docs/development/apps/api/models/index.html +10 -10
  115. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +10 -10
  116. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +10 -10
  117. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +10 -10
  118. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +10 -10
  119. nautobot/project-static/docs/development/apps/api/platform-features/index.html +10 -10
  120. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +10 -10
  121. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +10 -10
  122. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +10 -10
  123. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +10 -10
  124. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +10 -10
  125. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +10 -10
  126. nautobot/project-static/docs/development/apps/api/prometheus.html +10 -10
  127. nautobot/project-static/docs/development/apps/api/setup.html +10 -10
  128. nautobot/project-static/docs/development/apps/api/testing.html +10 -10
  129. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +10 -10
  130. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +10 -10
  131. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +10 -10
  132. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +10 -10
  133. nautobot/project-static/docs/development/apps/api/ui-extensions/object-detail-views.html +1 -2
  134. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +10 -10
  135. nautobot/project-static/docs/development/apps/api/ui-extensions/tabs.html +1 -2
  136. nautobot/project-static/docs/development/apps/api/views/base-template.html +10 -10
  137. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +10 -10
  138. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +10 -10
  139. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +10 -10
  140. nautobot/project-static/docs/development/apps/api/views/index.html +10 -10
  141. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +10 -10
  142. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +10 -10
  143. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +10 -10
  144. nautobot/project-static/docs/development/apps/api/views/notes.html +10 -10
  145. nautobot/project-static/docs/development/apps/api/views/rest-api.html +10 -10
  146. nautobot/project-static/docs/development/apps/api/views/urls.html +10 -10
  147. nautobot/project-static/docs/development/apps/api/views/view-overrides.html +1 -2
  148. nautobot/project-static/docs/development/apps/index.html +10 -10
  149. nautobot/project-static/docs/development/apps/migration/code-updates.html +10 -10
  150. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +10 -10
  151. nautobot/project-static/docs/development/apps/migration/from-v1.html +10 -10
  152. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +10 -10
  153. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +10 -10
  154. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +10 -10
  155. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +10 -10
  156. nautobot/project-static/docs/development/apps/porting-from-netbox.html +10 -10
  157. nautobot/project-static/docs/development/best-practices.html +1 -2
  158. nautobot/project-static/docs/development/core/application-registry.html +10 -10
  159. nautobot/project-static/docs/development/core/best-practices.html +10 -10
  160. nautobot/project-static/docs/development/core/bootstrap-ui.html +10 -10
  161. nautobot/project-static/docs/development/core/caching.html +10 -10
  162. nautobot/project-static/docs/development/core/controllers.html +10 -10
  163. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +10 -10
  164. nautobot/project-static/docs/development/core/extending-models.html +1 -2
  165. nautobot/project-static/docs/development/core/generic-views.html +10 -10
  166. nautobot/project-static/docs/development/core/getting-started.html +10 -10
  167. nautobot/project-static/docs/development/core/homepage.html +10 -10
  168. nautobot/project-static/docs/development/core/index.html +10 -10
  169. nautobot/project-static/docs/development/core/model-checklist.html +10 -10
  170. nautobot/project-static/docs/development/core/model-features.html +10 -10
  171. nautobot/project-static/docs/development/core/natural-keys.html +10 -10
  172. nautobot/project-static/docs/development/core/navigation-menu.html +10 -10
  173. nautobot/project-static/docs/development/core/react-ui.html +1 -2
  174. nautobot/project-static/docs/development/core/release-checklist.html +10 -10
  175. nautobot/project-static/docs/development/core/role-internals.html +10 -10
  176. nautobot/project-static/docs/development/core/settings.html +10 -10
  177. nautobot/project-static/docs/development/core/style-guide.html +10 -10
  178. nautobot/project-static/docs/development/core/templates.html +10 -10
  179. nautobot/project-static/docs/development/core/testing.html +12 -12
  180. nautobot/project-static/docs/development/core/user-preferences.html +10 -10
  181. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1 -2
  182. nautobot/project-static/docs/development/extending-models.html +1 -2
  183. nautobot/project-static/docs/development/generic-views.html +1 -2
  184. nautobot/project-static/docs/development/getting-started.html +1 -2
  185. nautobot/project-static/docs/development/homepage.html +1 -2
  186. nautobot/project-static/docs/development/index.html +10 -10
  187. nautobot/project-static/docs/development/jobs/index.html +10 -10
  188. nautobot/project-static/docs/development/jobs/migration/from-v1.html +10 -10
  189. nautobot/project-static/docs/development/model-features.html +1 -2
  190. nautobot/project-static/docs/development/natural-keys.html +1 -2
  191. nautobot/project-static/docs/development/navigation-menu.html +1 -2
  192. nautobot/project-static/docs/development/react-ui.html +1 -2
  193. nautobot/project-static/docs/development/release-checklist.html +1 -2
  194. nautobot/project-static/docs/development/role-internals.html +1 -2
  195. nautobot/project-static/docs/development/style-guide.html +1 -2
  196. nautobot/project-static/docs/development/templates.html +1 -2
  197. nautobot/project-static/docs/development/testing.html +1 -2
  198. nautobot/project-static/docs/development/user-preferences.html +1 -2
  199. nautobot/project-static/docs/docker/index.html +1 -2
  200. nautobot/project-static/docs/index.html +10 -10
  201. nautobot/project-static/docs/installation/centos.html +1 -2
  202. nautobot/project-static/docs/installation/external-authentication.html +1 -2
  203. nautobot/project-static/docs/installation/http-server.html +1 -2
  204. nautobot/project-static/docs/installation/index.html +1 -2
  205. nautobot/project-static/docs/installation/migrating-from-netbox.html +1 -2
  206. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1 -2
  207. nautobot/project-static/docs/installation/nautobot.html +1 -2
  208. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1 -2
  209. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1 -2
  210. nautobot/project-static/docs/installation/services.html +1 -2
  211. nautobot/project-static/docs/installation/ubuntu.html +1 -2
  212. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +1 -2
  213. nautobot/project-static/docs/installation/upgrading.html +1 -2
  214. nautobot/project-static/docs/models/circuits/circuit.html +1 -2
  215. nautobot/project-static/docs/models/circuits/circuittermination.html +1 -2
  216. nautobot/project-static/docs/models/circuits/circuittype.html +1 -2
  217. nautobot/project-static/docs/models/circuits/provider.html +1 -2
  218. nautobot/project-static/docs/models/circuits/providernetwork.html +1 -2
  219. nautobot/project-static/docs/models/cloud/cloudaccount.html +1 -2
  220. nautobot/project-static/docs/models/cloud/cloudnetwork.html +1 -2
  221. nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +1 -2
  222. nautobot/project-static/docs/models/cloud/cloudresourcetype.html +1 -2
  223. nautobot/project-static/docs/models/cloud/cloudservice.html +1 -2
  224. nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +1 -2
  225. nautobot/project-static/docs/models/dcim/cable.html +1 -2
  226. nautobot/project-static/docs/models/dcim/consoleport.html +1 -2
  227. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1 -2
  228. nautobot/project-static/docs/models/dcim/consoleserverport.html +1 -2
  229. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1 -2
  230. nautobot/project-static/docs/models/dcim/controller.html +1 -2
  231. nautobot/project-static/docs/models/dcim/controllermanageddevicegroup.html +1 -2
  232. nautobot/project-static/docs/models/dcim/device.html +1 -2
  233. nautobot/project-static/docs/models/dcim/devicebay.html +1 -2
  234. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1 -2
  235. nautobot/project-static/docs/models/dcim/devicefamily.html +1 -2
  236. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1 -2
  237. nautobot/project-static/docs/models/dcim/devicetype.html +1 -2
  238. nautobot/project-static/docs/models/dcim/frontport.html +1 -2
  239. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1 -2
  240. nautobot/project-static/docs/models/dcim/interface.html +1 -2
  241. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1 -2
  242. nautobot/project-static/docs/models/dcim/inventoryitem.html +1 -2
  243. nautobot/project-static/docs/models/dcim/location.html +1 -2
  244. nautobot/project-static/docs/models/dcim/locationtype.html +1 -2
  245. nautobot/project-static/docs/models/dcim/manufacturer.html +1 -2
  246. nautobot/project-static/docs/models/dcim/module.html +1 -2
  247. nautobot/project-static/docs/models/dcim/modulebay.html +1 -2
  248. nautobot/project-static/docs/models/dcim/modulebaytemplate.html +1 -2
  249. nautobot/project-static/docs/models/dcim/moduletype.html +1 -2
  250. nautobot/project-static/docs/models/dcim/platform.html +1 -2
  251. nautobot/project-static/docs/models/dcim/powerfeed.html +1 -2
  252. nautobot/project-static/docs/models/dcim/poweroutlet.html +1 -2
  253. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1 -2
  254. nautobot/project-static/docs/models/dcim/powerpanel.html +1 -2
  255. nautobot/project-static/docs/models/dcim/powerport.html +1 -2
  256. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1 -2
  257. nautobot/project-static/docs/models/dcim/rack.html +1 -2
  258. nautobot/project-static/docs/models/dcim/rackgroup.html +1 -2
  259. nautobot/project-static/docs/models/dcim/rackreservation.html +1 -2
  260. nautobot/project-static/docs/models/dcim/rearport.html +1 -2
  261. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1 -2
  262. nautobot/project-static/docs/models/dcim/softwareimagefile.html +1 -2
  263. nautobot/project-static/docs/models/dcim/softwareversion.html +1 -2
  264. nautobot/project-static/docs/models/dcim/virtualchassis.html +1 -2
  265. nautobot/project-static/docs/models/extras/computedfield.html +1 -2
  266. nautobot/project-static/docs/models/extras/configcontext.html +1 -2
  267. nautobot/project-static/docs/models/extras/configcontextschema.html +1 -2
  268. nautobot/project-static/docs/models/extras/contact.html +1 -2
  269. nautobot/project-static/docs/models/extras/customfield.html +1 -2
  270. nautobot/project-static/docs/models/extras/customlink.html +1 -2
  271. nautobot/project-static/docs/models/extras/dynamicgroup.html +1 -2
  272. nautobot/project-static/docs/models/extras/exporttemplate.html +1 -2
  273. nautobot/project-static/docs/models/extras/gitrepository.html +1 -2
  274. nautobot/project-static/docs/models/extras/jobhook.html +1 -2
  275. nautobot/project-static/docs/models/extras/joblogentry.html +1 -2
  276. nautobot/project-static/docs/models/extras/jobresult.html +1 -2
  277. nautobot/project-static/docs/models/extras/metadatachoice.html +1 -2
  278. nautobot/project-static/docs/models/extras/metadatatype.html +1 -2
  279. nautobot/project-static/docs/models/extras/objectmetadata.html +1 -2
  280. nautobot/project-static/docs/models/extras/role.html +1 -2
  281. nautobot/project-static/docs/models/extras/savedview.html +1 -2
  282. nautobot/project-static/docs/models/extras/secret.html +1 -2
  283. nautobot/project-static/docs/models/extras/secretsgroup.html +1 -2
  284. nautobot/project-static/docs/models/extras/staticgroupassociation.html +1 -2
  285. nautobot/project-static/docs/models/extras/status.html +1 -2
  286. nautobot/project-static/docs/models/extras/team.html +1 -2
  287. nautobot/project-static/docs/models/ipam/ipaddress.html +1 -2
  288. nautobot/project-static/docs/models/ipam/prefix.html +1 -2
  289. nautobot/project-static/docs/models/ipam/rir.html +1 -2
  290. nautobot/project-static/docs/models/ipam/routetarget.html +1 -2
  291. nautobot/project-static/docs/models/ipam/service.html +1 -2
  292. nautobot/project-static/docs/models/ipam/vlan.html +1 -2
  293. nautobot/project-static/docs/models/ipam/vlangroup.html +1 -2
  294. nautobot/project-static/docs/models/ipam/vrf.html +1 -2
  295. nautobot/project-static/docs/models/tenancy/tenant.html +1 -2
  296. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1 -2
  297. nautobot/project-static/docs/models/virtualization/cluster.html +1 -2
  298. nautobot/project-static/docs/models/virtualization/clustergroup.html +1 -2
  299. nautobot/project-static/docs/models/virtualization/clustertype.html +1 -2
  300. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1 -2
  301. nautobot/project-static/docs/models/virtualization/vminterface.html +1 -2
  302. nautobot/project-static/docs/objects.inv +0 -0
  303. nautobot/project-static/docs/overview/application_stack.html +10 -10
  304. nautobot/project-static/docs/overview/design_philosophy.html +10 -10
  305. nautobot/project-static/docs/overview/index.html +1 -2
  306. nautobot/project-static/docs/plugins/development.html +1 -2
  307. nautobot/project-static/docs/plugins/index.html +1 -2
  308. nautobot/project-static/docs/plugins/porting-from-netbox.html +1 -2
  309. nautobot/project-static/docs/release-notes/index.html +15 -15
  310. nautobot/project-static/docs/release-notes/version-1.0.html +10 -10
  311. nautobot/project-static/docs/release-notes/version-1.1.html +10 -10
  312. nautobot/project-static/docs/release-notes/version-1.2.html +10 -10
  313. nautobot/project-static/docs/release-notes/version-1.3.html +10 -10
  314. nautobot/project-static/docs/release-notes/version-1.4.html +10 -10
  315. nautobot/project-static/docs/release-notes/version-1.5.html +10 -10
  316. nautobot/project-static/docs/release-notes/version-1.6.html +10 -10
  317. nautobot/project-static/docs/release-notes/version-2.0.html +10 -10
  318. nautobot/project-static/docs/release-notes/version-2.1.html +10 -10
  319. nautobot/project-static/docs/release-notes/version-2.2.html +10 -10
  320. nautobot/project-static/docs/release-notes/version-2.3.html +491 -182
  321. nautobot/project-static/docs/requirements.txt +2 -2
  322. nautobot/project-static/docs/rest-api/overview.html +1 -2
  323. nautobot/project-static/docs/search/search_index.json +1 -1
  324. nautobot/project-static/docs/sitemap.xml +270 -270
  325. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  326. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +10 -10
  327. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +10 -10
  328. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +65 -12
  329. nautobot/project-static/docs/user-guide/administration/configuration/index.html +10 -10
  330. nautobot/project-static/docs/user-guide/administration/configuration/node-configuration.html +1 -2
  331. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +1 -2
  332. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +10 -10
  333. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +1 -2
  334. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +122 -10
  335. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +10 -10
  336. nautobot/project-static/docs/user-guide/administration/guides/caching.html +1 -2
  337. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +10 -10
  338. nautobot/project-static/docs/user-guide/administration/guides/docker.html +10 -10
  339. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +10 -10
  340. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +1 -2
  341. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +10 -10
  342. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +10 -10
  343. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +10 -10
  344. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +49 -10
  345. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +10 -10
  346. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +10 -10
  347. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +10 -10
  348. nautobot/project-static/docs/user-guide/administration/installation/docker.html +1 -2
  349. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +10 -10
  350. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +1 -2
  351. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +10 -10
  352. nautobot/project-static/docs/user-guide/administration/installation/index.html +10 -10
  353. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +10 -10
  354. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +10 -10
  355. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +1 -2
  356. nautobot/project-static/docs/user-guide/administration/installation/services.html +10 -10
  357. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +1 -2
  358. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +1 -2
  359. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +1 -2
  360. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +10 -10
  361. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +10 -10
  362. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +10 -10
  363. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +10 -10
  364. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +10 -10
  365. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +10 -10
  366. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +10 -10
  367. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +10 -10
  368. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +10 -10
  369. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +10 -10
  370. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +10 -10
  371. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +10 -10
  372. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +10 -10
  373. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +10 -10
  374. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +10 -10
  375. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +10 -10
  376. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +10 -10
  377. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +10 -10
  378. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +10 -10
  379. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +10 -10
  380. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +10 -10
  381. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +10 -10
  382. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +10 -10
  383. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +10 -10
  384. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +10 -10
  385. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +10 -10
  386. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +10 -10
  387. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +10 -10
  388. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +10 -10
  389. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +10 -10
  390. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +10 -10
  391. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +10 -10
  392. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +10 -10
  393. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +10 -10
  394. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +10 -10
  395. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +10 -10
  396. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +10 -10
  397. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +10 -10
  398. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +10 -10
  399. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +10 -10
  400. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +10 -10
  401. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +10 -10
  402. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +10 -10
  403. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +10 -10
  404. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +10 -10
  405. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +10 -10
  406. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +10 -10
  407. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +10 -10
  408. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +10 -10
  409. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +10 -10
  410. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +10 -10
  411. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +10 -10
  412. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +10 -10
  413. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +10 -10
  414. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +10 -10
  415. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +10 -10
  416. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +10 -10
  417. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +10 -10
  418. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +10 -10
  419. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +10 -10
  420. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +10 -10
  421. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +10 -10
  422. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +10 -10
  423. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +10 -10
  424. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +10 -10
  425. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +10 -10
  426. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +10 -10
  427. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +10 -10
  428. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +10 -10
  429. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +10 -10
  430. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +10 -10
  431. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +10 -10
  432. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +10 -10
  433. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +10 -10
  434. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +10 -10
  435. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +10 -10
  436. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +10 -10
  437. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +10 -10
  438. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +10 -10
  439. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +10 -10
  440. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +10 -10
  441. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +10 -10
  442. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +10 -10
  443. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +10 -10
  444. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +10 -10
  445. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +10 -10
  446. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +10 -10
  447. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +10 -10
  448. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +10 -10
  449. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +10 -10
  450. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +10 -10
  451. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +10 -10
  452. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +10 -10
  453. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +10 -10
  454. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +10 -10
  455. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +10 -10
  456. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +10 -10
  457. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +10 -10
  458. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +10 -10
  459. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +10 -10
  460. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +10 -10
  461. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +10 -10
  462. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +10 -10
  463. nautobot/project-static/docs/user-guide/index.html +10 -10
  464. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +10 -10
  465. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +10 -10
  466. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +10 -10
  467. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +10 -10
  468. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +10 -10
  469. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +10 -10
  470. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +10 -10
  471. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +10 -10
  472. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +10 -10
  473. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +10 -10
  474. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +10 -10
  475. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +10 -10
  476. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +10 -10
  477. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +10 -10
  478. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +10 -10
  479. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +10 -10
  480. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +10 -10
  481. nautobot/project-static/docs/user-guide/platform-functionality/note.html +10 -10
  482. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +10 -10
  483. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +10 -10
  484. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +10 -10
  485. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +10 -10
  486. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +10 -10
  487. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +10 -10
  488. nautobot/project-static/docs/user-guide/platform-functionality/role.html +10 -10
  489. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +10 -10
  490. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +10 -10
  491. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +10 -10
  492. nautobot/project-static/docs/user-guide/platform-functionality/status.html +10 -10
  493. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +10 -10
  494. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +10 -10
  495. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +10 -10
  496. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +10 -10
  497. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +10 -10
  498. nautobot/project-static/docs/user-guides/custom-fields.html +1 -2
  499. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1 -2
  500. nautobot/project-static/docs/user-guides/getting-started/index.html +1 -2
  501. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1 -2
  502. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1 -2
  503. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1 -2
  504. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1 -2
  505. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1 -2
  506. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1 -2
  507. nautobot/project-static/docs/user-guides/git-data-source.html +1 -2
  508. nautobot/project-static/docs/user-guides/graphql.html +1 -2
  509. nautobot/project-static/docs/user-guides/ip-address-merge-tool.html +1 -2
  510. nautobot/project-static/docs/user-guides/relationships.html +1 -2
  511. nautobot/project-static/docs/user-guides/s3-django-storage.html +1 -2
  512. nautobot/project-static/js/forms.js +10 -0
  513. nautobot/virtualization/forms.py +24 -0
  514. nautobot/virtualization/templates/virtualization/vminterface.html +4 -0
  515. nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
  516. nautobot/virtualization/tests/test_views.py +7 -2
  517. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/METADATA +2 -2
  518. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/RECORD +522 -520
  519. nautobot/project-static/docs/assets/stylesheets/main.0253249f.min.css +0 -1
  520. nautobot/project-static/docs/assets/stylesheets/main.0253249f.min.css.map +0 -1
  521. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/LICENSE.txt +0 -0
  522. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/NOTICE +0 -0
  523. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/WHEEL +0 -0
  524. {nautobot-2.3.10.dist-info → nautobot-2.3.12.dist-info}/entry_points.txt +0 -0
@@ -414,7 +414,7 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
414
414
  else:
415
415
  # render the form with the error message.
416
416
  data = {}
417
- if self.action in ["bulk_update", "bulk_destroy"]:
417
+ if not request.POST.get("_all") and self.action in ["bulk_update", "bulk_destroy"]:
418
418
  pk_list = self.pk_list
419
419
  table_class = self.get_table_class()
420
420
  table = table_class(queryset.filter(pk__in=pk_list), orderable=False)
@@ -578,6 +578,9 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
578
578
  if not form_class:
579
579
  if self.action == "bulk_destroy":
580
580
  queryset = self.get_queryset()
581
+ bulk_delete_all = bool(self.request.POST.get("_all"))
582
+ if bulk_delete_all:
583
+ return ConfirmationForm
581
584
 
582
585
  class BulkDestroyForm(ConfirmationForm):
583
586
  pk = ModelMultipleChoiceField(queryset=queryset, widget=MultipleHiddenInput)
@@ -909,7 +912,48 @@ class ObjectEditViewMixin(NautobotViewSetMixin, mixins.CreateModelMixin, mixins.
909
912
  return self.form_invalid(form)
910
913
 
911
914
 
912
- class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin):
915
+ class EditAndDeleteAllModelMixin:
916
+ """
917
+ UI mixin to bulk destroy all and bulk edit all model instances.
918
+ """
919
+
920
+ def _get_bulk_edit_delete_all_queryset(self, request):
921
+ """
922
+ Retrieve the queryset of model instances to be bulk-deleted or bulk-deleted, filtered based on request parameters.
923
+
924
+ This method handles the retrieval of a queryset of model instances that match the specified
925
+ filter criteria in the request parameters, allowing a bulk delete operation to be performed
926
+ on all matching instances.
927
+ """
928
+ model = self.queryset.model
929
+
930
+ # This Mixin is currently been used by both NautobotUIViewSet ObjectBulkDestroyViewMixin, ObjectBulkUpdateViewMixin
931
+ # BulkEditView, and BulkDeleteView which uses different keys for accessing filterset
932
+ filterset_class = getattr(self, "filterset", None)
933
+ if filterset_class is None:
934
+ filterset_class = getattr(self, "filterset_class", None)
935
+
936
+ if request.GET and filterset_class is not None:
937
+ queryset = filterset_class(request.GET, model.objects.all()).qs
938
+ # We take this approach because filterset.qs has already applied .distinct(),
939
+ # and performing a .delete directly on a queryset with .distinct applied is not allowed.
940
+ queryset = self.queryset.filter(pk__in=queryset)
941
+ else:
942
+ queryset = model.objects.all()
943
+ return queryset
944
+
945
+ def _bulk_delete_all_context(self, request, queryset):
946
+ model = queryset.model
947
+ return {
948
+ "obj_type_plural": model._meta.verbose_name_plural,
949
+ "return_url": self.get_return_url(request),
950
+ "total_objs_to_delete": queryset.count(),
951
+ "delete_all": True,
952
+ "table": None,
953
+ }
954
+
955
+
956
+ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, EditAndDeleteAllModelMixin):
913
957
  """
914
958
  UI mixin to bulk destroy model instances.
915
959
  """
@@ -923,7 +967,10 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin):
923
967
  queryset = self.get_queryset()
924
968
  model = queryset.model
925
969
  # Delete objects
926
- queryset = queryset.filter(pk__in=pk_list)
970
+ if self.request.POST.get("_all"):
971
+ queryset = self._get_bulk_edit_delete_all_queryset(self.request)
972
+ else:
973
+ queryset = queryset.filter(pk__in=pk_list)
927
974
 
928
975
  try:
929
976
  with transaction.atomic():
@@ -951,35 +998,33 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin):
951
998
  request.POST "_confirm": Function to validate the table form/BulkDestroyConfirmationForm and to perform the action of bulk destroy. Render the form with errors if exceptions are raised.
952
999
  """
953
1000
  queryset = self.get_queryset()
954
- model = queryset.model
1001
+ delete_all = bool(request.POST.get("_all"))
1002
+ data = {}
955
1003
  # Are we deleting *all* objects in the queryset or just a selected subset?
956
- if request.POST.get("_all"):
957
- if self.filterset_class is not None:
958
- self.pk_list = list(
959
- self.filterset_class(request.GET, model.objects.only("pk")).qs.values_list("pk", flat=True)
960
- )
961
- else:
962
- self.pk_list = list(model.objects.all().values_list("pk", flat=True))
1004
+ if delete_all:
1005
+ queryset = self._get_bulk_edit_delete_all_queryset(self.request)
1006
+ data = self._bulk_delete_all_context(request, queryset)
963
1007
  else:
964
1008
  self.pk_list = list(request.POST.getlist("pk"))
1009
+
965
1010
  form_class = self.get_form_class(**kwargs)
966
- data = {}
967
1011
  if "_confirm" in request.POST:
968
1012
  form = form_class(request.POST, initial=normalize_querydict(request.GET, form_class=form_class))
969
1013
  if form.is_valid():
970
1014
  return self.form_valid(form)
971
1015
  else:
972
1016
  return self.form_invalid(form)
973
- table_class = self.get_table_class()
974
- table = table_class(queryset.filter(pk__in=self.pk_list), orderable=False)
975
- if not table.rows:
976
- messages.warning(
977
- request,
978
- f"No {queryset.model._meta.verbose_name_plural} were selected for deletion.",
979
- )
980
- return redirect(self.get_return_url(request))
1017
+ if not delete_all:
1018
+ table_class = self.get_table_class()
1019
+ table = table_class(queryset.filter(pk__in=self.pk_list), orderable=False)
1020
+ if not table.rows:
1021
+ messages.warning(
1022
+ request,
1023
+ f"No {queryset.model._meta.verbose_name_plural} were selected for deletion.",
1024
+ )
1025
+ return redirect(self.get_return_url(request))
981
1026
 
982
- data.update({"table": table})
1027
+ data.update({"table": table})
983
1028
  return Response(data)
984
1029
 
985
1030
 
@@ -1037,7 +1082,7 @@ class ObjectBulkCreateViewMixin(NautobotViewSetMixin): # 3.0 TODO: remove, unus
1037
1082
  return self.form_invalid(form)
1038
1083
 
1039
1084
 
1040
- class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin):
1085
+ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, EditAndDeleteAllModelMixin):
1041
1086
  """
1042
1087
  UI mixin to bulk update model instances.
1043
1088
  """
@@ -1062,7 +1107,13 @@ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin):
1062
1107
  nullified_fields = request.POST.getlist("_nullify")
1063
1108
  with deferred_change_logging_for_bulk_operation():
1064
1109
  updated_objects = []
1065
- for obj in queryset.filter(pk__in=form.cleaned_data["pk"]):
1110
+ edit_all = self.request.POST.get("_all")
1111
+
1112
+ if edit_all:
1113
+ queryset = self._get_bulk_edit_delete_all_queryset(self.request)
1114
+ else:
1115
+ queryset = queryset.filter(pk__in=form.cleaned_data["pk"])
1116
+ for obj in queryset:
1066
1117
  self.obj = obj
1067
1118
  # Update standard fields. If a field is listed in _nullify, delete its value.
1068
1119
  for name in standard_fields:
@@ -1133,38 +1184,41 @@ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin):
1133
1184
  request.POST "_edit": Function to render the user selection of objects in a table form/BulkUpdateForm via Response that is passed to NautobotHTMLRenderer.
1134
1185
  request.POST "_apply": Function to validate the table form/BulkUpdateForm and to perform the action of bulk update. Render the form with errors if exceptions are raised.
1135
1186
  """
1136
- queryset = self.get_queryset()
1137
- model = queryset.model
1187
+ edit_all = request.POST.get("_all")
1138
1188
 
1139
- # If we are editing *all* objects in the queryset, replace the PK list with all matched objects.
1140
- if request.POST.get("_all"):
1141
- if self.filterset_class is not None:
1142
- self.pk_list = list(
1143
- self.filterset_class(request.GET, model.objects.only("pk")).qs.values_list("pk", flat=True)
1144
- )
1145
- else:
1146
- self.pk_list = list(model.objects.all().values_list("pk", flat=True))
1189
+ if edit_all:
1190
+ self.pk_list = None
1191
+ queryset = self._get_bulk_edit_delete_all_queryset(request)
1147
1192
  else:
1148
1193
  self.pk_list = list(request.POST.getlist("pk"))
1194
+ queryset = self.get_queryset().filter(pk__in=self.pk_list)
1195
+
1149
1196
  data = {}
1150
1197
  form_class = self.get_form_class()
1151
1198
  if "_apply" in request.POST:
1152
1199
  self.kwargs = kwargs
1153
- form = form_class(queryset.model, request.POST)
1200
+ form = form_class(queryset.model, request.POST, edit_all=edit_all)
1154
1201
  restrict_form_fields(form, request.user)
1155
1202
  if form.is_valid():
1156
1203
  return self.form_valid(form)
1157
1204
  else:
1158
1205
  return self.form_invalid(form)
1159
- table_class = self.get_table_class()
1160
- table = table_class(queryset.filter(pk__in=self.pk_list), orderable=False)
1161
- if not table.rows:
1162
- messages.warning(
1163
- request,
1164
- f"No {queryset.model._meta.verbose_name_plural} were selected to update.",
1165
- )
1166
- return redirect(self.get_return_url(request))
1167
- data.update({"table": table})
1206
+ table = None
1207
+ if not edit_all:
1208
+ table_class = self.get_table_class()
1209
+ table = table_class(queryset, orderable=False)
1210
+ if not table.rows:
1211
+ messages.warning(
1212
+ request,
1213
+ f"No {queryset.model._meta.verbose_name_plural} were selected to update.",
1214
+ )
1215
+ return redirect(self.get_return_url(request))
1216
+ data.update(
1217
+ {
1218
+ "table": table,
1219
+ "objs_count": queryset.count(),
1220
+ }
1221
+ )
1168
1222
  return Response(data)
1169
1223
 
1170
1224
 
@@ -249,19 +249,22 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
249
249
  "return_url": return_url,
250
250
  }
251
251
  form = form_class(initial=initial)
252
- table = self.construct_table(view, pk_list=pk_list)
252
+ delete_all = request.POST.get("_all")
253
+ if not delete_all:
254
+ table = self.construct_table(view, pk_list=pk_list)
253
255
  elif view.action == "bulk_create": # 3.0 TODO: remove, replaced by ImportObjects system Job
254
256
  form = view.get_form()
255
257
  if request.data:
256
258
  table = data.get("table")
257
259
  elif view.action == "bulk_update":
260
+ edit_all = request.POST.get("_all")
258
261
  pk_list = getattr(view, "pk_list", [])
259
- if pk_list:
262
+ if pk_list or edit_all:
260
263
  initial_data = {"pk": pk_list}
261
- form = form_class(model, initial=initial_data)
262
-
264
+ form = form_class(model, initial=initial_data, edit_all=edit_all)
263
265
  restrict_form_fields(form, request.user)
264
- table = self.construct_table(view, pk_list=pk_list)
266
+ if not edit_all:
267
+ table = self.construct_table(view, pk_list=pk_list)
265
268
  elif view.action == "notes":
266
269
  initial_data = {
267
270
  "assigned_object_type": content_type,
nautobot/dcim/choices.py CHANGED
@@ -804,6 +804,9 @@ class InterfaceTypeChoices(ChoiceSet):
804
804
  TYPE_400GE_CFP8 = "400gbase-x-cfp8"
805
805
  TYPE_800GE_QSFP_DD = "800gbase-x-qsfpdd"
806
806
  TYPE_800GE_OSFP = "800gbase-x-osfp"
807
+ TYPE_800GE_OSFP_XD = "800gbase-x-osfp-xd"
808
+ TYPE_1600GE_OSFP = "1600gbase-x-osfp"
809
+ TYPE_1600GE_OSFP_XD = "1600gbase-x-osfp-xd"
807
810
 
808
811
  # Ethernet Backplane
809
812
  TYPE_1GE_KX = "1000base-kx"
@@ -977,6 +980,9 @@ class InterfaceTypeChoices(ChoiceSet):
977
980
  (TYPE_400GE_CFP8, "CPF8 (400GE)"),
978
981
  (TYPE_800GE_QSFP_DD, "QSFP-DD (800GE)"),
979
982
  (TYPE_800GE_OSFP, "OSFP (800GE)"),
983
+ (TYPE_800GE_OSFP_XD, "OSFP-XD (800GE)"),
984
+ (TYPE_1600GE_OSFP, "OSFP (1600GE)"),
985
+ (TYPE_1600GE_OSFP_XD, "OSFP-XD (1600GE)"),
980
986
  ),
981
987
  ),
982
988
  (
@@ -220,13 +220,11 @@ class DeviceTable(StatusTableMixin, RoleTableMixin, BaseTable):
220
220
  )
221
221
 
222
222
 
223
- class DeviceImportTable(BaseTable):
223
+ class DeviceImportTable(StatusTableMixin, RoleTableMixin, BaseTable):
224
224
  name = tables.TemplateColumn(template_code=DEVICE_LINK)
225
- status = ColoredLabelColumn()
226
225
  tenant = TenantColumn()
227
226
  location = tables.Column(linkify=True)
228
227
  rack = tables.Column(linkify=True)
229
- role = tables.Column(verbose_name="Role")
230
228
  device_type = tables.Column(verbose_name="Type")
231
229
 
232
230
  class Meta(BaseTable.Meta):
@@ -1277,6 +1275,9 @@ class SoftwareImageFileTable(StatusTableMixin, BaseTable):
1277
1275
  class SoftwareVersionTable(StatusTableMixin, BaseTable):
1278
1276
  pk = ToggleColumn()
1279
1277
  version = tables.Column(linkify=True)
1278
+ platform = tables.Column(linkify=True)
1279
+ release_date = tables.DateColumn()
1280
+ end_of_support_date = tables.DateColumn()
1280
1281
  software_image_file_count = LinkedCountColumn(
1281
1282
  viewname="dcim:softwareimagefile_list",
1282
1283
  url_params={"software_version": "pk"},
@@ -1330,15 +1331,13 @@ class SoftwareVersionTable(StatusTableMixin, BaseTable):
1330
1331
  )
1331
1332
 
1332
1333
 
1333
- class ControllerTable(BaseTable):
1334
+ class ControllerTable(StatusTableMixin, RoleTableMixin, BaseTable):
1334
1335
  """Table for list view."""
1335
1336
 
1336
1337
  pk = ToggleColumn()
1337
1338
  name = tables.Column(linkify=True)
1338
- status = ColoredLabelColumn()
1339
1339
  location = tables.Column(linkify=True)
1340
1340
  platform = tables.Column(linkify=True)
1341
- role = tables.Column(linkify=True)
1342
1341
  tenant = TenantColumn()
1343
1342
  external_integration = tables.Column(linkify=True)
1344
1343
  controller_device = tables.Column(linkify=True)
@@ -20,7 +20,7 @@
20
20
  </tr>
21
21
  <tr>
22
22
  <td>Role</td>
23
- <td>{{ object.role|hyperlinked_object }}</td>
23
+ <td>{{ object.role|hyperlinked_object_with_color }}</td>
24
24
  </tr>
25
25
  <tr>
26
26
  <td>Location</td>
@@ -58,7 +58,7 @@
58
58
  <span class="hover_copy">
59
59
  <h1>
60
60
  <span id="devicename">{% block title %}{{ object }}{% endblock title %}</span>
61
- <button class="btn btn-xs btn-default hover_copy_button" data-clipboard-target="#devicename">
61
+ <button class="btn btn-xs btn-default hover_copy_button" data-clipboard-text="{{ object }}">
62
62
  <span class="mdi mdi-content-copy"></span>
63
63
  </button>
64
64
  </h1>
@@ -7,7 +7,7 @@
7
7
  <form action="" method="post" class="form form-horizontal">
8
8
  {% csrf_token %}
9
9
  <div class="row">
10
- <div class="col-md-6 col-md-offset-3">
10
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
11
11
  {% if form.non_field_errors %}
12
12
  <div class="panel panel-danger">
13
13
  <div class="panel-heading"><strong>Errors</strong></div>
@@ -25,13 +25,13 @@
25
25
  </div>
26
26
  </div>
27
27
  {% include 'inc/extras_features_edit_form_fields.html' with form=model_form %}
28
- <div class="form-group">
29
- <div class="col-md-9 col-md-offset-3 text-right">
30
- <button type="submit" name="_create" class="btn btn-primary">Create</button>
31
- <button type="submit" name="_addanother" class="btn btn-primary">Create and Add More</button>
32
- <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
33
- </div>
34
- </div>
28
+ </div>
29
+ </div>
30
+ <div class="row">
31
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 text-right">
32
+ <button type="submit" name="_create" class="btn btn-primary">Create</button>
33
+ <button type="submit" name="_addanother" class="btn btn-primary">Create and Add More</button>
34
+ <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
35
35
  </div>
36
36
  </div>
37
37
  </form>
@@ -5,7 +5,7 @@
5
5
  <form action="" method="post" enctype="multipart/form-data" class="form form-horizontal">
6
6
  {% csrf_token %}
7
7
  <div class="row">
8
- <div class="col-md-6 col-md-offset-3">
8
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
9
9
  <h3>{% block title %}Add New Member to Virtual Chassis {{ virtual_chassis }}{% endblock %}</h3>
10
10
  {% if membership_form.non_field_errors %}
11
11
  <div class="panel panel-danger">
@@ -25,7 +25,7 @@
25
25
  </div>
26
26
  </div>
27
27
  <div class="row">
28
- <div class="col-md-6 col-md-offset-3 text-right">
28
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 text-right">
29
29
  <button type="submit" name="_save" class="btn btn-primary">Save</button>
30
30
  <button type="submit" name="_addanother" class="btn btn-primary">Add Another</button>
31
31
  <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
@@ -8,7 +8,7 @@
8
8
  {{ pk_form.pk }}
9
9
  {{ formset.management_form }}
10
10
  <div class="row">
11
- <div class="col-md-8 col-md-offset-2">
11
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
12
12
  <h3>{% block title %}{% if vc_form.instance %}Editing {{ vc_form.instance }}{% else %}New Virtual Chassis{% endif %}{% endblock %}</h3>
13
13
  {% if vc_form.non_field_errors %}
14
14
  <div class="panel panel-danger">
@@ -84,7 +84,7 @@
84
84
  </div>
85
85
  </div>
86
86
  <div class="row">
87
- <div class="col-md-8 col-md-offset-2 text-right">
87
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 text-right">
88
88
  <button type="submit" name="_update" class="btn btn-primary">Update</button>
89
89
  <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
90
90
  </div>
@@ -0,0 +1,86 @@
1
+ from django.urls import reverse
2
+
3
+ from nautobot.core.testing.integration import SeleniumTestCase
4
+
5
+
6
+ class CreateDeviceTestCase(SeleniumTestCase):
7
+ """
8
+ Create a device and all pre-requisite objects through the UI.
9
+ """
10
+
11
+ def test_create_device(self):
12
+ """
13
+ This test goes through the process of creating a device in the UI. All pre-requisite objects are created:
14
+ - Manufacturer
15
+ - Device Type
16
+ - LocationType
17
+ - Location
18
+ - Role
19
+ - Device
20
+
21
+ """
22
+ self.user.is_superuser = True
23
+ self.user.save()
24
+ self.login(self.user.username, self.password)
25
+
26
+ # Manufacturer
27
+ self.click_navbar_entry("Devices", "Manufacturers")
28
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:manufacturer_list"))
29
+ self.click_list_view_add_button()
30
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:manufacturer_add"))
31
+ self.browser.fill("name", "Test Manufacturer 1")
32
+ self.click_edit_form_create_button()
33
+
34
+ # Device Type
35
+ self.click_navbar_entry("Devices", "Device Types")
36
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:devicetype_list"))
37
+ self.click_list_view_add_button()
38
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:devicetype_add"))
39
+ self.fill_select2_field("manufacturer", "Test Manufacturer 1")
40
+ self.browser.fill("model", "Test Device Type 1")
41
+ self.click_edit_form_create_button()
42
+
43
+ # LocationType
44
+ self.click_navbar_entry("Organization", "Location Types")
45
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:locationtype_list"))
46
+ self.click_list_view_add_button()
47
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:locationtype_add"))
48
+ self.fill_select2_multiselect_field("content_types", "dcim | device")
49
+ self.browser.fill("name", "Test Location Type 1")
50
+ self.click_edit_form_create_button()
51
+
52
+ # Location
53
+ self.click_navbar_entry("Organization", "Locations")
54
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:location_list"))
55
+ self.click_list_view_add_button()
56
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:location_add"))
57
+ self.fill_select2_field("location_type", "Test Location Type 1")
58
+ self.fill_select2_field("status", "") # pick first status
59
+ self.browser.fill("name", "Test Location 1")
60
+ self.click_edit_form_create_button()
61
+
62
+ # Role
63
+ self.click_navbar_entry("Organization", "Roles")
64
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("extras:role_list"))
65
+ self.click_list_view_add_button()
66
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("extras:role_add"))
67
+ self.browser.fill("name", "Test Role 1")
68
+ self.fill_select2_multiselect_field("content_types", "dcim | device")
69
+ self.click_edit_form_create_button()
70
+
71
+ # Device
72
+ self.click_navbar_entry("Devices", "Devices")
73
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:device_list"))
74
+ self.click_list_view_add_button()
75
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("dcim:device_add"))
76
+ self.browser.fill("name", "Test Device Integration Test 1")
77
+ self.fill_select2_field("role", "Test Role 1")
78
+ self.fill_select2_field("device_type", "Test Device Type 1")
79
+ self.fill_select2_field("location", "Test Location 1")
80
+ self.fill_select2_field("status", "") # pick first status
81
+ self.click_edit_form_create_button()
82
+
83
+ # Assert that the device was created
84
+ self.assertTrue(self.browser.is_text_present("Created device Test Device Integration Test 1", wait_time=5))
85
+ self.assertTrue(self.browser.is_text_present("Test Location 1", wait_time=5))
86
+ self.assertTrue(self.browser.is_text_present("Test Device Type 1", wait_time=5))
@@ -0,0 +1,42 @@
1
+ """Additional functions to process an OAuth2/OIDC user."""
2
+
3
+ import logging
4
+
5
+ from django.conf import settings
6
+ from django.contrib.auth.models import Group
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ CLAIMS_GROUP_NAME = getattr(settings, "NAUTOBOT_SSO_CLAIMS_GROUP", "groups")
12
+ """ Which claim to look at in the OAuth2/OIDC response
13
+
14
+ For Okta you can look at `Okta -> Authorization Servers -> Claims`. And a reasonable
15
+ default is "groups". For Azure a reasonable default is "roles".
16
+ """
17
+
18
+ SUPERUSER_GROUPS = getattr(settings, "NAUTOBOT_SSO_SUPERUSER_GROUPS", [])
19
+ STAFF_GROUPS = getattr(settings, "NAUTOBOT_SSO_STAFF_GROUPS", [])
20
+
21
+
22
+ def group_sync(uid, user=None, response=None, *args, **kwargs):
23
+ """Sync the users groups from OAuth2/OIDC auth and set staff/superuser as appropriate."""
24
+ if user and response and CLAIMS_GROUP_NAME and response.get(CLAIMS_GROUP_NAME, False):
25
+ group_memberships = response.get(CLAIMS_GROUP_NAME)
26
+ is_staff = False
27
+ is_superuser = False
28
+ logger.debug(f"User {uid} is a member of {', '.join(group_memberships)}")
29
+ # Make sure all groups exist in Nautobot
30
+ group_ids = []
31
+ for group in group_memberships:
32
+ if group in SUPERUSER_GROUPS:
33
+ is_superuser = True
34
+ if group in STAFF_GROUPS:
35
+ is_staff = True
36
+ group_ids.append(Group.objects.get_or_create(name=group)[0].id)
37
+ user.groups.set(group_ids)
38
+ user.is_superuser = is_superuser
39
+ user.is_staff = is_staff
40
+ user.save()
41
+ else:
42
+ logger.debug(f"Did not receive groups from OAuth2/OIDC, response: {response}")
@@ -201,6 +201,7 @@ class ObjectMetadata(ChangeLoggedModel, BaseModel):
201
201
  objects = ObjectMetadataManager()
202
202
  natural_key_field_names = ["pk"]
203
203
  documentation_static_path = "docs/user-guide/platform-functionality/objectmetadata.html"
204
+ is_metadata_associable_model = False
204
205
 
205
206
  class Meta:
206
207
  ordering = ["metadata_type"]
@@ -831,7 +831,7 @@ class Note(ChangeLoggedModel, BaseModel):
831
831
  unique_together = [["assigned_object_type", "assigned_object_id", "user_name", "created"]]
832
832
 
833
833
  def __str__(self):
834
- return f"{self.assigned_object} - {self.created.isoformat()}"
834
+ return f"{self.assigned_object} - {self.created.isoformat() if self.created else None}"
835
835
 
836
836
  def save(self, *args, **kwargs):
837
837
  # Record the user's name as static strings
@@ -207,8 +207,9 @@ class NautobotAppConfig(NautobotConfig):
207
207
  override_views = import_object(f"{self.__module__}.{self.override_views}")
208
208
  if override_views is not None:
209
209
  for qualified_view_name, view in override_views.items():
210
+ view_class_name = view.view_class.__name__ if hasattr(view, "view_class") else view.cls.__name__
210
211
  self.features.setdefault("overridden_views", []).append(
211
- (qualified_view_name, f"{view.__module__}.{view.view_class.__name__}")
212
+ (qualified_view_name, f"{view.__module__}.{view_class_name}")
212
213
  )
213
214
  register_override_views(override_views, self.name)
214
215
 
nautobot/extras/tables.py CHANGED
@@ -978,6 +978,7 @@ class MetadataTypeTable(BaseTable):
978
978
 
979
979
  class ObjectMetadataTable(BaseTable):
980
980
  pk = ToggleColumn()
981
+ # NOTE: there is no identity column in this table; this is intentional as we have no detail view for ObjectMetadata
981
982
  metadata_type = tables.Column(linkify=True)
982
983
  assigned_object = tables.TemplateColumn(
983
984
  template_code=ASSIGNED_OBJECT, verbose_name="Assigned object", orderable=False
@@ -28,7 +28,7 @@
28
28
  </th>
29
29
  </tr>
30
30
  {% endifchanged %}
31
- <tr class="collapseme-{{ row.record.grouping|slugify }}{% if not perms.extras.run_job or not row.record.runnable %} disabled{% endif %} collapse in" data-parent="#accordion" {{ row.attrs.as_html }}>
31
+ <tr class="{% cycle 'even' 'odd' %} collapseme-{{ row.record.grouping|slugify }}{% if not perms.extras.run_job or not row.record.runnable %} disabled{% endif %} collapse in" data-parent="#accordion" {{ row.attrs.as_html }}>
32
32
  {% for column, cell in row.items %}
33
33
  <td {{ column.attrs.td.as_html }}>{{ cell }}</td>
34
34
  {% endfor %}
@@ -1395,6 +1395,7 @@ class RequiredRelationshipTestMixin:
1395
1395
  # Protected FK to SoftwareVersion prevents deletion
1396
1396
  Controller.objects.all().delete()
1397
1397
  Device.objects.all().update(software_version=None)
1398
+ Device.objects.all().delete()
1398
1399
 
1399
1400
  # Create required relationships:
1400
1401
  device_ct = ContentType.objects.get_for_model(Device)
@@ -3033,8 +3033,6 @@ class ObjectChangeTestCase(TestCase):
3033
3033
 
3034
3034
 
3035
3035
  class ObjectMetadataTestCase(
3036
- ViewTestCases.GetObjectViewTestCase,
3037
- ViewTestCases.GetObjectChangelogViewTestCase,
3038
3036
  ViewTestCases.ListObjectsViewTestCase,
3039
3037
  ):
3040
3038
  model = ObjectMetadata
nautobot/extras/views.py CHANGED
@@ -2228,8 +2228,6 @@ class MetadataTypeUIViewSet(NautobotUIViewSet):
2228
2228
 
2229
2229
 
2230
2230
  class ObjectMetadataUIViewSet(
2231
- ObjectChangeLogViewMixin,
2232
- ObjectDetailViewMixin,
2233
2231
  ObjectListViewMixin,
2234
2232
  ):
2235
2233
  filterset_class = filters.ObjectMetadataFilterSet
@@ -2846,6 +2844,7 @@ class StatusBulkDeleteView(generic.BulkDeleteView):
2846
2844
 
2847
2845
  queryset = Status.objects.all()
2848
2846
  table = tables.StatusTable
2847
+ filterset = filters.StatusFilterSet
2849
2848
 
2850
2849
 
2851
2850
  class StatusDeleteView(generic.ObjectDeleteView):
nautobot/ipam/factory.py CHANGED
@@ -238,6 +238,9 @@ class VLANFactory(PrimaryModelFactory):
238
238
  lambda: Location.objects.filter(location_type__content_types__in=[vlan_ct]), minimum=0
239
239
  )
240
240
  )
241
+ if self.vlan_group and self.vlan_group.location:
242
+ # add the parent of the vlan group location to the vlan locations
243
+ self.locations.add(self.vlan_group.location.ancestors(include_self=True)[0])
241
244
 
242
245
 
243
246
  class VLANGetOrCreateFactory(VLANFactory):
nautobot/ipam/filters.py CHANGED
@@ -90,6 +90,11 @@ class VRFFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyModelFil
90
90
  to_field_name="name",
91
91
  label="Device (ID or name)",
92
92
  )
93
+ virtual_machines = NaturalKeyOrPKMultipleChoiceFilter(
94
+ queryset=VirtualMachine.objects.all(),
95
+ to_field_name="name",
96
+ label="Virtual Machine (ID or name)",
97
+ )
93
98
  prefix = NaturalKeyOrPKMultipleChoiceFilter(
94
99
  field_name="prefixes",
95
100
  queryset=Prefix.objects.all(),