nautobot 2.4.1__py3-none-any.whl → 2.4.3__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 (461) hide show
  1. nautobot/circuits/templates/circuits/inc/circuit_termination.html +1 -1
  2. nautobot/circuits/tests/integration/test_circuit.py +135 -0
  3. nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +43 -0
  4. nautobot/circuits/tests/integration/test_relationships.py +1 -1
  5. nautobot/circuits/views.py +4 -1
  6. nautobot/cloud/api/views.py +3 -3
  7. nautobot/core/apps/__init__.py +0 -5
  8. nautobot/core/constants.py +0 -1
  9. nautobot/core/forms/__init__.py +2 -0
  10. nautobot/core/forms/forms.py +2 -1
  11. nautobot/core/forms/widgets.py +8 -0
  12. nautobot/core/management/commands/generate_performance_test_endpoints.py +268 -0
  13. nautobot/core/templates/generic/object_bulk_delete.html +1 -1
  14. nautobot/core/templates/generic/object_bulk_destroy.html +1 -1
  15. nautobot/core/templates/generic/object_bulk_edit.html +1 -1
  16. nautobot/core/templates/generic/object_bulk_import.html +1 -1
  17. nautobot/core/templates/generic/object_create.html +5 -0
  18. nautobot/core/templates/generic/object_delete.html +1 -1
  19. nautobot/core/templates/generic/object_detail.html +1 -1
  20. nautobot/core/templates/generic/object_edit.html +1 -1
  21. nautobot/core/templates/inc/javascript.html +2 -0
  22. nautobot/core/templates/widgets/clearable_file.html +5 -0
  23. nautobot/core/templatetags/helpers.py +3 -3
  24. nautobot/core/testing/integration.py +469 -12
  25. nautobot/core/tests/test_commands.py +31 -0
  26. nautobot/core/tests/test_jobs.py +34 -2
  27. nautobot/core/tests/test_utils.py +17 -2
  28. nautobot/core/utils/git.py +7 -2
  29. nautobot/core/utils/lookup.py +12 -1
  30. nautobot/core/views/generic.py +10 -2
  31. nautobot/core/views/mixins.py +22 -7
  32. nautobot/core/views/utils.py +2 -2
  33. nautobot/dcim/api/views.py +11 -10
  34. nautobot/dcim/forms.py +15 -6
  35. nautobot/dcim/models/devices.py +1 -2
  36. nautobot/dcim/tables/devices.py +2 -1
  37. nautobot/dcim/templates/dcim/cable.html +1 -1
  38. nautobot/dcim/templates/dcim/cable_trace.html +4 -4
  39. nautobot/dcim/templates/dcim/consoleport.html +14 -4
  40. nautobot/dcim/templates/dcim/consoleserverport.html +14 -4
  41. nautobot/dcim/templates/dcim/device/base.html +1 -1
  42. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +3 -3
  43. nautobot/dcim/templates/dcim/device.html +2 -2
  44. nautobot/dcim/templates/dcim/device_component.html +1 -1
  45. nautobot/dcim/templates/dcim/devicetype.html +1 -1
  46. nautobot/dcim/templates/dcim/frontport.html +7 -2
  47. nautobot/dcim/templates/dcim/interface.html +9 -4
  48. nautobot/dcim/templates/dcim/location.html +1 -1
  49. nautobot/dcim/templates/dcim/locationtype.html +1 -1
  50. nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -1
  51. nautobot/dcim/templates/dcim/manufacturer.html +1 -1
  52. nautobot/dcim/templates/dcim/platform.html +1 -1
  53. nautobot/dcim/templates/dcim/powerfeed.html +9 -4
  54. nautobot/dcim/templates/dcim/poweroutlet.html +14 -4
  55. nautobot/dcim/templates/dcim/powerpanel.html +1 -1
  56. nautobot/dcim/templates/dcim/powerport.html +14 -4
  57. nautobot/dcim/templates/dcim/rack.html +1 -1
  58. nautobot/dcim/templates/dcim/rackgroup.html +1 -1
  59. nautobot/dcim/templates/dcim/rackreservation.html +2 -2
  60. nautobot/dcim/templates/dcim/rearport.html +7 -2
  61. nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
  62. nautobot/dcim/tests/integration/test_device_bulk_operations.py +30 -0
  63. nautobot/dcim/tests/integration/test_fileinputpicker.py +87 -0
  64. nautobot/dcim/tests/integration/test_location_bulk_operations.py +43 -0
  65. nautobot/dcim/tests/test_models.py +1 -1
  66. nautobot/dcim/tests/test_views.py +9 -1
  67. nautobot/dcim/views.py +12 -15
  68. nautobot/extras/api/serializers.py +33 -0
  69. nautobot/extras/api/views.py +13 -5
  70. nautobot/extras/constants.py +1 -0
  71. nautobot/extras/datasources/git.py +125 -0
  72. nautobot/extras/forms/forms.py +4 -0
  73. nautobot/extras/jobs.py +8 -1
  74. nautobot/extras/migrations/0122_add_graphqlquery_owner_content_type.py +34 -0
  75. nautobot/extras/models/customfields.py +29 -12
  76. nautobot/extras/models/datasources.py +85 -0
  77. nautobot/extras/models/models.py +15 -0
  78. nautobot/extras/models/relationships.py +17 -5
  79. nautobot/extras/signals.py +15 -1
  80. nautobot/extras/templates/extras/computedfield.html +1 -1
  81. nautobot/extras/templates/extras/configcontext.html +1 -1
  82. nautobot/extras/templates/extras/configcontextschema.html +1 -1
  83. nautobot/extras/templates/extras/customfield.html +1 -1
  84. nautobot/extras/templates/extras/customlink.html +1 -1
  85. nautobot/extras/templates/extras/dynamicgroup.html +1 -1
  86. nautobot/extras/templates/extras/exporttemplate.html +1 -1
  87. nautobot/extras/templates/extras/gitrepository.html +1 -1
  88. nautobot/extras/templates/extras/graphqlquery.html +1 -1
  89. nautobot/extras/templates/extras/job.html +1 -0
  90. nautobot/extras/templates/extras/job_detail.html +1 -1
  91. nautobot/extras/templates/extras/jobbutton_retrieve.html +1 -1
  92. nautobot/extras/templates/extras/jobhook.html +1 -1
  93. nautobot/extras/templates/extras/jobresult.html +1 -1
  94. nautobot/extras/templates/extras/objectchange.html +1 -1
  95. nautobot/extras/templates/extras/plugin_detail.html +1 -1
  96. nautobot/extras/templates/extras/relationship.html +1 -63
  97. nautobot/extras/templates/extras/role_retrieve.html +1 -1
  98. nautobot/extras/templates/extras/scheduledjob.html +1 -1
  99. nautobot/extras/templates/extras/secret.html +1 -1
  100. nautobot/extras/templates/extras/secretsgroup.html +1 -1
  101. nautobot/extras/templates/extras/status.html +1 -1
  102. nautobot/extras/templates/extras/tag.html +1 -1
  103. nautobot/extras/templates/extras/webhook.html +1 -1
  104. nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_interfaces.gql +8 -0
  105. nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_names.gql +5 -0
  106. nautobot/extras/tests/git_data/02-invalid-files/graphql_queries/bad_device_names.gql +5 -0
  107. nautobot/extras/tests/git_helper.py +9 -1
  108. nautobot/extras/tests/integration/__init__.py +29 -16
  109. nautobot/extras/tests/test_api.py +6 -0
  110. nautobot/extras/tests/test_customfields.py +49 -51
  111. nautobot/extras/tests/test_datasources.py +27 -0
  112. nautobot/extras/tests/test_dynamicgroups.py +14 -0
  113. nautobot/extras/tests/test_models.py +283 -0
  114. nautobot/extras/tests/test_utils.py +22 -1
  115. nautobot/extras/tests/test_views.py +197 -9
  116. nautobot/extras/utils.py +47 -8
  117. nautobot/extras/views.py +84 -26
  118. nautobot/ipam/api/views.py +3 -3
  119. nautobot/ipam/forms.py +2 -6
  120. nautobot/ipam/models.py +8 -2
  121. nautobot/ipam/tables.py +2 -2
  122. nautobot/ipam/templates/ipam/ipaddress.html +1 -1
  123. nautobot/ipam/templates/ipam/prefix.html +1 -1
  124. nautobot/ipam/templates/ipam/rir.html +1 -1
  125. nautobot/ipam/templates/ipam/routetarget.html +1 -1
  126. nautobot/ipam/templates/ipam/service.html +1 -1
  127. nautobot/ipam/templates/ipam/vlan.html +1 -1
  128. nautobot/ipam/templates/ipam/vlangroup.html +1 -1
  129. nautobot/ipam/templates/ipam/vrf.html +1 -1
  130. nautobot/ipam/tests/test_models.py +24 -0
  131. nautobot/ipam/tests/test_utils.py +41 -2
  132. nautobot/ipam/utils/__init__.py +18 -11
  133. nautobot/project-static/bootstrap-filestyle-1.2.3/bootstrap-filestyle.min.js +11 -0
  134. nautobot/project-static/docs/404.html +87 -12
  135. nautobot/project-static/docs/apps/index.html +88 -13
  136. nautobot/project-static/docs/apps/nautobot-apps.html +88 -13
  137. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.60a45f97.min.js} +1 -1
  138. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.60a45f97.min.js.map} +1 -1
  139. nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js → search.f8cc74c7.min.js} +1 -1
  140. nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js.map → search.f8cc74c7.min.js.map} +1 -1
  141. nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css → main.a40c8224.min.css} +1 -1
  142. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +87 -12
  143. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +87 -12
  144. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +87 -12
  145. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +87 -12
  146. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +87 -12
  147. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +87 -12
  148. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +87 -12
  149. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +87 -12
  150. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +87 -12
  151. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +87 -12
  152. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +87 -12
  153. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +87 -12
  154. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +87 -12
  155. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +87 -12
  156. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +87 -12
  157. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +87 -12
  158. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +87 -12
  159. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +87 -12
  160. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +87 -12
  161. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +87 -12
  162. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +87 -12
  163. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +87 -12
  164. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +177 -20
  165. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +114 -17
  166. nautobot/project-static/docs/development/apps/api/configuration-view.html +87 -12
  167. nautobot/project-static/docs/development/apps/api/database-backend-config.html +87 -12
  168. nautobot/project-static/docs/development/apps/api/models/django-admin.html +87 -12
  169. nautobot/project-static/docs/development/apps/api/models/global-search.html +87 -12
  170. nautobot/project-static/docs/development/apps/api/models/graphql.html +96 -21
  171. nautobot/project-static/docs/development/apps/api/models/index.html +87 -12
  172. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +87 -12
  173. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +87 -12
  174. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +89 -14
  175. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +87 -12
  176. nautobot/project-static/docs/development/apps/api/platform-features/index.html +87 -12
  177. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +87 -12
  178. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +87 -12
  179. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +87 -12
  180. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +87 -12
  181. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +87 -12
  182. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +87 -12
  183. nautobot/project-static/docs/development/apps/api/prometheus.html +87 -12
  184. nautobot/project-static/docs/development/apps/api/setup.html +88 -13
  185. nautobot/project-static/docs/development/apps/api/testing.html +87 -12
  186. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +87 -12
  187. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +87 -12
  188. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +87 -12
  189. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +87 -12
  190. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +87 -12
  191. nautobot/project-static/docs/development/apps/api/views/base-template.html +87 -12
  192. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +87 -12
  193. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +87 -12
  194. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +87 -12
  195. nautobot/project-static/docs/development/apps/api/views/index.html +87 -12
  196. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +87 -12
  197. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +87 -12
  198. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +87 -12
  199. nautobot/project-static/docs/development/apps/api/views/notes.html +87 -12
  200. nautobot/project-static/docs/development/apps/api/views/rest-api.html +87 -12
  201. nautobot/project-static/docs/development/apps/api/views/urls.html +87 -12
  202. nautobot/project-static/docs/development/apps/index.html +87 -12
  203. nautobot/project-static/docs/development/apps/migration/code-updates.html +93 -17
  204. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +89 -14
  205. nautobot/project-static/docs/development/apps/migration/from-v1.html +90 -15
  206. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +87 -12
  207. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +87 -12
  208. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +87 -12
  209. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +87 -12
  210. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +87 -12
  211. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +87 -12
  212. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +88 -13
  213. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +87 -12
  214. nautobot/project-static/docs/development/apps/porting-from-netbox.html +87 -12
  215. nautobot/project-static/docs/development/core/application-registry.html +87 -12
  216. nautobot/project-static/docs/development/core/best-practices.html +88 -13
  217. nautobot/project-static/docs/development/core/bootstrap-ui.html +88 -13
  218. nautobot/project-static/docs/development/core/caching.html +87 -12
  219. nautobot/project-static/docs/development/core/controllers.html +87 -12
  220. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +94 -19
  221. nautobot/project-static/docs/development/core/generic-views.html +87 -12
  222. nautobot/project-static/docs/development/core/getting-started.html +89 -14
  223. nautobot/project-static/docs/development/core/homepage.html +87 -12
  224. nautobot/project-static/docs/development/core/index.html +88 -13
  225. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +90 -15
  226. nautobot/project-static/docs/development/core/model-checklist.html +88 -13
  227. nautobot/project-static/docs/development/core/model-features.html +87 -12
  228. nautobot/project-static/docs/development/core/natural-keys.html +87 -12
  229. nautobot/project-static/docs/development/core/navigation-menu.html +88 -13
  230. nautobot/project-static/docs/development/core/release-checklist.html +88 -13
  231. nautobot/project-static/docs/development/core/role-internals.html +87 -12
  232. nautobot/project-static/docs/development/core/settings.html +88 -13
  233. nautobot/project-static/docs/development/core/style-guide.html +91 -16
  234. nautobot/project-static/docs/development/core/templates.html +88 -13
  235. nautobot/project-static/docs/development/core/testing.html +87 -12
  236. nautobot/project-static/docs/development/core/ui-component-framework.html +87 -12
  237. nautobot/project-static/docs/development/core/user-preferences.html +87 -12
  238. nautobot/project-static/docs/development/index.html +87 -12
  239. nautobot/project-static/docs/development/jobs/index.html +95 -13
  240. nautobot/project-static/docs/development/jobs/migration/from-v1.html +90 -14
  241. nautobot/project-static/docs/index.html +90 -14
  242. nautobot/project-static/docs/objects.inv +0 -0
  243. nautobot/project-static/docs/overview/application_stack.html +89 -14
  244. nautobot/project-static/docs/overview/design_philosophy.html +87 -12
  245. nautobot/project-static/docs/release-notes/index.html +87 -12
  246. nautobot/project-static/docs/release-notes/version-1.0.html +89 -14
  247. nautobot/project-static/docs/release-notes/version-1.1.html +89 -14
  248. nautobot/project-static/docs/release-notes/version-1.2.html +90 -15
  249. nautobot/project-static/docs/release-notes/version-1.3.html +88 -13
  250. nautobot/project-static/docs/release-notes/version-1.4.html +104 -29
  251. nautobot/project-static/docs/release-notes/version-1.5.html +95 -20
  252. nautobot/project-static/docs/release-notes/version-1.6.html +91 -16
  253. nautobot/project-static/docs/release-notes/version-2.0.html +97 -22
  254. nautobot/project-static/docs/release-notes/version-2.1.html +94 -19
  255. nautobot/project-static/docs/release-notes/version-2.2.html +88 -13
  256. nautobot/project-static/docs/release-notes/version-2.3.html +91 -16
  257. nautobot/project-static/docs/release-notes/version-2.4.html +465 -12
  258. nautobot/project-static/docs/requirements.txt +1 -1
  259. nautobot/project-static/docs/search/search_index.json +1 -1
  260. nautobot/project-static/docs/sitemap.xml +296 -288
  261. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  262. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +90 -15
  263. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +87 -12
  264. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +91 -16
  265. nautobot/project-static/docs/user-guide/administration/configuration/index.html +87 -12
  266. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +88 -13
  267. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +90 -15
  268. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +87 -12
  269. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +95 -20
  270. nautobot/project-static/docs/user-guide/administration/guides/docker.html +90 -15
  271. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +88 -13
  272. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +87 -12
  273. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +91 -16
  274. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +87 -12
  275. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +102 -27
  276. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +89 -14
  277. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +87 -12
  278. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +88 -13
  279. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +87 -12
  280. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +87 -12
  281. nautobot/project-static/docs/user-guide/administration/installation/index.html +87 -12
  282. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +88 -13
  283. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +93 -18
  284. nautobot/project-static/docs/user-guide/administration/installation/services.html +88 -13
  285. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +87 -12
  286. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +87 -12
  287. nautobot/project-static/docs/user-guide/administration/security/index.html +9420 -0
  288. nautobot/project-static/docs/user-guide/administration/security/notices.html +9844 -0
  289. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +87 -12
  290. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +88 -13
  291. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +87 -12
  292. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +87 -12
  293. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +87 -12
  294. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +87 -12
  295. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +87 -12
  296. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +87 -12
  297. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +87 -12
  298. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +98 -20
  299. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +87 -12
  300. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +87 -12
  301. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +87 -12
  302. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +87 -12
  303. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +87 -12
  304. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +87 -12
  305. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +87 -12
  306. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +87 -12
  307. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +87 -12
  308. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +87 -12
  309. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +87 -12
  310. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +87 -12
  311. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +87 -12
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +87 -12
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +87 -12
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +87 -12
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +87 -12
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +87 -12
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +87 -12
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +87 -12
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +87 -12
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +87 -12
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +87 -12
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +87 -12
  323. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +87 -12
  324. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +87 -12
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +87 -12
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +87 -12
  327. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +87 -12
  328. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +87 -12
  329. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +87 -12
  330. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +87 -12
  331. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +87 -12
  332. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +87 -12
  333. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +87 -12
  334. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +87 -12
  335. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +87 -12
  336. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +87 -12
  337. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +87 -12
  338. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +87 -12
  339. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +87 -12
  340. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +87 -12
  341. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +87 -12
  342. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +87 -12
  343. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +87 -12
  344. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +87 -12
  345. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +87 -12
  346. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +87 -12
  347. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +87 -12
  348. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +87 -12
  349. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +87 -12
  350. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +87 -12
  351. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +87 -12
  352. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +87 -12
  353. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +87 -12
  354. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +87 -12
  355. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +87 -12
  356. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +87 -12
  357. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +87 -12
  358. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +87 -12
  359. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +87 -12
  360. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +87 -12
  361. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +87 -12
  362. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +87 -12
  363. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +87 -12
  364. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +87 -12
  365. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +87 -12
  366. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +87 -12
  367. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +87 -12
  368. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +87 -12
  369. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +87 -12
  370. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +87 -12
  371. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +87 -12
  372. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +87 -12
  373. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +87 -12
  374. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +87 -12
  375. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +87 -12
  376. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +87 -12
  377. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +87 -12
  378. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +87 -12
  379. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +87 -12
  380. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +99 -24
  381. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +87 -12
  382. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +87 -12
  383. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +90 -15
  384. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +87 -12
  385. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +87 -12
  386. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +87 -12
  387. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +87 -12
  388. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +87 -12
  389. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +87 -12
  390. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +188 -30
  391. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +87 -12
  392. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +87 -12
  393. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +87 -12
  394. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +87 -12
  395. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +87 -12
  396. nautobot/project-static/docs/user-guide/index.html +87 -12
  397. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +87 -12
  398. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +87 -12
  399. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +87 -12
  400. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +87 -12
  401. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +88 -13
  402. nautobot/project-static/docs/user-guide/platform-functionality/events.html +87 -12
  403. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +87 -12
  404. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +87 -12
  405. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +407 -14
  406. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +90 -15
  407. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +87 -12
  408. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +87 -12
  409. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +87 -12
  410. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +87 -12
  411. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +87 -12
  412. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +87 -12
  413. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +89 -14
  414. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +93 -18
  415. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +87 -12
  416. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +87 -12
  417. nautobot/project-static/docs/user-guide/platform-functionality/note.html +87 -12
  418. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +87 -12
  419. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +87 -12
  420. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +87 -12
  421. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +87 -12
  422. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +87 -12
  423. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +87 -12
  424. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +87 -12
  425. nautobot/project-static/docs/user-guide/platform-functionality/role.html +87 -12
  426. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +87 -12
  427. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +87 -12
  428. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +87 -12
  429. nautobot/project-static/docs/user-guide/platform-functionality/status.html +87 -12
  430. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +87 -12
  431. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +87 -12
  432. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +87 -12
  433. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +87 -12
  434. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +87 -12
  435. nautobot/project-static/js/dropdown.js +28 -0
  436. nautobot/tenancy/forms.py +9 -0
  437. nautobot/tenancy/templates/tenancy/tenant.html +1 -2
  438. nautobot/tenancy/templates/tenancy/tenant_create.html +21 -0
  439. nautobot/tenancy/templates/tenancy/tenant_edit.html +2 -21
  440. nautobot/tenancy/templates/tenancy/tenantgroup.html +2 -44
  441. nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +1 -0
  442. nautobot/tenancy/tests/test_views.py +5 -1
  443. nautobot/tenancy/urls.py +7 -79
  444. nautobot/tenancy/views.py +51 -80
  445. nautobot/virtualization/templates/virtualization/cluster.html +1 -1
  446. nautobot/virtualization/templates/virtualization/clustergroup.html +1 -1
  447. nautobot/virtualization/templates/virtualization/clustertype.html +1 -1
  448. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  449. nautobot/virtualization/templates/virtualization/vminterface.html +1 -1
  450. nautobot/wireless/api/serializers.py +6 -1
  451. nautobot/wireless/api/views.py +3 -3
  452. nautobot/wireless/tests/test_api.py +5 -0
  453. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/METADATA +12 -12
  454. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/RECORD +459 -443
  455. nautobot/dcim/tests/integration/test_device_bulk_delete.py +0 -189
  456. nautobot/dcim/tests/integration/test_device_bulk_edit.py +0 -181
  457. /nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css.map → main.a40c8224.min.css.map} +0 -0
  458. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/LICENSE.txt +0 -0
  459. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/NOTICE +0 -0
  460. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/WHEEL +0 -0
  461. {nautobot-2.4.1.dist-info → nautobot-2.4.3.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load helpers %}
3
3
 
4
4
  {% block extra_breadcrumbs %}
@@ -39,7 +39,7 @@
39
39
  <td>Connected Device</td>
40
40
  <td>
41
41
  {% if object.connected_endpoint %}
42
- {{ object.connected_endpoint.device|hyperlinked_object }}
42
+ {{ object.connected_endpoint.parent|hyperlinked_object }}
43
43
  ({{ object.connected_endpoint }})
44
44
  {% else %}
45
45
  <span class="text-muted">None</span>
@@ -110,8 +110,13 @@
110
110
  </tr>
111
111
  {% if object.connected_endpoint %}
112
112
  <tr>
113
- <td>Device</td>
114
- <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
113
+ {% if object.connected_endpoint.device %}
114
+ <td>Device</td>
115
+ <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
116
+ {% else %}
117
+ <td>Module</td>
118
+ <td>{{ object.connected_endpoint.module|hyperlinked_object }}</td>
119
+ {% endif %}
115
120
  </tr>
116
121
  <tr>
117
122
  <td>Power Port</td>
@@ -8,8 +8,13 @@
8
8
  </div>
9
9
  <table class="table table-hover panel-body attr-table">
10
10
  <tr>
11
- <td>Device</td>
12
- <td>{{ object.device|hyperlinked_object }}</td>
11
+ {% if object.device %}
12
+ <td>Device</td>
13
+ <td>{{ object.device|hyperlinked_object }}</td>
14
+ {% else %}
15
+ <td>Module</td>
16
+ <td>{{ object.module|hyperlinked_object }}</td>
17
+ {% endif %}
13
18
  </tr>
14
19
  <tr>
15
20
  <td>Name</td>
@@ -57,8 +62,13 @@
57
62
  </tr>
58
63
  {% if object.connected_endpoint %}
59
64
  <tr>
60
- <td>Device</td>
61
- <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
65
+ {% if object.connected_endpoint.device %}
66
+ <td>Device</td>
67
+ <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
68
+ {% else %}
69
+ <td>Module</td>
70
+ <td>{{ object.connected_endpoint.module|hyperlinked_object }}</td>
71
+ {% endif %}
62
72
  </tr>
63
73
  <tr>
64
74
  <td>Power Port</td>
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load helpers %}
3
3
 
4
4
  {% block extra_breadcrumbs %}
@@ -8,8 +8,13 @@
8
8
  </div>
9
9
  <table class="table table-hover panel-body attr-table">
10
10
  <tr>
11
- <td>Device</td>
12
- <td>{{ object.device|hyperlinked_object }}</td>
11
+ {% if object.device %}
12
+ <td>Device</td>
13
+ <td>{{ object.device|hyperlinked_object }}</td>
14
+ {% else %}
15
+ <td>Module</td>
16
+ <td>{{ object.module|hyperlinked_object }}</td>
17
+ {% endif %}
13
18
  </tr>
14
19
  <tr>
15
20
  <td>Name</td>
@@ -57,8 +62,13 @@
57
62
  </tr>
58
63
  {% if object.connected_endpoint %}
59
64
  <tr>
60
- <td>Device</td>
61
- <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
65
+ {% if object.connected_endpoint.device %}
66
+ <td>Device</td>
67
+ <td>{{ object.connected_endpoint.device|hyperlinked_object }}</td>
68
+ {% else %}
69
+ <td>Module</td>
70
+ <td>{{ object.connected_endpoint.module|hyperlinked_object }}</td>
71
+ {% endif %}
62
72
  </tr>
63
73
  <tr>
64
74
  <td>Power Outlet / Feed</td>
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load helpers %}
3
3
  {% load static %}
4
4
 
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load buttons %}
3
3
  {% load helpers %}
4
4
 
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load helpers %}
3
3
  {% load static %}
4
4
 
@@ -15,7 +15,7 @@
15
15
  {% with rack=object.rack %}
16
16
  <tr>
17
17
  <td>Location</td>
18
- <td>{% include 'dcim/inc/location_hierarchy.html' with location=object.location %}</td>
18
+ <td>{% include 'dcim/inc/location_hierarchy.html' with location=rack.location %}</td>
19
19
  </tr>
20
20
  <tr>
21
21
  <td>Group</td>
@@ -8,8 +8,13 @@
8
8
  </div>
9
9
  <table class="table table-hover panel-body attr-table">
10
10
  <tr>
11
- <td>Device</td>
12
- <td>{{ object.device|hyperlinked_object }}</td>
11
+ {% if object.device %}
12
+ <td>Device</td>
13
+ <td>{{ object.device|hyperlinked_object }}</td>
14
+ {% else %}
15
+ <td>Module</td>
16
+ <td>{{ object.module|hyperlinked_object }}</td>
17
+ {% endif %}
13
18
  </tr>
14
19
  <tr>
15
20
  <td>Name</td>
@@ -1,4 +1,4 @@
1
- {% extends 'generic/object_detail.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% load helpers %}
3
3
 
4
4
  {% block content_left_page %}
@@ -0,0 +1,30 @@
1
+ import uuid
2
+
3
+ from nautobot.core.testing.integration import (
4
+ BulkOperationsTestCases,
5
+ )
6
+ from nautobot.dcim.models import Device
7
+ from nautobot.extras.tests.integration import create_test_device
8
+
9
+
10
+ class DeviceBulkOperationsTestCase(BulkOperationsTestCases.BulkOperationsTestCase):
11
+ """
12
+ Test devices bulk edit / delete operations.
13
+ """
14
+
15
+ model_menu_path = ("Devices", "Devices")
16
+ model_base_viewname = "dcim:device"
17
+ model_edit_data = {"serial": "Test serial"}
18
+ model_filter_by = {"location": "Test Location 2"}
19
+ model_class = Device
20
+
21
+ def setup_items(self):
22
+ Device.objects.all().delete()
23
+ test_uuid = str(uuid.uuid4())
24
+
25
+ # Create device for test
26
+ create_test_device("Test Device Integration Test 1", test_uuid=test_uuid)
27
+ create_test_device("Test Device Integration Test 2", test_uuid=test_uuid)
28
+ create_test_device("Test Device Integration Test 3", test_uuid=test_uuid)
29
+ create_test_device("Test Device Integration Test 4", "Test Location 2", test_uuid=test_uuid)
30
+ create_test_device("Test Device Integration Test 5", "Test Location 2", test_uuid=test_uuid)
@@ -0,0 +1,87 @@
1
+ from django.urls import reverse
2
+
3
+ from nautobot.core.testing.integration import SeleniumTestCase, WebDriverWait
4
+ from nautobot.dcim.models import Location, LocationType
5
+ from nautobot.extras.models import Job, Status
6
+
7
+
8
+ class ClearableFileInputTestCase(SeleniumTestCase):
9
+ def setUp(self):
10
+ super().setUp()
11
+ self.user.is_superuser = True
12
+ self.user.save()
13
+ self.login(self.user.username, self.password)
14
+
15
+ def tearDown(self):
16
+ self.logout()
17
+ super().tearDown()
18
+
19
+ def _assert_file_picker(self, uri_to_visit: str, page_loaded_confirmation: str, file_input_selector_id: str):
20
+ """
21
+ Ensure clearable input file type has working clear and info display.
22
+ """
23
+ self.browser.visit(f"{self.live_server_url}{uri_to_visit}")
24
+ WebDriverWait(self.browser, 10).until(lambda driver: driver.is_text_present(page_loaded_confirmation))
25
+
26
+ # Find the first file input button and scroll to it
27
+ front_image_button = self.browser.find_by_css("span.group-span-filestyle.input-group-btn").first
28
+ front_image_button.scroll_to()
29
+
30
+ # cancel button is NOT visible initially
31
+ self.assertFalse(self.browser.find_by_css("button.clear-button").first.visible)
32
+
33
+ # Test file text changes after selecting a file
34
+ file_selection_indicator_css = "div.bootstrap-filestyle input[type='text'].form-control"
35
+ self.assertEqual(self.browser.find_by_css(file_selection_indicator_css).first.value, "")
36
+ front_image_file_input = self.browser.find_by_id(file_input_selector_id).first
37
+ front_image_file_input.value = "/dev/null"
38
+ self.assertEqual(self.browser.find_by_css(file_selection_indicator_css).first.value, "null")
39
+
40
+ # clear button is now visible
41
+ clear_button = self.browser.find_by_css("button.clear-button").first
42
+ self.assertTrue(clear_button.visible)
43
+
44
+ # clicking clearbutton should hide the button, and wipe the file input value
45
+ clear_button.click()
46
+ self.assertFalse(clear_button.visible)
47
+ self.assertEqual(front_image_file_input.value, "")
48
+
49
+ def test_add_device_page(self):
50
+ """
51
+ Confirm device type add page input is working correctly.
52
+ """
53
+ self._assert_file_picker(
54
+ uri_to_visit=reverse("dcim:devicetype_add"),
55
+ page_loaded_confirmation="Device Type",
56
+ file_input_selector_id="id_front_image",
57
+ )
58
+
59
+ def test_job_runner_page(self):
60
+ """
61
+ Confirm job run page file input is working correctly.
62
+ """
63
+ example_job = Job.objects.get(name="Example File Input/Output job").pk
64
+ job_example_file_uri = reverse("extras:job_run", kwargs={"pk": example_job})
65
+ self._assert_file_picker(
66
+ uri_to_visit=job_example_file_uri,
67
+ page_loaded_confirmation="Example File",
68
+ file_input_selector_id="id_input_file",
69
+ )
70
+
71
+ def test_location_image_attachment_view(self):
72
+ """
73
+ Confirm location image attachment page is working correctly.
74
+ """
75
+ location_type, _ = LocationType.objects.get_or_create(name="Campus")
76
+ location_status = Status.objects.get_for_model(Location).first()
77
+ location, _ = Location.objects.get_or_create(
78
+ name="Test Location 1", location_type=location_type, status=location_status
79
+ )
80
+ location_image_attach_uri = reverse(
81
+ "dcim:location_add_image", kwargs={"object_id": location.id, "model": Location}
82
+ )
83
+ self._assert_file_picker(
84
+ uri_to_visit=location_image_attach_uri,
85
+ page_loaded_confirmation="Image attachment",
86
+ file_input_selector_id="id_image",
87
+ )
@@ -0,0 +1,43 @@
1
+ from django.contrib.contenttypes.models import ContentType
2
+
3
+ from nautobot.core.testing.integration import (
4
+ BulkOperationsTestCases,
5
+ )
6
+ from nautobot.dcim.models import Device, Location, LocationType
7
+ from nautobot.extras.models import Status
8
+
9
+
10
+ class LocationBulkOperationsTestCase(BulkOperationsTestCases.BulkOperationsTestCase):
11
+ """
12
+ Test locations bulk edit / delete operations.
13
+ """
14
+
15
+ model_menu_path = ("Organization", "Locations")
16
+ model_base_viewname = "dcim:location"
17
+ model_edit_data = {"description": "Test description"}
18
+ model_filter_by = {"location_type": "External"}
19
+ model_class = Location
20
+
21
+ def setup_items(self):
22
+ Location.objects.all().delete()
23
+
24
+ # Create locations for test
25
+ self.create_location("Test Location Integration Test 1")
26
+ self.create_location("Test Location Integration Test 2")
27
+ self.create_location("Test Location Integration Test 3")
28
+ self.create_location("Test Location Integration Test 4", "External")
29
+ self.create_location("Test Location Integration Test 5", "External")
30
+
31
+ @staticmethod
32
+ def create_location(location_name, location_type="Internal"):
33
+ location_type, location_type_created = LocationType.objects.get_or_create(name=location_type)
34
+ if location_type_created:
35
+ location_type.content_types.add(ContentType.objects.get_for_model(Device))
36
+ location_type.save()
37
+
38
+ location_status = Status.objects.get_for_model(Location).first()
39
+ Location.objects.get_or_create(
40
+ name=location_name,
41
+ status=location_status,
42
+ location_type=location_type,
43
+ )
@@ -2790,7 +2790,7 @@ class ControllerTestCase(ModelTestCases.BaseModelTestCase):
2790
2790
  controller.validated_save()
2791
2791
  self.assertEqual(
2792
2792
  error.exception.message_dict["location"][0],
2793
- f'Devices may not associate to locations of type "{location_type}".',
2793
+ f'Controllers may not associate to locations of type "{location_type}".',
2794
2794
  )
2795
2795
 
2796
2796
 
@@ -161,7 +161,7 @@ def create_test_device(name):
161
161
  return device
162
162
 
163
163
 
164
- class LocationTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
164
+ class LocationTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase, ViewTestCases.BulkEditObjectsViewTestCase):
165
165
  model = LocationType
166
166
  sort_on_field = "nestable"
167
167
 
@@ -194,6 +194,13 @@ class LocationTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
194
194
  "nestable": True,
195
195
  }
196
196
 
197
+ cls.bulk_edit_data = {
198
+ "description": "A generic description",
199
+ "add_content_types": [
200
+ ContentType.objects.get_for_model(CircuitTermination).pk,
201
+ ],
202
+ }
203
+
197
204
  def _get_queryset(self):
198
205
  return super()._get_queryset().order_by("-last_updated")
199
206
 
@@ -743,6 +750,7 @@ class DeviceFamilyTestCase(ViewTestCases.PrimaryObjectViewTestCase):
743
750
  cls.form_data = {
744
751
  "name": "New Device Family",
745
752
  "description": "A new device family",
753
+ "tags": [t.pk for t in Tag.objects.get_for_model(DeviceFamily)],
746
754
  }
747
755
  cls.bulk_edit_data = {
748
756
  "description": "A new device family",
nautobot/dcim/views.py CHANGED
@@ -40,7 +40,7 @@ from nautobot.core.ui.choices import SectionChoices
40
40
  from nautobot.core.utils.lookup import get_form_for_model
41
41
  from nautobot.core.utils.permissions import get_permission_for_model
42
42
  from nautobot.core.utils.requests import normalize_querydict
43
- from nautobot.core.views import generic, mixins as view_mixins
43
+ from nautobot.core.views import generic
44
44
  from nautobot.core.views.mixins import (
45
45
  GetReturnURLMixin,
46
46
  ObjectBulkDestroyViewMixin,
@@ -213,21 +213,13 @@ class BaseDeviceComponentTemplatesBulkRenameView(generic.BulkRenameView):
213
213
  #
214
214
 
215
215
 
216
- class LocationTypeUIViewSet(
217
- view_mixins.ObjectDetailViewMixin,
218
- view_mixins.ObjectListViewMixin,
219
- view_mixins.ObjectEditViewMixin,
220
- view_mixins.ObjectDestroyViewMixin,
221
- view_mixins.ObjectBulkDestroyViewMixin,
222
- view_mixins.ObjectBulkCreateViewMixin, # 3.0 TODO: remove this mixin as it's no longer used
223
- view_mixins.ObjectChangeLogViewMixin,
224
- view_mixins.ObjectNotesViewMixin,
225
- ):
216
+ class LocationTypeUIViewSet(NautobotUIViewSet):
226
217
  queryset = LocationType.objects.all()
227
218
  filterset_class = filters.LocationTypeFilterSet
228
219
  filterset_form_class = forms.LocationTypeFilterForm
229
220
  table_class = tables.LocationTypeTable
230
221
  form_class = forms.LocationTypeForm
222
+ bulk_update_form_class = forms.LocationTypeBulkEditForm
231
223
  serializer_class = serializers.LocationSerializer
232
224
 
233
225
  object_detail_content = object_detail.ObjectDetailContent(
@@ -1755,16 +1747,21 @@ class DeviceListView(generic.ObjectListView):
1755
1747
 
1756
1748
  class DeviceView(generic.ObjectView):
1757
1749
  queryset = Device.objects.select_related(
1750
+ "cluster__cluster_group",
1751
+ "controller_managed_device_group__controller",
1752
+ "device_redundancy_group",
1753
+ "device_type__device_family",
1758
1754
  "location",
1759
- "rack__rack_group",
1760
- "tenant__tenant_group",
1761
- "role",
1762
1755
  "platform",
1763
1756
  "primary_ip4",
1764
1757
  "primary_ip6",
1758
+ "rack__rack_group",
1759
+ "role",
1760
+ "secrets_group",
1765
1761
  "software_version",
1766
1762
  "status",
1767
- )
1763
+ "tenant__tenant_group",
1764
+ ).prefetch_related("images", "software_image_files")
1768
1765
 
1769
1766
  object_detail_content = object_detail.ObjectDetailContent(
1770
1767
  extra_buttons=(
@@ -480,11 +480,32 @@ class GitRepositorySerializer(TaggedModelSerializerMixin, NautobotModelSerialize
480
480
 
481
481
  class GraphQLQuerySerializer(ValidatedModelSerializer, NotesSerializerMixin):
482
482
  variables = serializers.DictField(read_only=True)
483
+ owner_content_type = ContentTypeField(
484
+ queryset=ContentType.objects.filter(FeatureQuery("graphql_query_owners").get_query()),
485
+ required=False,
486
+ allow_null=True,
487
+ default=None,
488
+ )
489
+ owner = serializers.SerializerMethodField(read_only=True)
483
490
 
484
491
  class Meta:
485
492
  model = GraphQLQuery
486
493
  fields = "__all__"
487
494
 
495
+ @extend_schema_field(
496
+ PolymorphicProxySerializer(
497
+ component_name="GraphQLQueryOwner",
498
+ resource_type_field_name="object_type",
499
+ serializers=lambda: nested_serializers_for_models(FeatureQuery("graphql_query_owners").list_subclasses()),
500
+ allow_null=True,
501
+ )
502
+ )
503
+ def get_owner(self, obj):
504
+ if obj.owner is None:
505
+ return None
506
+ depth = get_nested_serializer_depth(self)
507
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
508
+
488
509
 
489
510
  class GraphQLQueryInputSerializer(serializers.Serializer):
490
511
  variables = serializers.DictField(allow_null=True, default={})
@@ -1148,3 +1169,15 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1148
1169
  raise serializers.ValidationError(conflicts)
1149
1170
 
1150
1171
  return validated_attrs
1172
+
1173
+
1174
+ #
1175
+ # More Git repositories
1176
+ #
1177
+
1178
+
1179
+ class GitRepositorySyncResponseSerializer(serializers.Serializer):
1180
+ """Serializer representing responses from the GitRepository.sync() POST endpoint."""
1181
+
1182
+ message = serializers.CharField(read_only=True)
1183
+ job_result = JobResultSerializer(read_only=True)
@@ -425,7 +425,7 @@ class GitRepositoryViewSet(NautobotModelViewSet):
425
425
  serializer_class = serializers.GitRepositorySerializer
426
426
  filterset_class = filters.GitRepositoryFilterSet
427
427
 
428
- @extend_schema(methods=["post"], request=serializers.GitRepositorySerializer)
428
+ @extend_schema(methods=["post"], responses={"200": serializers.GitRepositorySyncResponseSerializer}, request=None)
429
429
  # Since we are explicitly checking for `extras:change_gitrepository` in the API sync() method
430
430
  # We explicitly set the permission_classes to IsAuthenticated in the @action decorator
431
431
  # bypassing the default DRF permission check for `extras:add_gitrepository` and the permission check fall through to the function itself.
@@ -441,8 +441,16 @@ class GitRepositoryViewSet(NautobotModelViewSet):
441
441
  raise CeleryWorkerNotRunningException()
442
442
 
443
443
  repository = get_object_or_404(GitRepository, id=pk)
444
- repository.sync(user=request.user)
445
- return Response({"message": f"Repository {repository} sync job added to queue."})
444
+ job_result = repository.sync(user=request.user)
445
+
446
+ data = {
447
+ # Kept message for backward compatibility for now
448
+ "message": f"Repository {repository} sync job added to queue.",
449
+ "job_result": job_result,
450
+ }
451
+
452
+ serializer = serializers.GitRepositorySyncResponseSerializer(data, context={"request": request})
453
+ return Response(serializer.data, status=status.HTTP_200_OK)
446
454
 
447
455
 
448
456
  #
@@ -828,7 +836,7 @@ class JobQueueViewSet(NautobotModelViewSet):
828
836
  filterset_class = filters.JobQueueFilterSet
829
837
 
830
838
 
831
- class JobQueueAssignmentViewSet(NautobotModelViewSet):
839
+ class JobQueueAssignmentViewSet(ModelViewSet):
832
840
  """
833
841
  Manage job queue assignments through DELETE, GET, POST, PUT, and PATCH requests.
834
842
  """
@@ -1061,7 +1069,7 @@ class MetadataChoiceViewSet(ModelViewSet):
1061
1069
  filterset_class = filters.MetadataChoiceFilterSet
1062
1070
 
1063
1071
 
1064
- class ObjectMetadataViewSet(NautobotModelViewSet):
1072
+ class ObjectMetadataViewSet(ModelViewSet):
1065
1073
  queryset = ObjectMetadata.objects.all()
1066
1074
  serializer_class = serializers.ObjectMetadataSerializer
1067
1075
  filterset_class = filters.ObjectMetadataFilterSet
@@ -11,6 +11,7 @@ EXTRAS_FEATURES = [
11
11
  "dynamic_groups",
12
12
  "export_template_owners",
13
13
  "export_templates",
14
+ "graphql_query_owners",
14
15
  "graphql",
15
16
  "job_results", # No longer used
16
17
  "locations",