nautobot 2.4.11__py3-none-any.whl → 2.4.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 (354) hide show
  1. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -114
  2. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +1 -1
  3. nautobot/circuits/views.py +76 -6
  4. nautobot/cloud/navigation.py +1 -1
  5. nautobot/core/jobs/cleanup.py +4 -4
  6. nautobot/core/templates/components/panel/header_extra_content_table.html +12 -1
  7. nautobot/core/templates/components/panel/panel.html +4 -0
  8. nautobot/core/templates/generic/object_retrieve.html +1 -0
  9. nautobot/core/tests/test_utils.py +1 -177
  10. nautobot/core/tests/test_views.py +2 -2
  11. nautobot/core/ui/object_detail.py +1 -1
  12. nautobot/core/utils/module_loading.py +58 -63
  13. nautobot/dcim/filters/__init__.py +6 -0
  14. nautobot/dcim/filters/mixins.py +2 -1
  15. nautobot/dcim/models/devices.py +10 -0
  16. nautobot/dcim/tables/devices.py +2 -0
  17. nautobot/dcim/templates/dcim/controller/base.html +1 -9
  18. nautobot/dcim/templates/dcim/controller_retrieve.html +2 -83
  19. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +2 -25
  20. nautobot/dcim/templates/dcim/virtualchassis.html +2 -51
  21. nautobot/dcim/templates/dcim/virtualchassis_add.html +2 -22
  22. nautobot/dcim/templates/dcim/virtualchassis_create.html +22 -0
  23. nautobot/dcim/templates/dcim/virtualchassis_edit.html +2 -93
  24. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +51 -0
  25. nautobot/dcim/templates/dcim/virtualchassis_update.html +93 -0
  26. nautobot/dcim/urls.py +1 -58
  27. nautobot/dcim/views.py +145 -189
  28. nautobot/extras/datasources/git.py +2 -2
  29. nautobot/extras/jobs_ui.py +208 -0
  30. nautobot/extras/models/tags.py +4 -0
  31. nautobot/extras/tables.py +1 -1
  32. nautobot/extras/templates/extras/configcontextschema_retrieve.html +2 -2
  33. nautobot/extras/templates/extras/inc/configcontext_data.html +1 -1
  34. nautobot/extras/templates/extras/inc/configcontext_format.html +6 -0
  35. nautobot/extras/templates/extras/inc/json_data.html +1 -1
  36. nautobot/extras/templates/extras/inc/json_format.html +2 -2
  37. nautobot/extras/templates/extras/job_detail.html +1 -326
  38. nautobot/extras/templates/extras/tag_retrieve.html +1 -51
  39. nautobot/extras/views.py +80 -27
  40. nautobot/project-static/docs/404.html +2 -2
  41. nautobot/project-static/docs/apps/index.html +2 -2
  42. nautobot/project-static/docs/apps/nautobot-apps.html +2 -2
  43. nautobot/project-static/docs/assets/javascripts/{bundle.13a4f30d.min.js → bundle.56ea9cef.min.js} +2 -2
  44. nautobot/project-static/docs/assets/javascripts/{bundle.13a4f30d.min.js.map → bundle.56ea9cef.min.js.map} +2 -2
  45. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +2 -2
  46. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +2 -2
  47. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +2 -2
  48. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +2 -2
  49. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +2 -2
  50. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +2 -2
  51. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +2 -2
  52. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +2 -2
  53. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +2 -2
  54. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +2 -2
  55. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +2 -2
  56. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2 -2
  57. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2 -2
  58. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +2 -2
  59. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2 -2
  60. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2 -2
  61. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +2 -2
  62. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +2 -2
  63. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +2 -2
  64. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +2 -2
  65. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2 -2
  66. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +2 -2
  67. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2 -2
  68. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2 -2
  69. nautobot/project-static/docs/development/apps/api/configuration-view.html +2 -2
  70. nautobot/project-static/docs/development/apps/api/database-backend-config.html +2 -2
  71. nautobot/project-static/docs/development/apps/api/models/django-admin.html +2 -2
  72. nautobot/project-static/docs/development/apps/api/models/global-search.html +2 -2
  73. nautobot/project-static/docs/development/apps/api/models/graphql.html +2 -2
  74. nautobot/project-static/docs/development/apps/api/models/index.html +2 -2
  75. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +2 -2
  76. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +2 -2
  77. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +2 -2
  78. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +2 -2
  79. nautobot/project-static/docs/development/apps/api/platform-features/index.html +2 -2
  80. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +2 -2
  81. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +2 -2
  82. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +2 -2
  83. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +2 -2
  84. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +2 -2
  85. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +2 -2
  86. nautobot/project-static/docs/development/apps/api/prometheus.html +2 -2
  87. nautobot/project-static/docs/development/apps/api/setup.html +2 -2
  88. nautobot/project-static/docs/development/apps/api/testing.html +2 -2
  89. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +2 -2
  90. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +2 -2
  91. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +2 -2
  92. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +2 -2
  93. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +2 -2
  94. nautobot/project-static/docs/development/apps/api/views/base-template.html +2 -2
  95. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +2 -2
  96. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +2 -2
  97. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +2 -2
  98. nautobot/project-static/docs/development/apps/api/views/index.html +2 -2
  99. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +2 -2
  100. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +2 -2
  101. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +2 -2
  102. nautobot/project-static/docs/development/apps/api/views/notes.html +2 -2
  103. nautobot/project-static/docs/development/apps/api/views/rest-api.html +2 -2
  104. nautobot/project-static/docs/development/apps/api/views/urls.html +2 -2
  105. nautobot/project-static/docs/development/apps/index.html +2 -2
  106. nautobot/project-static/docs/development/apps/migration/code-updates.html +2 -2
  107. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +2 -2
  108. nautobot/project-static/docs/development/apps/migration/from-v1.html +2 -2
  109. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +2 -2
  110. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +2 -2
  111. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +2 -2
  112. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +2 -2
  113. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +2 -2
  114. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +2 -2
  115. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +2 -2
  116. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +2 -2
  117. nautobot/project-static/docs/development/apps/porting-from-netbox.html +2 -2
  118. nautobot/project-static/docs/development/core/application-registry.html +2 -2
  119. nautobot/project-static/docs/development/core/best-practices.html +2 -2
  120. nautobot/project-static/docs/development/core/bootstrap-ui.html +2 -2
  121. nautobot/project-static/docs/development/core/caching.html +2 -2
  122. nautobot/project-static/docs/development/core/controllers.html +2 -2
  123. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +2 -2
  124. nautobot/project-static/docs/development/core/generic-views.html +2 -2
  125. nautobot/project-static/docs/development/core/getting-started.html +2 -2
  126. nautobot/project-static/docs/development/core/homepage.html +2 -2
  127. nautobot/project-static/docs/development/core/index.html +2 -2
  128. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +2 -2
  129. nautobot/project-static/docs/development/core/model-checklist.html +2 -2
  130. nautobot/project-static/docs/development/core/model-features.html +2 -2
  131. nautobot/project-static/docs/development/core/natural-keys.html +2 -2
  132. nautobot/project-static/docs/development/core/navigation-menu.html +2 -2
  133. nautobot/project-static/docs/development/core/release-checklist.html +2 -2
  134. nautobot/project-static/docs/development/core/role-internals.html +2 -2
  135. nautobot/project-static/docs/development/core/settings.html +2 -2
  136. nautobot/project-static/docs/development/core/style-guide.html +2 -2
  137. nautobot/project-static/docs/development/core/templates.html +2 -2
  138. nautobot/project-static/docs/development/core/testing.html +2 -2
  139. nautobot/project-static/docs/development/core/ui-component-framework.html +2 -2
  140. nautobot/project-static/docs/development/core/user-preferences.html +2 -2
  141. nautobot/project-static/docs/development/index.html +2 -2
  142. nautobot/project-static/docs/development/jobs/getting-started.html +2 -6
  143. nautobot/project-static/docs/development/jobs/index.html +2 -2
  144. nautobot/project-static/docs/development/jobs/installation.html +2 -2
  145. nautobot/project-static/docs/development/jobs/job-extensions.html +2 -2
  146. nautobot/project-static/docs/development/jobs/job-logging.html +2 -2
  147. nautobot/project-static/docs/development/jobs/job-patterns.html +2 -2
  148. nautobot/project-static/docs/development/jobs/job-structure.html +2 -2
  149. nautobot/project-static/docs/development/jobs/migration/from-v1.html +2 -2
  150. nautobot/project-static/docs/development/jobs/testing.html +2 -2
  151. nautobot/project-static/docs/index.html +2 -2
  152. nautobot/project-static/docs/objects.inv +0 -0
  153. nautobot/project-static/docs/overview/application_stack.html +2 -2
  154. nautobot/project-static/docs/overview/design_philosophy.html +2 -2
  155. nautobot/project-static/docs/release-notes/index.html +2 -2
  156. nautobot/project-static/docs/release-notes/version-1.0.html +2 -2
  157. nautobot/project-static/docs/release-notes/version-1.1.html +2 -2
  158. nautobot/project-static/docs/release-notes/version-1.2.html +2 -2
  159. nautobot/project-static/docs/release-notes/version-1.3.html +2 -2
  160. nautobot/project-static/docs/release-notes/version-1.4.html +2 -2
  161. nautobot/project-static/docs/release-notes/version-1.5.html +2 -2
  162. nautobot/project-static/docs/release-notes/version-1.6.html +2 -2
  163. nautobot/project-static/docs/release-notes/version-2.0.html +2 -2
  164. nautobot/project-static/docs/release-notes/version-2.1.html +2 -2
  165. nautobot/project-static/docs/release-notes/version-2.2.html +2 -2
  166. nautobot/project-static/docs/release-notes/version-2.3.html +2 -2
  167. nautobot/project-static/docs/release-notes/version-2.4.html +111 -2
  168. nautobot/project-static/docs/requirements.txt +1 -1
  169. nautobot/project-static/docs/search/search_index.json +1 -1
  170. nautobot/project-static/docs/sitemap.xml +299 -299
  171. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  172. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +2 -2
  173. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +2 -2
  174. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +2 -2
  175. nautobot/project-static/docs/user-guide/administration/configuration/index.html +2 -2
  176. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +2 -2
  177. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +2 -2
  178. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +2 -2
  179. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +2 -2
  180. nautobot/project-static/docs/user-guide/administration/guides/docker.html +2 -2
  181. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +2 -2
  182. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +2 -2
  183. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +2 -2
  184. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +2 -2
  185. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +2 -2
  186. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +2 -2
  187. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +2 -2
  188. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +2 -2
  189. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +2 -2
  190. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +2 -2
  191. nautobot/project-static/docs/user-guide/administration/installation/index.html +2 -2
  192. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +2 -2
  193. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +2 -2
  194. nautobot/project-static/docs/user-guide/administration/installation/services.html +2 -2
  195. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +2 -2
  196. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +2 -2
  197. nautobot/project-static/docs/user-guide/administration/security/index.html +2 -2
  198. nautobot/project-static/docs/user-guide/administration/security/notices.html +2 -2
  199. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +2 -2
  200. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +2 -2
  201. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +2 -2
  202. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +2 -2
  203. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +2 -2
  204. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +2 -2
  205. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +2 -2
  206. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +2 -2
  207. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +2 -2
  208. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +2 -2
  209. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +2 -2
  210. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +2 -2
  211. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +2 -2
  212. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +2 -2
  213. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +2 -2
  214. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +2 -2
  215. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +2 -2
  216. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +2 -2
  217. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +2 -2
  218. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +2 -2
  219. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +2 -2
  220. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +2 -2
  221. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +2 -2
  222. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +2 -2
  223. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +2 -2
  224. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +2 -2
  225. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +2 -2
  226. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +2 -2
  227. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +2 -2
  228. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +2 -2
  229. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +2 -2
  230. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +2 -2
  231. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +2 -2
  232. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +2 -2
  233. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +2 -2
  234. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +2 -2
  235. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +2 -2
  236. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +2 -2
  237. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +2 -2
  238. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +2 -2
  239. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +2 -2
  240. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +2 -2
  241. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +2 -2
  242. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +2 -2
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +2 -2
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +2 -2
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +2 -2
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +2 -2
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +2 -2
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +2 -2
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +2 -2
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +2 -2
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +2 -2
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +2 -2
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +2 -2
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +2 -2
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +2 -2
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +2 -2
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +2 -2
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +2 -2
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +2 -2
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +2 -2
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +2 -2
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +2 -2
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +2 -2
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +2 -2
  265. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +2 -2
  266. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +2 -2
  267. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +2 -2
  268. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +2 -2
  269. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +2 -2
  270. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +2 -2
  271. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +2 -2
  272. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +2 -2
  273. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +2 -2
  274. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +2 -2
  275. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +2 -2
  276. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +2 -2
  277. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +2 -2
  278. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +2 -2
  279. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +2 -2
  280. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +2 -2
  281. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +2 -2
  282. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +2 -2
  283. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +2 -2
  284. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +2 -2
  285. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +2 -2
  286. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +2 -2
  287. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +2 -2
  288. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +2 -2
  289. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +2 -2
  290. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +2 -2
  291. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +2 -2
  292. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +2 -2
  293. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +2 -2
  294. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +2 -2
  295. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +2 -2
  296. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +2 -2
  297. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +2 -2
  298. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +2 -2
  299. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +2 -2
  300. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +2 -2
  301. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +3 -3
  302. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +2 -2
  303. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +2 -2
  304. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +2 -2
  305. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +2 -2
  306. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +2 -2
  307. nautobot/project-static/docs/user-guide/index.html +2 -2
  308. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +2 -2
  309. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +2 -2
  310. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +2 -2
  311. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +2 -2
  312. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +2 -2
  313. nautobot/project-static/docs/user-guide/platform-functionality/events.html +2 -2
  314. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +2 -2
  315. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +2 -2
  316. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +2 -2
  317. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +2 -2
  318. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +2 -2
  319. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +2 -2
  320. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +2 -2
  321. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +2 -2
  322. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +2 -2
  323. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +2 -2
  324. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +2 -2
  325. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +2 -2
  326. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +2 -2
  327. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +2 -2
  328. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +2 -2
  329. nautobot/project-static/docs/user-guide/platform-functionality/note.html +2 -2
  330. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +2 -2
  331. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +2 -2
  332. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +2 -2
  333. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +2 -2
  334. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +2 -2
  335. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +2 -2
  336. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +2 -2
  337. nautobot/project-static/docs/user-guide/platform-functionality/role.html +2 -2
  338. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +2 -2
  339. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +2 -2
  340. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +2 -2
  341. nautobot/project-static/docs/user-guide/platform-functionality/status.html +2 -2
  342. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +2 -2
  343. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +2 -2
  344. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +2 -2
  345. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +2 -2
  346. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +2 -2
  347. nautobot/wireless/navigation.py +1 -1
  348. nautobot/wireless/tables.py +13 -5
  349. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/METADATA +1 -1
  350. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/RECORD +354 -349
  351. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/LICENSE.txt +0 -0
  352. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/NOTICE +0 -0
  353. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/WHEEL +0 -0
  354. {nautobot-2.4.11.dist-info → nautobot-2.4.12.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,93 @@
1
+ {% extends 'base.html' %}
2
+ {% load helpers %}
3
+ {% load form_helpers %}
4
+
5
+ {% block content %}
6
+ <form action="" method="post" enctype="multipart/form-data" class="form form-horizontal">
7
+ {% csrf_token %}
8
+ {{ pk_form.pk }}
9
+ {{ formset.management_form }}
10
+ <div class="row">
11
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
12
+ <h3>{% block title %}{% if vc_form.instance %}Editing {{ vc_form.instance }}{% else %}New Virtual Chassis{% endif %}{% endblock %}</h3>
13
+ {% if vc_form.non_field_errors %}
14
+ <div class="panel panel-danger">
15
+ <div class="panel-heading"><strong>Errors</strong></div>
16
+ <div class="panel-body">
17
+ {{ vc_form.non_field_errors }}
18
+ </div>
19
+ </div>
20
+ {% endif %}
21
+ <div class="panel panel-default">
22
+ <div class="panel-heading"><strong>Virtual Chassis</strong></div>
23
+ <div class="table panel-body">
24
+ {% render_field vc_form.name %}
25
+ {% render_field vc_form.domain %}
26
+ {% render_field vc_form.master %}
27
+ </div>
28
+ </div>
29
+ {% include 'inc/extras_features_edit_form_fields.html' with form=vc_form %}
30
+ <div class="panel panel-default">
31
+ <div class="panel-heading"><strong>Members</strong></div>
32
+ <table class="table panel-body">
33
+ <thead>
34
+ <tr>
35
+ <th>Device</th>
36
+ <th>Rack/Unit</th>
37
+ <th>Serial</th>
38
+ <th>Position</th>
39
+ <th>Priority</th>
40
+ <th></th>
41
+ </tr>
42
+ </thead>
43
+ <tbody>
44
+ {% for form in formset %}
45
+ {% for field in form.hidden_fields %}
46
+ {{ field }}
47
+ {% endfor %}
48
+ {% with device=form.instance virtual_chassis=vc_form.instance %}
49
+ <tr>
50
+ <td>{{ device|hyperlinked_object }}</td>
51
+ <td>
52
+ {% if device.rack %}
53
+ {{ device.rack }} / {{ device.position }}
54
+ {% else %}
55
+ <span class="text-muted">&mdash;</span>
56
+ {% endif %}
57
+ </td>
58
+ <td>{{ device.serial|placeholder }}</td>
59
+ <td>
60
+ {{ form.vc_position }}
61
+ {% if form.vc_position.errors %}
62
+ <br /><small class="text-danger">{{ form.vc_position.errors.0 }}</small>
63
+ {% endif %}
64
+ </td>
65
+ <td>
66
+ {{ form.vc_priority }}
67
+ {% if form.vc_priority.errors %}
68
+ <br /><small class="text-danger">{{ form.vc_priority.errors.0 }}</small>
69
+ {% endif %}
70
+ </td>
71
+ <td>
72
+ {% if virtual_chassis.present_in_database %}
73
+ <a href="{% url 'dcim:virtualchassis_remove_member' pk=device.pk %}?return_url={% url 'dcim:virtualchassis_edit' pk=virtual_chassis.pk %}" class="btn btn-danger btn-xs{% if virtual_chassis.master == device %} disabled{% endif %}">
74
+ <span class="mdi mdi-trash-can-outline" aria-hidden="true"></span>
75
+ </a>
76
+ {% endif %}
77
+ </td>
78
+ </tr>
79
+ {% endwith %}
80
+ {% endfor %}
81
+ </tbody>
82
+ </table>
83
+ </div>
84
+ </div>
85
+ </div>
86
+ <div class="row">
87
+ <div class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1 text-right">
88
+ <button type="submit" name="_update" class="btn btn-primary">Update</button>
89
+ <a href="{{ return_url }}" class="btn btn-default">Cancel</a>
90
+ </div>
91
+ </div>
92
+ </form>
93
+ {% endblock %}
nautobot/dcim/urls.py CHANGED
@@ -21,7 +21,6 @@ from .models import (
21
21
  PowerPort,
22
22
  Rack,
23
23
  RearPort,
24
- VirtualChassis,
25
24
  )
26
25
 
27
26
  app_name = "dcim"
@@ -49,6 +48,7 @@ router.register("rack-groups", views.RackGroupUIViewSet)
49
48
  router.register("rack-reservations", views.RackReservationUIViewSet)
50
49
  router.register("software-image-files", views.SoftwareImageFileUIViewSet)
51
50
  router.register("software-versions", views.SoftwareVersionUIViewSet)
51
+ router.register("virtual-chassis", views.VirtualChassisUIViewSet)
52
52
  router.register("virtual-device-contexts", views.VirtualDeviceContextUIViewSet)
53
53
 
54
54
  urlpatterns = [
@@ -1194,63 +1194,6 @@ urlpatterns = [
1194
1194
  name="interface_connections_list",
1195
1195
  ),
1196
1196
  # Virtual chassis
1197
- path(
1198
- "virtual-chassis/",
1199
- views.VirtualChassisListView.as_view(),
1200
- name="virtualchassis_list",
1201
- ),
1202
- path(
1203
- "virtual-chassis/add/",
1204
- views.VirtualChassisCreateView.as_view(),
1205
- name="virtualchassis_add",
1206
- ),
1207
- path(
1208
- "virtual-chassis/import/",
1209
- views.VirtualChassisBulkImportView.as_view(), # 3.0 TODO: remove, unused
1210
- name="virtualchassis_import",
1211
- ),
1212
- path(
1213
- "virtual-chassis/edit/",
1214
- views.VirtualChassisBulkEditView.as_view(),
1215
- name="virtualchassis_bulk_edit",
1216
- ),
1217
- path(
1218
- "virtual-chassis/delete/",
1219
- views.VirtualChassisBulkDeleteView.as_view(),
1220
- name="virtualchassis_bulk_delete",
1221
- ),
1222
- path(
1223
- "virtual-chassis/<uuid:pk>/",
1224
- views.VirtualChassisView.as_view(),
1225
- name="virtualchassis",
1226
- ),
1227
- path(
1228
- "virtual-chassis/<uuid:pk>/edit/",
1229
- views.VirtualChassisEditView.as_view(),
1230
- name="virtualchassis_edit",
1231
- ),
1232
- path(
1233
- "virtual-chassis/<uuid:pk>/delete/",
1234
- views.VirtualChassisDeleteView.as_view(),
1235
- name="virtualchassis_delete",
1236
- ),
1237
- path(
1238
- "virtual-chassis/<uuid:pk>/changelog/",
1239
- ObjectChangeLogView.as_view(),
1240
- name="virtualchassis_changelog",
1241
- kwargs={"model": VirtualChassis},
1242
- ),
1243
- path(
1244
- "virtual-chassis/<uuid:pk>/notes/",
1245
- ObjectNotesView.as_view(),
1246
- name="virtualchassis_notes",
1247
- kwargs={"model": VirtualChassis},
1248
- ),
1249
- path(
1250
- "virtual-chassis/<uuid:pk>/add-member/",
1251
- views.VirtualChassisAddMemberView.as_view(),
1252
- name="virtualchassis_add_member",
1253
- ),
1254
1197
  path(
1255
1198
  "virtual-chassis-members/<uuid:pk>/delete/",
1256
1199
  views.VirtualChassisRemoveMemberView.as_view(),
nautobot/dcim/views.py CHANGED
@@ -70,8 +70,8 @@ from nautobot.wireless.models import (
70
70
  ControllerManagedDeviceGroupWirelessNetworkAssignment,
71
71
  )
72
72
  from nautobot.wireless.tables import (
73
+ BaseControllerManagedDeviceGroupWirelessNetworkAssignmentTable,
73
74
  ControllerManagedDeviceGroupRadioProfileAssignmentTable,
74
- ControllerManagedDeviceGroupWirelessNetworkAssignmentTable,
75
75
  DeviceGroupWirelessNetworkTable,
76
76
  RadioProfileTable,
77
77
  )
@@ -2238,7 +2238,7 @@ class DeviceWirelessView(generic.ObjectView):
2238
2238
  wireless_networks = ControllerManagedDeviceGroupWirelessNetworkAssignment.objects.filter(
2239
2239
  controller_managed_device_group=controller_managed_device_group
2240
2240
  ).select_related("wireless_network", "controller_managed_device_group", "vlan")
2241
- wireless_networks_table = ControllerManagedDeviceGroupWirelessNetworkAssignmentTable(
2241
+ wireless_networks_table = BaseControllerManagedDeviceGroupWirelessNetworkAssignmentTable(
2242
2242
  data=wireless_networks, user=request.user, orderable=False
2243
2243
  )
2244
2244
  wireless_networks_table.columns.hide("controller_managed_device_group")
@@ -3907,151 +3907,102 @@ class InterfaceConnectionsListView(ConnectionsListView):
3907
3907
  #
3908
3908
 
3909
3909
 
3910
- class VirtualChassisListView(generic.ObjectListView):
3911
- queryset = VirtualChassis.objects.all()
3912
- table = tables.VirtualChassisTable
3913
- filterset = filters.VirtualChassisFilterSet
3914
- filterset_form = forms.VirtualChassisFilterForm
3915
-
3916
-
3917
- class VirtualChassisView(generic.ObjectView):
3910
+ class VirtualChassisUIViewSet(NautobotUIViewSet):
3911
+ bulk_update_form_class = forms.VirtualChassisBulkEditForm
3912
+ filterset_class = filters.VirtualChassisFilterSet
3913
+ filterset_form_class = forms.VirtualChassisFilterForm
3914
+ form_class = forms.VirtualChassisCreateForm
3915
+ serializer_class = serializers.VirtualChassisSerializer
3916
+ table_class = tables.VirtualChassisTable
3918
3917
  queryset = VirtualChassis.objects.all()
3919
3918
 
3920
3919
  def get_extra_context(self, request, instance):
3921
- members = Device.objects.restrict(request.user).filter(virtual_chassis=instance)
3922
-
3923
- return {"members": members, **super().get_extra_context(request, instance)}
3924
-
3925
-
3926
- class VirtualChassisCreateView(generic.ObjectEditView):
3927
- queryset = VirtualChassis.objects.all()
3928
- model_form = forms.VirtualChassisCreateForm
3929
- template_name = "dcim/virtualchassis_add.html"
3930
-
3931
-
3932
- class VirtualChassisEditView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
3933
- queryset = VirtualChassis.objects.all()
3934
-
3935
- def get_required_permission(self):
3936
- return "dcim.change_virtualchassis"
3937
-
3938
- def get(self, request, pk):
3939
- virtual_chassis = get_object_or_404(self.queryset, pk=pk)
3940
- VCMemberFormSet = modelformset_factory(
3941
- model=Device,
3942
- form=forms.DeviceVCMembershipForm,
3943
- formset=forms.BaseVCMemberFormSet,
3944
- extra=0,
3945
- )
3946
- members_queryset = virtual_chassis.members.select_related("rack").order_by("vc_position")
3947
-
3948
- vc_form = forms.VirtualChassisForm(instance=virtual_chassis)
3949
- vc_form.fields["master"].queryset = members_queryset
3950
- formset = VCMemberFormSet(queryset=members_queryset)
3951
-
3952
- return render(
3953
- request,
3954
- "dcim/virtualchassis_edit.html",
3955
- {
3956
- "vc_form": vc_form,
3957
- "formset": formset,
3958
- "return_url": self.get_return_url(request, virtual_chassis),
3959
- },
3960
- )
3961
-
3962
- def post(self, request, pk):
3963
- virtual_chassis = get_object_or_404(self.queryset, pk=pk)
3964
- VCMemberFormSet = modelformset_factory(
3965
- model=Device,
3966
- form=forms.DeviceVCMembershipForm,
3967
- formset=forms.BaseVCMemberFormSet,
3968
- extra=0,
3969
- )
3970
- members_queryset = virtual_chassis.members.select_related("rack").order_by("vc_position")
3971
-
3972
- vc_form = forms.VirtualChassisForm(request.POST, instance=virtual_chassis)
3973
- vc_form.fields["master"].queryset = members_queryset
3974
- formset = VCMemberFormSet(request.POST, queryset=members_queryset)
3975
-
3976
- if vc_form.is_valid() and formset.is_valid():
3977
- with transaction.atomic():
3978
- # Save the VirtualChassis
3979
- vc_form.save()
3980
-
3981
- # Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
3982
- # duplicate positions. Then save each member instance.
3983
- members = formset.save(commit=False)
3984
- devices = Device.objects.filter(pk__in=[m.pk for m in members])
3985
- for device in devices:
3986
- device.vc_position = None
3987
- device.save()
3988
- for member in members:
3989
- member.save()
3990
-
3991
- return redirect(virtual_chassis.get_absolute_url())
3992
-
3993
- return render(
3994
- request,
3995
- "dcim/virtualchassis_edit.html",
3996
- {
3997
- "vc_form": vc_form,
3998
- "formset": formset,
3999
- "return_url": self.get_return_url(request, virtual_chassis),
4000
- },
4001
- )
4002
-
4003
-
4004
- class VirtualChassisDeleteView(generic.ObjectDeleteView):
4005
- queryset = VirtualChassis.objects.all()
3920
+ context = super().get_extra_context(request, instance)
4006
3921
 
3922
+ if self.action == "update":
3923
+ VCMemberFormSet = modelformset_factory(
3924
+ model=Device,
3925
+ form=forms.DeviceVCMembershipForm,
3926
+ formset=forms.BaseVCMemberFormSet,
3927
+ extra=0,
3928
+ )
3929
+ members_queryset = instance.members.select_related("rack").order_by("vc_position")
4007
3930
 
4008
- class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMixin, View):
4009
- queryset = VirtualChassis.objects.all()
3931
+ if request.method == "POST":
3932
+ formset = VCMemberFormSet(request.POST, queryset=members_queryset)
3933
+ else:
3934
+ formset = VCMemberFormSet(queryset=members_queryset)
4010
3935
 
4011
- def get_required_permission(self):
4012
- return "dcim.change_virtualchassis"
3936
+ vc_form = forms.VirtualChassisForm(instance=instance)
3937
+ vc_form.fields["master"].queryset = members_queryset
4013
3938
 
4014
- def get(self, request, pk):
4015
- virtual_chassis = get_object_or_404(self.queryset, pk=pk)
3939
+ context.update(
3940
+ {
3941
+ "formset": formset,
3942
+ "vc_form": vc_form,
3943
+ "return_url": self.get_return_url(request, instance),
3944
+ }
3945
+ )
4016
3946
 
4017
- initial_data = {k: request.GET[k] for k in request.GET}
4018
- member_select_form = forms.VCMemberSelectForm(initial=initial_data)
4019
- membership_form = forms.DeviceVCMembershipForm(initial=initial_data)
3947
+ elif self.action == "retrieve":
3948
+ members = Device.objects.restrict(request.user).filter(virtual_chassis=instance)
3949
+ context.update({"members": members})
4020
3950
 
4021
- return render(
4022
- request,
4023
- "dcim/virtualchassis_add_member.html",
4024
- {
4025
- "virtual_chassis": virtual_chassis,
4026
- "member_select_form": member_select_form,
4027
- "membership_form": membership_form,
4028
- "return_url": self.get_return_url(request, virtual_chassis),
4029
- },
4030
- )
3951
+ return context
4031
3952
 
4032
- def post(self, request, pk):
4033
- virtual_chassis = get_object_or_404(self.queryset, pk=pk)
3953
+ def form_save(self, form, **kwargs):
3954
+ obj = super().form_save(form, **kwargs)
4034
3955
 
4035
- member_select_form = forms.VCMemberSelectForm(request.POST)
3956
+ if self.action == "update":
3957
+ context = self.get_extra_context(self.request, obj)
3958
+ formset = context.get("formset")
4036
3959
 
4037
- if member_select_form.is_valid():
4038
- device = member_select_form.cleaned_data["device"]
4039
- device.virtual_chassis = virtual_chassis
4040
- data = {k: request.POST[k] for k in ["vc_position", "vc_priority"]}
4041
- membership_form = forms.DeviceVCMembershipForm(data=data, validate_vc_position=True, instance=device)
3960
+ if formset.is_valid():
3961
+ with transaction.atomic():
3962
+ members = formset.save(commit=False)
3963
+ # Nullify the vc_position of each member first to allow reordering without raising an IntegrityError on
3964
+ # duplicate positions. Then save each member instance.
3965
+ Device.objects.filter(pk__in=[m.pk for m in members]).update(vc_position=None)
3966
+ for member in members:
3967
+ member.save()
3968
+ else:
3969
+ raise ValidationError(formset.errors)
4042
3970
 
4043
- if membership_form.is_valid():
4044
- membership_form.save()
4045
- msg = format_html('Added member <a href="{}">{}</a>', device.get_absolute_url(), device)
4046
- messages.success(request, msg)
3971
+ return obj
4047
3972
 
4048
- if "_addanother" in request.POST:
4049
- return redirect(request.get_full_path())
3973
+ @action(
3974
+ detail=True,
3975
+ methods=["get", "post"],
3976
+ url_path="add-member",
3977
+ url_name="add_member",
3978
+ custom_view_base_action="change",
3979
+ custom_view_additional_permissions=["dcim.change_virtualchassis"],
3980
+ )
3981
+ def add_member(self, request, pk=None):
3982
+ virtual_chassis = self.get_object()
4050
3983
 
4051
- return redirect(self.get_return_url(request, device))
3984
+ if request.method == "POST":
3985
+ member_select_form = forms.VCMemberSelectForm(request.POST)
3986
+ if member_select_form.is_valid():
3987
+ device = member_select_form.cleaned_data["device"]
3988
+ device.virtual_chassis = virtual_chassis
3989
+ data = {k: request.POST[k] for k in ["vc_position", "vc_priority"]}
3990
+ membership_form = forms.DeviceVCMembershipForm(data=data, validate_vc_position=True, instance=device)
3991
+
3992
+ if membership_form.is_valid():
3993
+ membership_form.save()
3994
+ msg = format_html('Added member <a href="{}">{}</a>', device.get_absolute_url(), device)
3995
+ messages.success(request, msg)
4052
3996
 
3997
+ if "_addanother" in request.POST:
3998
+ return redirect(request.get_full_path())
3999
+ return redirect(self.get_return_url(request, device))
4000
+ else:
4001
+ membership_form = forms.DeviceVCMembershipForm(data=request.POST)
4053
4002
  else:
4054
- membership_form = forms.DeviceVCMembershipForm(data=request.POST)
4003
+ initial_data = {k: request.GET[k] for k in request.GET}
4004
+ member_select_form = forms.VCMemberSelectForm(initial=initial_data)
4005
+ membership_form = forms.DeviceVCMembershipForm(initial=initial_data)
4055
4006
 
4056
4007
  return render(
4057
4008
  request,
@@ -4120,24 +4071,6 @@ class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURL
4120
4071
  )
4121
4072
 
4122
4073
 
4123
- class VirtualChassisBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
4124
- queryset = VirtualChassis.objects.all()
4125
- table = tables.VirtualChassisTable
4126
-
4127
-
4128
- class VirtualChassisBulkEditView(generic.BulkEditView):
4129
- queryset = VirtualChassis.objects.all()
4130
- filterset = filters.VirtualChassisFilterSet
4131
- table = tables.VirtualChassisTable
4132
- form = forms.VirtualChassisBulkEditForm
4133
-
4134
-
4135
- class VirtualChassisBulkDeleteView(generic.BulkDeleteView):
4136
- queryset = VirtualChassis.objects.all()
4137
- filterset = filters.VirtualChassisFilterSet
4138
- table = tables.VirtualChassisTable
4139
-
4140
-
4141
4074
  #
4142
4075
  # Power panels
4143
4076
  #
@@ -4687,25 +4620,69 @@ class ControllerUIViewSet(NautobotUIViewSet):
4687
4620
  table_class = tables.ControllerTable
4688
4621
  template_name = "dcim/controller_create.html"
4689
4622
 
4690
- def get_extra_context(self, request, instance):
4691
- context = super().get_extra_context(request, instance)
4692
-
4693
- if self.action == "retrieve" and instance:
4694
- devices = Device.objects.restrict(request.user).filter(controller_managed_device_group__controller=instance)
4695
- devices_table = tables.DeviceTable(devices)
4696
- devices_table.columns.show("controller_managed_device_group")
4697
- devices_table.columns.show("capabilities")
4698
- devices_table.sequence = ("name", "controller_managed_device_group", "capabilities", "...")
4699
-
4700
- paginate = {
4701
- "paginator_class": EnhancedPaginator,
4702
- "per_page": get_paginate_count(request),
4703
- }
4704
- RequestConfig(request, paginate).configure(devices_table)
4705
-
4706
- context["devices_table"] = devices_table
4707
-
4708
- return context
4623
+ object_detail_content = object_detail.ObjectDetailContent(
4624
+ panels=(
4625
+ object_detail.ObjectFieldsPanel(
4626
+ section=SectionChoices.LEFT_HALF,
4627
+ weight=100,
4628
+ fields="__all__",
4629
+ value_transforms={
4630
+ "capabilities": [helpers.label_list],
4631
+ },
4632
+ exclude_fields=[
4633
+ "external_integration",
4634
+ "controller_device",
4635
+ "controller_device_redundancy_group",
4636
+ ],
4637
+ ),
4638
+ object_detail.ObjectFieldsPanel(
4639
+ section=SectionChoices.RIGHT_HALF,
4640
+ weight=200,
4641
+ label="Integration",
4642
+ fields=[
4643
+ "external_integration",
4644
+ "controller_device",
4645
+ "controller_device_redundancy_group",
4646
+ ],
4647
+ ),
4648
+ object_detail.ObjectsTablePanel(
4649
+ section=SectionChoices.FULL_WIDTH,
4650
+ weight=100,
4651
+ table_class=tables.DeviceTable,
4652
+ table_title="Managed Devices",
4653
+ table_filter="controller_managed_device_group__controller",
4654
+ include_columns=[
4655
+ "capabilities",
4656
+ "controller_managed_device_group",
4657
+ "manufacturer",
4658
+ ],
4659
+ related_field_name="controller",
4660
+ add_button_route=None,
4661
+ ),
4662
+ ),
4663
+ extra_tabs=(
4664
+ object_detail.DistinctViewTab(
4665
+ weight=700,
4666
+ tab_id="wireless_networks",
4667
+ url_name="dcim:controller_wirelessnetworks",
4668
+ label="Wireless Networks",
4669
+ related_object_attribute="wireless_network_assignments",
4670
+ panels=(
4671
+ object_detail.ObjectsTablePanel(
4672
+ section=SectionChoices.FULL_WIDTH,
4673
+ weight=100,
4674
+ table_title="Wireless Networks",
4675
+ table_class=BaseControllerManagedDeviceGroupWirelessNetworkAssignmentTable,
4676
+ table_filter="controller_managed_device_group__controller",
4677
+ tab_id="wireless_networks",
4678
+ add_button_route=None,
4679
+ select_related_fields=["wireless_network"],
4680
+ exclude_columns=["controller"],
4681
+ ),
4682
+ ),
4683
+ ),
4684
+ ),
4685
+ )
4709
4686
 
4710
4687
  @action(
4711
4688
  detail=True,
@@ -4716,28 +4693,7 @@ class ControllerUIViewSet(NautobotUIViewSet):
4716
4693
  custom_view_additional_permissions=["wireless.view_controllermanageddevicegroupwirelessnetworkassignment"],
4717
4694
  )
4718
4695
  def wirelessnetworks(self, request, *args, **kwargs):
4719
- instance = self.get_object()
4720
- controller_managed_device_groups = instance.controller_managed_device_groups.restrict(
4721
- request.user, "view"
4722
- ).values_list("pk", flat=True)
4723
- wireless_networks = ControllerManagedDeviceGroupWirelessNetworkAssignment.objects.filter(
4724
- controller_managed_device_group__in=list(controller_managed_device_groups)
4725
- ).select_related("wireless_network")
4726
- wireless_networks_table = ControllerManagedDeviceGroupWirelessNetworkAssignmentTable(
4727
- data=wireless_networks, user=request.user, orderable=False
4728
- )
4729
- wireless_networks_table.columns.hide("controller")
4730
-
4731
- RequestConfig(
4732
- request, paginate={"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
4733
- ).configure(wireless_networks_table)
4734
-
4735
- return Response(
4736
- {
4737
- "wireless_networks_table": wireless_networks_table,
4738
- "active_tab": "wireless-networks",
4739
- }
4740
- )
4696
+ return Response({})
4741
4697
 
4742
4698
 
4743
4699
  class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
@@ -720,8 +720,8 @@ def refresh_job_code_from_repository(repository_slug, skip_reimport=False, ignor
720
720
  After cloning/updating/deleting a GitRepository on disk, call this function to reload and reregister its Python.
721
721
 
722
722
  Args:
723
- repository_slug (str): Repository slug (directory in GIT_ROOT) that was populated, updated, or deleted.
724
- skip_reimport (bool): If True, unload existing jobs from this repository but do not re-import them.
723
+ repository_slug (str): Repository directory in GIT_ROOT that was updated or deleted.
724
+ skip_reimport (bool): If True, unload existing code from this repository but do not re-import it.
725
725
  ignore_import_errors (bool): If True, any exceptions raised in the import will be caught and logged.
726
726
  If False, exceptions will be re-raised after logging.
727
727
  """