nautobot 2.4.14__py3-none-any.whl → 2.4.16__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.
Files changed (434) hide show
  1. nautobot/apps/choices.py +8 -0
  2. nautobot/apps/ui.py +14 -0
  3. nautobot/core/api/views.py +2 -0
  4. nautobot/core/choices.py +4 -0
  5. nautobot/core/filters.py +21 -41
  6. nautobot/core/management/commands/check_job_approval_status.py +47 -0
  7. nautobot/core/management/commands/generate_test_data.py +1 -1
  8. nautobot/core/management/commands/migrate.py +1 -1
  9. nautobot/core/models/tree_queries.py +17 -0
  10. nautobot/core/settings.py +2 -2
  11. nautobot/core/tables.py +25 -2
  12. nautobot/core/templates/base_django.html +1 -1
  13. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  14. nautobot/core/templates/generic/object_list.html +17 -20
  15. nautobot/core/templates/inc/breadcrumbs.html +14 -0
  16. nautobot/core/templatetags/buttons.py +2 -4
  17. nautobot/core/templatetags/helpers.py +29 -6
  18. nautobot/core/templatetags/ui_framework.py +21 -0
  19. nautobot/core/testing/filters.py +20 -3
  20. nautobot/core/testing/forms.py +1 -1
  21. nautobot/core/tests/integration/test_filters.py +2 -2
  22. nautobot/core/tests/test_breadcrumbs.py +366 -0
  23. nautobot/core/tests/test_commands.py +40 -0
  24. nautobot/core/tests/test_filters.py +51 -1
  25. nautobot/core/tests/test_forms.py +1 -1
  26. nautobot/core/tests/test_graphql.py +4 -4
  27. nautobot/core/tests/test_titles.py +183 -0
  28. nautobot/core/tests/test_tree_queries.py +30 -0
  29. nautobot/core/tests/test_views.py +2 -2
  30. nautobot/core/tests/test_views_utils.py +1 -1
  31. nautobot/core/ui/breadcrumbs.py +538 -0
  32. nautobot/core/ui/bulk_buttons.py +53 -0
  33. nautobot/core/ui/object_detail.py +31 -8
  34. nautobot/core/ui/titles.py +127 -0
  35. nautobot/core/ui/utils.py +25 -0
  36. nautobot/core/utils/migrations.py +1 -1
  37. nautobot/core/views/__init__.py +1 -1
  38. nautobot/core/views/mixins.py +26 -1
  39. nautobot/core/views/renderers.py +20 -2
  40. nautobot/core/views/utils.py +13 -12
  41. nautobot/dcim/api/serializers.py +9 -0
  42. nautobot/dcim/choices.py +53 -0
  43. nautobot/dcim/filters/__init__.py +15 -3
  44. nautobot/dcim/forms.py +120 -7
  45. nautobot/dcim/management/commands/trace_paths.py +1 -1
  46. nautobot/dcim/migrations/0072_alter_powerfeed_options_and_more.py +97 -0
  47. nautobot/dcim/models/device_component_templates.py +8 -0
  48. nautobot/dcim/models/device_components.py +31 -12
  49. nautobot/dcim/models/devices.py +1 -1
  50. nautobot/dcim/models/power.py +171 -10
  51. nautobot/dcim/models/racks.py +7 -4
  52. nautobot/dcim/tables/devices.py +2 -0
  53. nautobot/dcim/tables/devicetypes.py +1 -0
  54. nautobot/dcim/tables/power.py +30 -2
  55. nautobot/dcim/templates/dcim/device.html +2 -2
  56. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -214
  57. nautobot/dcim/templates/dcim/location_retrieve.html +2 -2
  58. nautobot/dcim/templates/dcim/powerfeed_edit.html +8 -0
  59. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -1
  60. nautobot/dcim/tests/integration/test_device_bulk_operations.py +61 -0
  61. nautobot/dcim/tests/test_api.py +24 -4
  62. nautobot/dcim/tests/test_filters.py +91 -13
  63. nautobot/dcim/tests/test_models.py +262 -0
  64. nautobot/dcim/tests/test_views.py +20 -12
  65. nautobot/dcim/utils.py +9 -0
  66. nautobot/dcim/views.py +390 -77
  67. nautobot/extras/factory.py +19 -20
  68. nautobot/extras/filters/__init__.py +3 -2
  69. nautobot/extras/filters/mixins.py +15 -1
  70. nautobot/extras/forms/__init__.py +2 -1
  71. nautobot/extras/forms/forms.py +62 -0
  72. nautobot/extras/managers.py +4 -1
  73. nautobot/extras/migrations/0125_jobresult_date_started.py +18 -0
  74. nautobot/extras/models/customfields.py +1 -2
  75. nautobot/extras/models/datasources.py +1 -2
  76. nautobot/extras/models/jobs.py +7 -3
  77. nautobot/extras/plugins/views.py +24 -1
  78. nautobot/extras/secrets/__init__.py +1 -1
  79. nautobot/extras/tables.py +21 -0
  80. nautobot/extras/templates/extras/customfield.html +2 -129
  81. nautobot/extras/templates/extras/customfield_edit.html +2 -108
  82. nautobot/extras/templates/extras/customfield_retrieve.html +129 -0
  83. nautobot/extras/templates/extras/customfield_update.html +108 -0
  84. nautobot/extras/templates/extras/inc/jobresult.html +7 -3
  85. nautobot/extras/templates/extras/jobresult.html +2 -155
  86. nautobot/extras/templates/extras/jobresult_retrieve.html +155 -0
  87. nautobot/extras/templates/extras/marketplace.html +5 -6
  88. nautobot/extras/templates/extras/note.html +2 -53
  89. nautobot/extras/templates/extras/note_retrieve.html +53 -0
  90. nautobot/extras/templates/extras/plugins_list.html +5 -6
  91. nautobot/extras/templates/extras/secretsgroup_retrieve.html +2 -29
  92. nautobot/extras/templatetags/custom_links.py +2 -2
  93. nautobot/extras/templatetags/job_buttons.py +1 -1
  94. nautobot/extras/templatetags/plugins.py +1 -1
  95. nautobot/extras/tests/integration/test_computedfields.py +2 -2
  96. nautobot/extras/tests/integration/test_customfields.py +14 -11
  97. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  98. nautobot/extras/tests/integration/test_notes.py +1 -1
  99. nautobot/extras/tests/integration/test_plugins.py +6 -6
  100. nautobot/extras/tests/integration/test_relationships.py +2 -2
  101. nautobot/extras/tests/test_filters.py +9 -0
  102. nautobot/extras/tests/test_forms.py +2 -2
  103. nautobot/extras/tests/test_plugins.py +14 -3
  104. nautobot/extras/tests/test_relationships.py +7 -7
  105. nautobot/extras/tests/test_views.py +172 -1
  106. nautobot/extras/urls.py +3 -59
  107. nautobot/extras/utils.py +1 -1
  108. nautobot/extras/views.py +96 -182
  109. nautobot/ipam/tables.py +8 -15
  110. nautobot/ipam/tests/migration/test_migrations.py +8 -8
  111. nautobot/ipam/tests/test_api.py +2 -2
  112. nautobot/ipam/tests/test_models.py +1 -1
  113. nautobot/project-static/docs/404.html +23 -0
  114. nautobot/project-static/docs/apps/index.html +23 -0
  115. nautobot/project-static/docs/apps/nautobot-apps.html +23 -0
  116. nautobot/project-static/docs/assets/_mkdocstrings.css +44 -6
  117. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +28 -0
  118. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +25 -0
  119. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +128 -20
  120. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +37 -4
  121. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +39 -6
  122. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +25 -0
  123. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +24 -0
  124. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +32 -5
  125. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +41 -8
  126. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +39 -7
  127. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +43 -10
  128. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +74 -59
  129. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +143 -28
  130. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +43 -12
  131. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +135 -53
  132. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +229 -36
  133. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +27 -1
  134. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +30 -1
  135. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +162 -18
  136. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +258 -51
  137. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5987 -2620
  138. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +25 -0
  139. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +154 -55
  140. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +150 -35
  141. nautobot/project-static/docs/development/apps/api/configuration-view.html +23 -0
  142. nautobot/project-static/docs/development/apps/api/database-backend-config.html +23 -0
  143. nautobot/project-static/docs/development/apps/api/models/django-admin.html +23 -0
  144. nautobot/project-static/docs/development/apps/api/models/global-search.html +23 -0
  145. nautobot/project-static/docs/development/apps/api/models/graphql.html +23 -0
  146. nautobot/project-static/docs/development/apps/api/models/index.html +23 -0
  147. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +23 -0
  148. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +23 -0
  149. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +23 -0
  150. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +23 -0
  151. nautobot/project-static/docs/development/apps/api/platform-features/index.html +23 -0
  152. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +23 -0
  153. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +23 -0
  154. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +23 -0
  155. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +23 -0
  156. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +23 -0
  157. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +23 -0
  158. nautobot/project-static/docs/development/apps/api/prometheus.html +23 -0
  159. nautobot/project-static/docs/development/apps/api/setup.html +23 -0
  160. nautobot/project-static/docs/development/apps/api/testing.html +23 -0
  161. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +23 -0
  162. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +23 -0
  163. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +23 -0
  164. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +23 -0
  165. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +23 -0
  166. nautobot/project-static/docs/development/apps/api/views/base-template.html +23 -0
  167. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +23 -0
  168. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +23 -0
  169. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +23 -0
  170. nautobot/project-static/docs/development/apps/api/views/index.html +23 -0
  171. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +23 -0
  172. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -2
  173. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +23 -0
  174. nautobot/project-static/docs/development/apps/api/views/notes.html +23 -0
  175. nautobot/project-static/docs/development/apps/api/views/rest-api.html +23 -0
  176. nautobot/project-static/docs/development/apps/api/views/urls.html +23 -0
  177. nautobot/project-static/docs/development/apps/index.html +23 -0
  178. nautobot/project-static/docs/development/apps/migration/code-updates.html +23 -0
  179. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +23 -0
  180. nautobot/project-static/docs/development/apps/migration/from-v1.html +23 -0
  181. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +23 -0
  182. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +23 -0
  183. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +23 -0
  184. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +23 -0
  185. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +26 -3
  186. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +10544 -0
  187. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +23 -0
  188. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +23 -0
  189. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +23 -0
  190. nautobot/project-static/docs/development/apps/porting-from-netbox.html +26 -3
  191. nautobot/project-static/docs/development/core/application-registry.html +23 -0
  192. nautobot/project-static/docs/development/core/best-practices.html +23 -0
  193. nautobot/project-static/docs/development/core/bootstrap-ui.html +23 -0
  194. nautobot/project-static/docs/development/core/caching.html +23 -0
  195. nautobot/project-static/docs/development/core/controllers.html +23 -0
  196. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +23 -0
  197. nautobot/project-static/docs/development/core/generic-views.html +23 -0
  198. nautobot/project-static/docs/development/core/getting-started.html +23 -0
  199. nautobot/project-static/docs/development/core/homepage.html +23 -0
  200. nautobot/project-static/docs/development/core/index.html +23 -0
  201. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +23 -0
  202. nautobot/project-static/docs/development/core/model-checklist.html +23 -0
  203. nautobot/project-static/docs/development/core/model-features.html +23 -0
  204. nautobot/project-static/docs/development/core/natural-keys.html +23 -0
  205. nautobot/project-static/docs/development/core/navigation-menu.html +23 -0
  206. nautobot/project-static/docs/development/core/release-checklist.html +23 -0
  207. nautobot/project-static/docs/development/core/role-internals.html +23 -0
  208. nautobot/project-static/docs/development/core/settings.html +23 -0
  209. nautobot/project-static/docs/development/core/style-guide.html +23 -0
  210. nautobot/project-static/docs/development/core/templates.html +23 -0
  211. nautobot/project-static/docs/development/core/testing.html +23 -0
  212. nautobot/project-static/docs/development/core/ui-component-framework.html +713 -255
  213. nautobot/project-static/docs/development/core/user-preferences.html +23 -0
  214. nautobot/project-static/docs/development/index.html +23 -0
  215. nautobot/project-static/docs/development/jobs/getting-started.html +23 -0
  216. nautobot/project-static/docs/development/jobs/index.html +23 -0
  217. nautobot/project-static/docs/development/jobs/installation.html +23 -0
  218. nautobot/project-static/docs/development/jobs/job-extensions.html +23 -0
  219. nautobot/project-static/docs/development/jobs/job-logging.html +23 -0
  220. nautobot/project-static/docs/development/jobs/job-patterns.html +23 -0
  221. nautobot/project-static/docs/development/jobs/job-structure.html +23 -0
  222. nautobot/project-static/docs/development/jobs/migration/from-v1.html +23 -0
  223. nautobot/project-static/docs/development/jobs/testing.html +23 -0
  224. nautobot/project-static/docs/index.html +23 -0
  225. nautobot/project-static/docs/media/development/core/ui-component-framework/breadcrumbs-titles-data-flow.png +0 -0
  226. nautobot/project-static/docs/media/power_distribution.png +0 -0
  227. nautobot/project-static/docs/objects.inv +0 -0
  228. nautobot/project-static/docs/overview/application_stack.html +23 -0
  229. nautobot/project-static/docs/overview/design_philosophy.html +23 -0
  230. nautobot/project-static/docs/release-notes/index.html +23 -0
  231. nautobot/project-static/docs/release-notes/version-1.0.html +23 -0
  232. nautobot/project-static/docs/release-notes/version-1.1.html +23 -0
  233. nautobot/project-static/docs/release-notes/version-1.2.html +23 -0
  234. nautobot/project-static/docs/release-notes/version-1.3.html +23 -0
  235. nautobot/project-static/docs/release-notes/version-1.4.html +23 -0
  236. nautobot/project-static/docs/release-notes/version-1.5.html +23 -0
  237. nautobot/project-static/docs/release-notes/version-1.6.html +23 -0
  238. nautobot/project-static/docs/release-notes/version-2.0.html +23 -0
  239. nautobot/project-static/docs/release-notes/version-2.1.html +23 -0
  240. nautobot/project-static/docs/release-notes/version-2.2.html +23 -0
  241. nautobot/project-static/docs/release-notes/version-2.3.html +23 -0
  242. nautobot/project-static/docs/release-notes/version-2.4.html +306 -0
  243. nautobot/project-static/docs/requirements.txt +2 -2
  244. nautobot/project-static/docs/search/search_index.json +1 -1
  245. nautobot/project-static/docs/sitemap.xml +303 -299
  246. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  247. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +23 -0
  248. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +23 -0
  249. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +23 -0
  250. nautobot/project-static/docs/user-guide/administration/configuration/index.html +23 -0
  251. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +23 -0
  252. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +23 -0
  253. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +23 -0
  254. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +23 -0
  255. nautobot/project-static/docs/user-guide/administration/guides/docker.html +23 -0
  256. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +23 -0
  257. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +23 -0
  258. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +23 -0
  259. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +23 -0
  260. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +23 -0
  261. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +23 -0
  262. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +23 -0
  263. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +23 -0
  264. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +23 -0
  265. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +23 -0
  266. nautobot/project-static/docs/user-guide/administration/installation/index.html +23 -0
  267. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +23 -0
  268. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +23 -0
  269. nautobot/project-static/docs/user-guide/administration/installation/services.html +23 -0
  270. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +23 -0
  271. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +23 -0
  272. nautobot/project-static/docs/user-guide/administration/security/index.html +23 -0
  273. nautobot/project-static/docs/user-guide/administration/security/notices.html +23 -0
  274. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +284 -219
  275. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +23 -0
  276. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +23 -0
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +23 -0
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +23 -0
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +23 -0
  280. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +23 -0
  281. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +23 -0
  282. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +23 -0
  283. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +23 -0
  284. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +23 -0
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +23 -0
  286. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +23 -0
  287. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +23 -0
  288. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +23 -0
  289. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +23 -0
  290. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +23 -0
  291. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +23 -0
  292. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +23 -0
  293. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +23 -0
  294. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +23 -0
  295. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +23 -0
  296. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +23 -0
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +23 -0
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +23 -0
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +23 -0
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +23 -0
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +23 -0
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +23 -0
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +23 -0
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +23 -0
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +23 -0
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +23 -0
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +23 -0
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +23 -0
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +23 -0
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +23 -0
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +23 -0
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +23 -0
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +23 -0
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +23 -0
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +23 -0
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +23 -0
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +23 -0
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +23 -0
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +23 -0
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +23 -0
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +23 -0
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +23 -0
  323. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +23 -0
  324. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +23 -0
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +305 -5
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +24 -1
  327. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +23 -0
  328. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +136 -3
  329. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +41 -1
  330. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +40 -0
  331. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +23 -0
  332. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +23 -0
  333. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +23 -0
  334. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +23 -0
  335. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +23 -0
  336. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +23 -0
  337. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +23 -0
  338. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +23 -0
  339. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +23 -0
  340. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +23 -0
  341. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +23 -0
  342. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +23 -0
  343. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +23 -0
  344. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +23 -0
  345. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +23 -0
  346. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +23 -0
  347. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +23 -0
  348. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +23 -0
  349. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +23 -0
  350. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +23 -0
  351. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +23 -0
  352. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +23 -0
  353. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +23 -0
  354. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +23 -0
  355. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +23 -0
  356. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +23 -0
  357. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +23 -0
  358. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +23 -0
  359. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +23 -0
  360. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +23 -0
  361. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +23 -0
  362. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +23 -0
  363. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +23 -0
  364. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +23 -0
  365. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +23 -0
  366. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +23 -0
  367. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +23 -0
  368. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +23 -0
  369. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +23 -0
  370. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +23 -0
  371. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +23 -0
  372. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +23 -0
  373. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +23 -0
  374. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +23 -0
  375. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +23 -0
  376. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +23 -0
  377. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +23 -0
  378. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +23 -0
  379. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +23 -0
  380. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +23 -0
  381. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +23 -0
  382. nautobot/project-static/docs/user-guide/index.html +23 -0
  383. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +23 -0
  384. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +23 -0
  385. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +23 -0
  386. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +23 -0
  387. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +23 -0
  388. nautobot/project-static/docs/user-guide/platform-functionality/events.html +23 -0
  389. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +23 -0
  390. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +23 -0
  391. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +23 -0
  392. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +23 -0
  393. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +23 -0
  394. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +23 -0
  395. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +23 -0
  396. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +24 -1
  397. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +23 -0
  398. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +23 -0
  399. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +23 -0
  400. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +23 -0
  401. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +23 -0
  402. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +23 -0
  403. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +23 -0
  404. nautobot/project-static/docs/user-guide/platform-functionality/note.html +23 -0
  405. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +23 -0
  406. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +23 -0
  407. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +23 -0
  408. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +23 -0
  409. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +23 -0
  410. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +23 -0
  411. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +23 -0
  412. nautobot/project-static/docs/user-guide/platform-functionality/role.html +23 -0
  413. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +23 -0
  414. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +23 -0
  415. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +23 -0
  416. nautobot/project-static/docs/user-guide/platform-functionality/status.html +23 -0
  417. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +23 -0
  418. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +23 -0
  419. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +23 -0
  420. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +23 -0
  421. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +23 -0
  422. nautobot/users/tests/test_api.py +2 -2
  423. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -252
  424. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -75
  425. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +252 -0
  426. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +75 -0
  427. nautobot/virtualization/urls.py +3 -61
  428. nautobot/virtualization/views.py +48 -72
  429. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/METADATA +24 -24
  430. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/RECORD +434 -417
  431. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/LICENSE.txt +0 -0
  432. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/NOTICE +0 -0
  433. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/WHEEL +0 -0
  434. {nautobot-2.4.14.dist-info → nautobot-2.4.16.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,53 @@
1
+ {% extends 'generic/object_retrieve.html' %}
2
+ {% load buttons %}
3
+ {% load plugins %}
4
+ {% load perms %}
5
+ {% load helpers %}
6
+
7
+ {% block breadcrumbs %}
8
+ <li><a href="{% url 'extras:note_list' %}">Notes</a></li>
9
+ {% if object.assigned_object.get_absolute_url %}
10
+ <li><a href="{{ object.assigned_object.get_absolute_url }}notes/">{{ object.assigned_object }}</a></li>
11
+ {% endif %}
12
+ <li>{{ object }}</li>
13
+ {% endblock breadcrumbs %}
14
+
15
+ {% block content %}
16
+ <div class="row">
17
+ <div class="col-md-5">
18
+ <div class="panel panel-default">
19
+ <div class="panel-heading">
20
+ <strong>Note</strong>
21
+ </div>
22
+ <table class="table table-hover panel-body attr-table">
23
+ <tr>
24
+ <td>User</td>
25
+ <td>
26
+ {{ object.user|default:object.user_name }}
27
+ </td>
28
+ </tr>
29
+ <tr>
30
+ <td>Object Type</td>
31
+ <td>
32
+ {{ object.assigned_object_type }}
33
+ </td>
34
+ </tr>
35
+ <tr>
36
+ <td>Object</td>
37
+ <td>
38
+ {{ object.assigned_object | hyperlinked_object }}
39
+ </td>
40
+ </tr>
41
+ </table>
42
+ </div>
43
+ <div class="panel panel-default">
44
+ <div class="panel-heading">
45
+ <strong>Text</strong>
46
+ </div>
47
+ <div class="panel-body rendered-markdown">
48
+ {{ object.note|render_markdown }}
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ {% endblock %}
@@ -1,15 +1,14 @@
1
1
  {% extends "base.html" %}
2
2
  {% load helpers %}
3
3
  {% load static %}
4
+ {% load ui_framework %}
5
+
6
+ {% block document_title %}{% render_title "plain" %}{% endblock %}
4
7
 
5
8
  {% block content %}
6
9
  <div class="row noprint">
7
10
  <div class="col-md-12">
8
- <ol class="breadcrumb">
9
- {% block breadcrumbs %}
10
- <li><a href="{% url 'apps:apps_list' %}">Installed Apps</a></li>
11
- {% endblock breadcrumbs %}
12
- </ol>
11
+ {% render_breadcrumbs %}
13
12
  </div>
14
13
  </div>
15
14
 
@@ -34,7 +33,7 @@
34
33
  <a class="btn btn-primary" href="{% url 'apps:apps_marketplace' %}">Visit Apps Marketplace</a>
35
34
  </div>
36
35
 
37
- <h1>{% block title %}Installed Apps{% endblock %}</h1>
36
+ <h1>{% block page_heading %}{% render_title %}{% endblock %}</h1>
38
37
 
39
38
  <div class="row">
40
39
  <div class="col-md-12">
@@ -1,29 +1,2 @@
1
- {% extends "generic/object_retrieve.html" %}
2
- {% load helpers %}
3
-
4
- {% block content_left_page %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading">
7
- <strong>Secrets Group</strong>
8
- </div>
9
- <table class="table table-hover panel-body attr-table">
10
- <tr>
11
- <td>Description</td>
12
- <td colspan="3">{{ object.description | placeholder }}</td>
13
- </tr>
14
- <tr>
15
- <td rowspan="{{ secrets_group_associations | length | add:'1'}}">Secrets</td>
16
- <th>Access Type</th>
17
- <th>Secret Type</th>
18
- <th>Secret</th>
19
- </tr>
20
- {% for secret_association in secrets_group_associations %}
21
- <tr>
22
- <td>{{ secret_association.access_type }}</td>
23
- <td>{{ secret_association.secret_type | bettertitle }}</td>
24
- <td>{{ secret_association.secret|hyperlinked_object }}</td>
25
- </tr>
26
- {% endfor %}
27
- </table>
28
- </div>
29
- {% endblock content_left_page %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -40,7 +40,7 @@ def custom_links(context, obj):
40
40
  "user": context["user"], # django.contrib.auth.context_processors.auth
41
41
  "perms": context["perms"], # django.contrib.auth.context_processors.auth
42
42
  }
43
- template_code = mark_safe("") # noqa: S308 # suspicious-mark-safe-usage -- this one is safe
43
+ template_code = mark_safe("")
44
44
  group_names = OrderedDict()
45
45
 
46
46
  for cl in links:
@@ -70,7 +70,7 @@ def custom_links(context, obj):
70
70
 
71
71
  # Add grouped links to template
72
72
  for group, links in group_names.items():
73
- links_rendered = mark_safe("") # noqa: S308 # suspicious-mark-safe-usage -- this one is safe
73
+ links_rendered = mark_safe("")
74
74
 
75
75
  for cl in links:
76
76
  try:
@@ -71,7 +71,7 @@ CONFIRM_MODAL = """
71
71
  </div>
72
72
  """
73
73
 
74
- SAFE_EMPTY_STR = mark_safe("") # noqa: S308 # suspicious-mark-safe-usage -- this one is safe
74
+ SAFE_EMPTY_STR = mark_safe("")
75
75
 
76
76
 
77
77
  def _render_job_button_for_obj(job_button, obj, context, content_type):
@@ -50,7 +50,7 @@ def _get_registered_content(obj, method, template_context, return_html=True):
50
50
  content = getattr(instance, method)()
51
51
  if not return_html:
52
52
  for i, content in enumerate(content):
53
- objects.append({f"{plugin_name}:{i+1}": content})
53
+ objects.append({f"{plugin_name}:{i + 1}": content})
54
54
  else:
55
55
  html += content
56
56
 
@@ -40,7 +40,7 @@ class ComputedFieldsTestCase(SeleniumTestCase):
40
40
  and checks it appears ONLY there!.
41
41
  """
42
42
  # Visit the device detail page
43
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": self.device.pk})}')
43
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': self.device.pk})}")
44
44
  # Check the computed field appears in the primary information tab
45
45
  self.assertTrue(self.browser.is_text_present("Device Computed Field"))
46
46
  self.assertTrue(self.browser.is_text_present(f"{self.device.name} is awesome!"))
@@ -52,7 +52,7 @@ class ComputedFieldsTestCase(SeleniumTestCase):
52
52
  self.computed_field.advanced_ui = True
53
53
  self.computed_field.save()
54
54
  # Visit the device detail page
55
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": self.device.pk})}')
55
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': self.device.pk})}")
56
56
  # Check the computed field does NOT appear in the primary information tab
57
57
  self.assertFalse(self.browser.is_text_present("Device Computed Field"))
58
58
  self.assertFalse(self.browser.is_text_present(f"{self.device.name} is awesome!"))
@@ -96,12 +96,13 @@ class CustomFieldTestCase(SeleniumTestCase):
96
96
 
97
97
  def test_fail_create_invalid_type_with_choices(self):
98
98
  """Test fail type!=select with choices."""
99
+ cf_label = "Test Text"
99
100
  with self.assertRaises(AssertionError):
100
- self._create_custom_field(field_label="Test Text", field_type="text", choices=["bad1"])
101
+ self._create_custom_field(field_label=cf_label, field_type="text", choices=["bad1"])
101
102
 
102
103
  # Assert error state
103
- self.assertTrue(self.browser.is_text_present("Editing custom field"))
104
- self.assertTrue(self.browser.is_text_present("Errors encountered when saving custom field choices"))
104
+ self.assertTrue(self.browser.is_text_present("Add a new custom field"))
105
+ self.assertTrue(self.browser.is_text_present(f"{cf_label} failed validation"))
105
106
  self.assertTrue(self.browser.is_text_present("Custom field choices can only be assigned to selection fields"))
106
107
 
107
108
  def test_create_type_select_with_choices_adding_dynamic_row(self):
@@ -133,7 +134,8 @@ class CustomFieldTestCase(SeleniumTestCase):
133
134
  choices = ["replace_me"]
134
135
 
135
136
  # Create the field
136
- self._create_custom_field(field_label="Test Select", field_type="select", choices=choices)
137
+ cf_label = "Test Select"
138
+ self._create_custom_field(field_label=cf_label, field_type="select", choices=choices)
137
139
  detail_url = self.browser.url
138
140
 
139
141
  #
@@ -148,7 +150,8 @@ class CustomFieldTestCase(SeleniumTestCase):
148
150
  self.browser.fill("custom_field_choices-0-value", "")
149
151
  self.assertEqual(self.browser.find_by_name("custom_field_choices-0-value").value, "")
150
152
  self.browser.find_by_text("Update").click()
151
- self.assertTrue(self.browser.is_text_present("Errors encountered when saving custom field choices"))
153
+ self.assertTrue(self.browser.is_text_present(f"{cf_label} failed validation"))
154
+ self.assertTrue(self.browser.is_text_present("This field is required."))
152
155
 
153
156
  #
154
157
  # Pass updating existing choice (changing value of existing choice)
@@ -208,7 +211,7 @@ class CustomFieldTestCase(SeleniumTestCase):
208
211
  device.cf[custom_field.key] = "This is some testing text"
209
212
  device.validated_save()
210
213
  # Visit the device detail page
211
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": device.pk})}')
214
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': device.pk})}")
212
215
  # Check the custom field appears in the primary information tab
213
216
  self.assertTrue(self.browser.is_text_present("Device Custom Field"))
214
217
  self.assertTrue(self.browser.is_text_present("This is some testing text"))
@@ -220,7 +223,7 @@ class CustomFieldTestCase(SeleniumTestCase):
220
223
  custom_field.advanced_ui = True
221
224
  custom_field.save()
222
225
  # Visit the device detail page
223
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": device.pk})}')
226
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': device.pk})}")
224
227
  # Check the custom field does NOT appear in the primary information tab
225
228
  self.assertFalse(self.browser.is_text_present("Device Custom Field"))
226
229
  self.assertFalse(self.browser.is_text_present("This is some testing text"))
@@ -245,7 +248,7 @@ class CustomFieldTestCase(SeleniumTestCase):
245
248
  device_content_type = ContentType.objects.get_for_model(Device)
246
249
  custom_field.content_types.set([device_content_type])
247
250
  # Visit the device edit page
248
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device_edit", kwargs={"pk": self.device.pk})}')
251
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device_edit', kwargs={'pk': self.device.pk})}")
249
252
  self.browser.find_by_id("id_cf_test_valid_json_field").first.type("test")
250
253
  active_web_element = self.browser.driver.switch_to.active_element
251
254
  # Type invalid JSON data into the form
@@ -271,7 +274,7 @@ class CustomFieldTestCase(SeleniumTestCase):
271
274
  device_content_type = ContentType.objects.get_for_model(Device)
272
275
  custom_field.content_types.set([device_content_type])
273
276
  # Visit the device edit page
274
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device_edit", kwargs={"pk": self.device.pk})}')
277
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device_edit', kwargs={'pk': self.device.pk})}")
275
278
  self.browser.find_by_id("id_cf_test_invalid_json_field").first.type("test")
276
279
  active_web_element = self.browser.driver.switch_to.active_element
277
280
  # Type invalid JSON data into the form
@@ -303,7 +306,7 @@ class CustomFieldTestCase(SeleniumTestCase):
303
306
  device_content_type = ContentType.objects.get_for_model(Device)
304
307
  custom_field.content_types.set([device_content_type])
305
308
  # Visit the device edit page
306
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device_edit", kwargs={"pk": device.pk})}')
309
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device_edit', kwargs={'pk': device.pk})}")
307
310
  # Get the first item selected on the custom field
308
311
  self.browser.find_by_xpath(".//label[contains(text(), 'Device Selection Field')]").click()
309
312
  active_web_element = self.browser.driver.switch_to.active_element
@@ -325,7 +328,7 @@ class CustomFieldTestCase(SeleniumTestCase):
325
328
  self.browser.find_by_xpath(".//button[contains(text(), 'Confirm')]").click()
326
329
 
327
330
  # Visit the device edit page
328
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device_edit", kwargs={"pk": device.pk})}')
331
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device_edit', kwargs={'pk': device.pk})}")
329
332
  # Click update button
330
333
  self.browser.find_by_xpath(".//button[contains(text(), 'Update')]").click()
331
334
  # Check successful redirect to device object page
@@ -79,6 +79,6 @@ class DynamicGroupTestCase(SeleniumTestCase):
79
79
 
80
80
  # Verify dynamic group shows up on device detail tab
81
81
  self.browser.visit(
82
- f'{self.live_server_url}{reverse("dcim:device_dynamicgroups", kwargs={"pk": devices[0].pk})}'
82
+ f"{self.live_server_url}{reverse('dcim:device_dynamicgroups', kwargs={'pk': devices[0].pk})}"
83
83
  )
84
84
  self.assertTrue(self.browser.is_text_present(name))
@@ -29,7 +29,7 @@ class NoteTestCase(SeleniumTestCase):
29
29
  location = Location.objects.create(name="Location 1", location_type=location_type, status=location_status)
30
30
 
31
31
  # Navigate to the created location.
32
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:location", kwargs={"pk": location.pk})}')
32
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:location', kwargs={'pk': location.pk})}")
33
33
 
34
34
  # Verify notes tab shows up and click it.
35
35
  self.assertTrue(self.browser.links.find_by_partial_href(f"/dcim/locations/{location.pk}/notes/"))
@@ -134,13 +134,13 @@ class AppDocumentationTest(SeleniumTestCase):
134
134
 
135
135
  def test_object_edit_help_provided(self):
136
136
  """The ExampleModel object provides model documentation, this test ensures the help link is rendered."""
137
- self.browser.visit(f'{self.live_server_url}{reverse("plugins:example_app:examplemodel_add")}')
137
+ self.browser.visit(f"{self.live_server_url}{reverse('plugins:example_app:examplemodel_add')}")
138
138
 
139
139
  self.assertTrue(self.browser.links.find_by_partial_href("example_app/docs/models/examplemodel.html"))
140
140
 
141
141
  def test_object_edit_help_not_provided(self):
142
142
  """The AnotherExampleModel object doesn't provide model documentation, this test ensures no help link is provided."""
143
- self.browser.visit(f'{self.live_server_url}{reverse("plugins:example_app:anotherexamplemodel_add")}')
143
+ self.browser.visit(f"{self.live_server_url}{reverse('plugins:example_app:anotherexamplemodel_add')}")
144
144
 
145
145
  self.assertFalse(self.browser.links.find_by_partial_href("example_app/docs/models/anotherexamplemodel.html"))
146
146
 
@@ -158,13 +158,13 @@ class AppReturnUrlTestCase(SeleniumTestCase):
158
158
 
159
159
  def test_app_return_url(self):
160
160
  """This test ensures that Apps return url for new objects is the list view."""
161
- self.browser.visit(f'{self.live_server_url}{reverse("plugins:example_app:examplemodel_add")}')
161
+ self.browser.visit(f"{self.live_server_url}{reverse('plugins:example_app:examplemodel_add')}")
162
162
 
163
163
  form = self.browser.find_by_tag("form")
164
164
 
165
165
  # Check that the Cancel button is a link to the examplemodel_list view.
166
166
  element = form.first.links.find_by_text("Cancel").first
167
- self.assertEqual(element["href"], f'{self.live_server_url}{reverse("plugins:example_app:examplemodel_list")}')
167
+ self.assertEqual(element["href"], f"{self.live_server_url}{reverse('plugins:example_app:examplemodel_list')}")
168
168
 
169
169
 
170
170
  class AppTabsTestCase(SeleniumTestCase):
@@ -193,7 +193,7 @@ class AppTabsTestCase(SeleniumTestCase):
193
193
  status=status,
194
194
  )
195
195
  # Visit the circuit's detail page and check that the tab is visible
196
- self.browser.visit(f'{self.live_server_url}{reverse("circuits:circuit", args=[str(circuit.pk)])}')
196
+ self.browser.visit(f"{self.live_server_url}{reverse('circuits:circuit', args=[str(circuit.pk)])}")
197
197
  self.assertTrue(self.browser.is_text_present("App Tab"))
198
198
  # Visit the tab link and check the view content
199
199
  self.browser.links.find_by_partial_text("Example App Tab")[0].click()
@@ -210,7 +210,7 @@ class AppTabsTestCase(SeleniumTestCase):
210
210
  # Set up the required objects:
211
211
  device = create_test_device("Test Device")
212
212
  # Visit the device's detail page and check that the tab is visible
213
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", args=[str(device.pk)])}')
213
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', args=[str(device.pk)])}")
214
214
  for tab_i in [1, 2]:
215
215
  self.assertTrue(self.browser.is_text_present(f"Example App Tab {tab_i}"))
216
216
  # Visit the tab link and check the view content
@@ -51,7 +51,7 @@ class RelationshipsTestCase(SeleniumTestCase):
51
51
  destination=power_panel,
52
52
  )
53
53
  # Visit the device detail page
54
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": device.pk})}')
54
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': device.pk})}")
55
55
  # Check the relationship appears in the primary information tab
56
56
  self.assertTrue(self.browser.is_text_present("power panel"))
57
57
  self.assertTrue(self.browser.is_text_present("Power Panel"))
@@ -63,7 +63,7 @@ class RelationshipsTestCase(SeleniumTestCase):
63
63
  relationship.advanced_ui = True
64
64
  relationship.save()
65
65
  # Visit the device detail page
66
- self.browser.visit(f'{self.live_server_url}{reverse("dcim:device", kwargs={"pk": device.pk})}')
66
+ self.browser.visit(f"{self.live_server_url}{reverse('dcim:device', kwargs={'pk': device.pk})}")
67
67
  # Check the relationship does NOT appear in the primary information tab
68
68
  self.assertFalse(self.browser.is_text_present("power panel"))
69
69
  self.assertFalse(self.browser.is_text_present("Power Panel"))
@@ -171,6 +171,8 @@ class ComputedFieldTestCase(FilterTestCases.FilterTestCase):
171
171
  def test_content_type(self):
172
172
  params = {"content_type": "dcim.location"}
173
173
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
174
+ params = {"content_type__n": "dcim.location"}
175
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
174
176
 
175
177
 
176
178
  class ConfigContextTestCase(FilterTestCases.FilterTestCase):
@@ -650,6 +652,8 @@ class ExportTemplateTestCase(FilterTestCases.FilterTestCase):
650
652
  def test_content_type(self):
651
653
  params = {"content_type": ContentType.objects.get(model="location").pk}
652
654
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
655
+ params = {"content_type__n": ContentType.objects.get(model="location").pk}
656
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
653
657
 
654
658
 
655
659
  class FileProxyTestCase(FilterTestCases.FilterTestCase):
@@ -865,6 +869,8 @@ class ImageAttachmentTestCase(FilterTestCases.FilterTestCase):
865
869
  def test_content_type(self):
866
870
  params = {"content_type": "dcim.location"}
867
871
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
872
+ params = {"content_type__n": "dcim.location"}
873
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
868
874
 
869
875
  def test_content_type_id_and_object_id(self):
870
876
  params = {
@@ -981,6 +987,7 @@ class JobResultFilterSetTestCase(FilterTestCases.FilterTestCase):
981
987
  filterset = JobResultFilterSet
982
988
  generic_filter_tests = (
983
989
  ("date_created",),
990
+ ("date_started",),
984
991
  ("date_done",),
985
992
  ("job_model", "job_model__id"),
986
993
  ("job_model", "job_model__name"),
@@ -1091,6 +1098,8 @@ class JobHookFilterSetTestCase(FilterTestCases.FilterTestCase):
1091
1098
  def test_content_types(self):
1092
1099
  params = {"content_types": ["dcim.devicetype"]}
1093
1100
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
1101
+ params = {"content_types__n": ["dcim.devicetype"]}
1102
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
1094
1103
 
1095
1104
  def test_enabled(self):
1096
1105
  params = {"enabled": True}
@@ -1101,9 +1101,9 @@ class DeprecatedAliasesTestCase(TestCase):
1101
1101
 
1102
1102
  def test_deprecated_form_mixin_classes(self):
1103
1103
  # Importing these mixin classes doesn't directly warn, but subclassing them does.
1104
- from nautobot.extras.forms import (
1104
+ from nautobot.extras.forms import CustomFieldBulkCreateForm
1105
+ from nautobot.extras.forms.mixins import (
1105
1106
  AddRemoveTagsForm,
1106
- CustomFieldBulkCreateForm,
1107
1107
  CustomFieldBulkEditForm,
1108
1108
  CustomFieldModelForm,
1109
1109
  RelationshipModelForm,
@@ -393,6 +393,18 @@ class PluginDetailViewTest(TestCase):
393
393
  self.assertIn("For testing purposes only", response_body, msg=response_body)
394
394
 
395
395
 
396
+ class MarketplaceViewTest(TestCase):
397
+ def test_view_anonymous(self):
398
+ self.client.logout()
399
+ response = self.client.get(reverse("apps:apps_marketplace"))
400
+ # Redirects to the login page
401
+ self.assertHttpStatus(response, 302)
402
+
403
+ def test_view_authenticated(self):
404
+ response = self.client.get(reverse("apps:apps_marketplace"))
405
+ self.assertHttpStatus(response, 200)
406
+
407
+
396
408
  class AppAPITest(APIViewTestCases.APIViewTestCase):
397
409
  model = ExampleModel
398
410
  bulk_update_data = {
@@ -888,11 +900,10 @@ class TestAppCoreViewOverrides(TestCase):
888
900
  self.assertEqual("Hello world! I'm an overridden view.", response.content.decode(response.charset))
889
901
 
890
902
  response = self.client.get(
891
- f'{reverse("plugins:plugin_detail", kwargs={"plugin": "example_app_with_view_override"})}'
903
+ f"{reverse('plugins:plugin_detail', kwargs={'plugin': 'example_app_with_view_override'})}"
892
904
  )
893
905
  self.assertIn(
894
- "plugins:example_app:view_to_be_overridden <code>"
895
- "example_app_with_view_override.views.ViewOverride</code>",
906
+ "plugins:example_app:view_to_be_overridden <code>example_app_with_view_override.views.ViewOverride</code>",
896
907
  extract_page_body(response.content.decode(response.charset)),
897
908
  )
898
909
 
@@ -1670,7 +1670,7 @@ class RequiredRelationshipTestMixin:
1670
1670
  response = self.send_data(
1671
1671
  from_model,
1672
1672
  {
1673
- "name": f'{params["create_data"]["name"]} edited',
1673
+ "name": f"{params['create_data']['name']} edited",
1674
1674
  "relationships": {},
1675
1675
  },
1676
1676
  interact_with,
@@ -1688,13 +1688,13 @@ class RequiredRelationshipTestMixin:
1688
1688
  # Object is updated with the required relationship data (succeeds)
1689
1689
  response = self.send_data(
1690
1690
  from_model,
1691
- {"name": f'{params["create_data"]["name"]} edited', **related_objects_data},
1691
+ {"name": f"{params['create_data']['name']} edited", **related_objects_data},
1692
1692
  interact_with,
1693
1693
  action="edit",
1694
1694
  url_kwargs={"pk": newly_created_object.pk},
1695
1695
  )
1696
1696
  self.assertHttpStatus(response, 200)
1697
- self.assertEqual(f'{params["create_data"]["name"]} edited', response.json()["name"])
1697
+ self.assertEqual(f"{params['create_data']['name']} edited", response.json()["name"])
1698
1698
 
1699
1699
  """
1700
1700
  - Object is created with the required relationship data (succeeds)
@@ -1704,7 +1704,7 @@ class RequiredRelationshipTestMixin:
1704
1704
  """
1705
1705
 
1706
1706
  # Delete the object that was previously created, so we can test with the same data again
1707
- from_model.objects.get(name=f'{params["create_data"]["name"]} edited').delete()
1707
+ from_model.objects.get(name=f"{params['create_data']['name']} edited").delete()
1708
1708
  self.assertEqual(from_model.objects.count(), existing_count)
1709
1709
 
1710
1710
  # Object is created with the required relationship data (succeeds)
@@ -1718,19 +1718,19 @@ class RequiredRelationshipTestMixin:
1718
1718
  newly_created_object = from_model.objects.get(name=params["create_data"]["name"])
1719
1719
  response = self.send_data(
1720
1720
  from_model,
1721
- {"name": f'{params["create_data"]["name"]} changed'},
1721
+ {"name": f"{params['create_data']['name']} changed"},
1722
1722
  interact_with,
1723
1723
  action="edit",
1724
1724
  url_kwargs={"pk": newly_created_object.pk},
1725
1725
  )
1726
1726
  self.assertHttpStatus(response, 200)
1727
- self.assertEqual(f'{params["create_data"]["name"]} changed', response.json()["name"])
1727
+ self.assertEqual(f"{params['create_data']['name']} changed", response.json()["name"])
1728
1728
 
1729
1729
  # Object is updated to remove the relationship data (fails)
1730
1730
  response = self.send_data(
1731
1731
  from_model,
1732
1732
  {
1733
- "name": f'{params["create_data"]["name"]} changed again',
1733
+ "name": f"{params['create_data']['name']} changed again",
1734
1734
  "relationships": {},
1735
1735
  },
1736
1736
  interact_with,