nautobot 2.4.0b1__py3-none-any.whl → 2.4.1__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 (601) hide show
  1. nautobot/apps/__init__.py +1 -1
  2. nautobot/apps/api.py +8 -8
  3. nautobot/apps/change_logging.py +2 -2
  4. nautobot/apps/choices.py +4 -4
  5. nautobot/apps/events.py +3 -3
  6. nautobot/apps/factory.py +2 -2
  7. nautobot/apps/filters.py +1 -1
  8. nautobot/apps/forms.py +20 -20
  9. nautobot/apps/graphql.py +2 -2
  10. nautobot/apps/jobs.py +8 -8
  11. nautobot/apps/models.py +19 -19
  12. nautobot/apps/tables.py +1 -1
  13. nautobot/apps/testing.py +10 -10
  14. nautobot/apps/ui.py +2 -2
  15. nautobot/apps/utils.py +7 -7
  16. nautobot/apps/views.py +7 -7
  17. nautobot/circuits/api/serializers.py +1 -0
  18. nautobot/circuits/api/views.py +4 -8
  19. nautobot/circuits/tables.py +2 -1
  20. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  21. nautobot/circuits/views.py +3 -3
  22. nautobot/cloud/api/views.py +6 -10
  23. nautobot/cloud/models.py +1 -1
  24. nautobot/cloud/views.py +0 -16
  25. nautobot/core/api/constants.py +11 -0
  26. nautobot/core/api/fields.py +5 -5
  27. nautobot/core/api/filter_backends.py +3 -9
  28. nautobot/core/api/schema.py +13 -2
  29. nautobot/core/api/serializers.py +40 -34
  30. nautobot/core/api/views.py +56 -4
  31. nautobot/core/celery/log.py +4 -4
  32. nautobot/core/celery/schedulers.py +2 -2
  33. nautobot/core/choices.py +2 -2
  34. nautobot/core/events/__init__.py +3 -3
  35. nautobot/core/filters.py +67 -35
  36. nautobot/core/forms/__init__.py +19 -19
  37. nautobot/core/forms/fields.py +14 -11
  38. nautobot/core/forms/forms.py +33 -2
  39. nautobot/core/graphql/types.py +1 -1
  40. nautobot/core/jobs/__init__.py +28 -7
  41. nautobot/core/jobs/bulk_actions.py +285 -0
  42. nautobot/core/jobs/cleanup.py +48 -12
  43. nautobot/core/jobs/groups.py +1 -1
  44. nautobot/core/management/commands/validate_models.py +1 -1
  45. nautobot/core/models/__init__.py +3 -1
  46. nautobot/core/models/query_functions.py +2 -2
  47. nautobot/core/models/tree_queries.py +6 -3
  48. nautobot/core/settings.py +29 -2
  49. nautobot/core/settings.yaml +21 -0
  50. nautobot/core/tables.py +79 -61
  51. nautobot/core/templates/about.html +67 -0
  52. nautobot/core/templates/inc/media.html +3 -0
  53. nautobot/core/templates/inc/nav_menu.html +1 -0
  54. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  55. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  56. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  57. nautobot/core/templates/search.html +7 -0
  58. nautobot/core/templates/utilities/render_jinja2.html +1 -1
  59. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  60. nautobot/core/templates/utilities/theme_preview.html +7 -0
  61. nautobot/core/templatetags/helpers.py +11 -2
  62. nautobot/core/testing/__init__.py +8 -8
  63. nautobot/core/testing/api.py +170 -15
  64. nautobot/core/testing/filters.py +45 -10
  65. nautobot/core/testing/forms.py +2 -0
  66. nautobot/core/testing/integration.py +86 -4
  67. nautobot/core/testing/mixins.py +7 -2
  68. nautobot/core/testing/views.py +44 -29
  69. nautobot/core/tests/integration/test_app_home.py +0 -1
  70. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  71. nautobot/core/tests/integration/test_filters.py +0 -2
  72. nautobot/core/tests/integration/test_home.py +0 -1
  73. nautobot/core/tests/integration/test_navbar.py +0 -1
  74. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  75. nautobot/core/tests/runner.py +1 -1
  76. nautobot/core/tests/test_api.py +98 -1
  77. nautobot/core/tests/test_csv.py +25 -3
  78. nautobot/core/tests/test_filters.py +209 -246
  79. nautobot/core/tests/test_forms.py +1 -0
  80. nautobot/core/tests/test_jobs.py +460 -1
  81. nautobot/core/tests/test_models.py +9 -0
  82. nautobot/core/tests/test_settings_schema.py +7 -0
  83. nautobot/core/tests/test_tables.py +100 -0
  84. nautobot/core/tests/test_utils.py +63 -1
  85. nautobot/core/tests/test_views.py +30 -3
  86. nautobot/core/ui/nav.py +1 -0
  87. nautobot/core/ui/object_detail.py +15 -1
  88. nautobot/core/urls.py +11 -0
  89. nautobot/core/utils/lookup.py +11 -8
  90. nautobot/core/utils/querysets.py +64 -0
  91. nautobot/core/utils/requests.py +24 -9
  92. nautobot/core/views/__init__.py +42 -0
  93. nautobot/core/views/generic.py +131 -197
  94. nautobot/core/views/mixins.py +126 -38
  95. nautobot/core/views/renderers.py +6 -6
  96. nautobot/dcim/api/serializers.py +56 -64
  97. nautobot/dcim/api/views.py +47 -113
  98. nautobot/dcim/constants.py +6 -13
  99. nautobot/dcim/factory.py +6 -1
  100. nautobot/dcim/filters/__init__.py +31 -2
  101. nautobot/dcim/forms.py +36 -17
  102. nautobot/dcim/graphql/types.py +2 -2
  103. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  104. nautobot/dcim/models/__init__.py +1 -1
  105. nautobot/dcim/models/device_component_templates.py +2 -2
  106. nautobot/dcim/models/device_components.py +22 -20
  107. nautobot/dcim/models/devices.py +10 -1
  108. nautobot/dcim/models/locations.py +3 -3
  109. nautobot/dcim/models/power.py +6 -5
  110. nautobot/dcim/models/racks.py +4 -4
  111. nautobot/dcim/tables/__init__.py +3 -3
  112. nautobot/dcim/tables/devices.py +7 -5
  113. nautobot/dcim/tables/devicetypes.py +2 -2
  114. nautobot/dcim/tables/racks.py +1 -1
  115. nautobot/dcim/templates/dcim/controller_create.html +1 -7
  116. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
  117. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
  118. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
  119. nautobot/dcim/templates/dcim/device.html +1 -9
  120. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  121. nautobot/dcim/templates/dcim/location.html +1 -9
  122. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  123. nautobot/dcim/templates/dcim/rack.html +1 -9
  124. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  125. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  126. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
  127. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
  128. nautobot/dcim/tests/integration/test_controller.py +62 -0
  129. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  130. nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
  131. nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
  132. nautobot/dcim/tests/test_api.py +16 -5
  133. nautobot/dcim/tests/test_filters.py +33 -0
  134. nautobot/dcim/tests/test_forms.py +51 -2
  135. nautobot/dcim/tests/test_graphql.py +52 -0
  136. nautobot/dcim/tests/test_jobs.py +118 -0
  137. nautobot/dcim/tests/test_models.py +52 -9
  138. nautobot/dcim/tests/test_views.py +21 -83
  139. nautobot/dcim/views.py +1 -13
  140. nautobot/extras/api/customfields.py +2 -2
  141. nautobot/extras/api/serializers.py +90 -85
  142. nautobot/extras/api/views.py +22 -27
  143. nautobot/extras/constants.py +2 -0
  144. nautobot/extras/filters/__init__.py +8 -6
  145. nautobot/extras/forms/base.py +2 -2
  146. nautobot/extras/forms/forms.py +139 -31
  147. nautobot/extras/forms/mixins.py +14 -6
  148. nautobot/extras/group_sync.py +3 -3
  149. nautobot/extras/health_checks.py +1 -2
  150. nautobot/extras/jobs.py +85 -18
  151. nautobot/extras/managers.py +3 -1
  152. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  153. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  154. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  155. nautobot/extras/models/__init__.py +1 -1
  156. nautobot/extras/models/contacts.py +1 -1
  157. nautobot/extras/models/customfields.py +12 -11
  158. nautobot/extras/models/groups.py +11 -9
  159. nautobot/extras/models/jobs.py +23 -4
  160. nautobot/extras/models/models.py +2 -2
  161. nautobot/extras/plugins/__init__.py +13 -2
  162. nautobot/extras/plugins/marketplace_manifest.yml +84 -79
  163. nautobot/extras/plugins/tables.py +16 -14
  164. nautobot/extras/plugins/views.py +65 -69
  165. nautobot/extras/registry.py +1 -1
  166. nautobot/extras/secrets/__init__.py +2 -2
  167. nautobot/extras/tables.py +7 -5
  168. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  169. nautobot/extras/templates/extras/job_detail.html +16 -0
  170. nautobot/extras/templates/extras/job_edit.html +1 -0
  171. nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
  172. nautobot/extras/templates/extras/marketplace.html +29 -11
  173. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  174. nautobot/extras/templates/extras/plugins_tiles.html +21 -10
  175. nautobot/extras/templatetags/job_buttons.py +4 -4
  176. nautobot/extras/test_jobs/api_test_job.py +1 -1
  177. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  178. nautobot/extras/test_jobs/dry_run.py +1 -1
  179. nautobot/extras/test_jobs/fail.py +5 -5
  180. nautobot/extras/test_jobs/file_output.py +1 -1
  181. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  182. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  183. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  184. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  185. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  186. nautobot/extras/test_jobs/log_redaction.py +1 -1
  187. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  188. nautobot/extras/test_jobs/modify_db.py +1 -1
  189. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  190. nautobot/extras/test_jobs/object_var_required.py +1 -1
  191. nautobot/extras/test_jobs/object_vars.py +1 -1
  192. nautobot/extras/test_jobs/pass.py +3 -3
  193. nautobot/extras/test_jobs/profiling.py +1 -1
  194. nautobot/extras/test_jobs/relative_import.py +3 -3
  195. nautobot/extras/test_jobs/singleton.py +16 -0
  196. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  197. nautobot/extras/test_jobs/task_queues.py +1 -1
  198. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  199. nautobot/extras/tests/test_api.py +13 -13
  200. nautobot/extras/tests/test_customfields.py +1 -1
  201. nautobot/extras/tests/test_datasources.py +2 -1
  202. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  203. nautobot/extras/tests/test_filters.py +6 -6
  204. nautobot/extras/tests/test_forms.py +33 -1
  205. nautobot/extras/tests/test_jobs.py +178 -32
  206. nautobot/extras/tests/test_models.py +16 -10
  207. nautobot/extras/tests/test_plugins.py +62 -9
  208. nautobot/extras/tests/test_relationships.py +120 -9
  209. nautobot/extras/tests/test_views.py +56 -194
  210. nautobot/extras/utils.py +3 -2
  211. nautobot/extras/views.py +30 -98
  212. nautobot/ipam/api/fields.py +3 -3
  213. nautobot/ipam/api/serializers.py +41 -33
  214. nautobot/ipam/api/views.py +68 -117
  215. nautobot/ipam/factory.py +1 -1
  216. nautobot/ipam/filters.py +3 -2
  217. nautobot/ipam/lookups.py +101 -62
  218. nautobot/ipam/models.py +66 -16
  219. nautobot/ipam/querysets.py +2 -2
  220. nautobot/ipam/tables.py +23 -7
  221. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  222. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  223. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  224. nautobot/ipam/templates/ipam/prefix.html +1 -9
  225. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  226. nautobot/ipam/templates/ipam/vlan.html +1 -9
  227. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  228. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  229. nautobot/ipam/tests/test_api.py +436 -3
  230. nautobot/ipam/tests/test_forms.py +49 -47
  231. nautobot/ipam/tests/test_migrations.py +30 -30
  232. nautobot/ipam/tests/test_models.py +95 -34
  233. nautobot/ipam/tests/test_querysets.py +63 -1
  234. nautobot/ipam/tests/test_views.py +3 -0
  235. nautobot/ipam/utils/__init__.py +36 -6
  236. nautobot/ipam/views.py +61 -87
  237. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  238. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  239. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  240. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  241. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  242. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  243. nautobot/project-static/docs/404.html +46 -4
  244. nautobot/project-static/docs/apps/index.html +46 -4
  245. nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
  246. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  247. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
  248. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
  249. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
  250. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
  251. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
  252. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
  253. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
  254. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
  255. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
  256. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
  257. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
  258. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
  259. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
  260. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
  261. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
  262. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
  263. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
  264. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
  265. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
  266. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
  267. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
  268. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
  269. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
  270. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
  271. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
  272. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
  273. nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
  274. nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
  275. nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
  276. nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
  277. nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
  278. nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
  279. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
  280. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
  281. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
  282. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
  283. nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
  284. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
  285. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
  286. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
  287. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
  288. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
  289. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
  290. nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
  291. nautobot/project-static/docs/development/apps/api/setup.html +46 -4
  292. nautobot/project-static/docs/development/apps/api/testing.html +46 -4
  293. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
  294. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
  295. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
  296. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
  297. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
  298. nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
  299. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
  300. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
  301. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
  302. nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
  303. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
  304. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
  305. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
  306. nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
  307. nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
  308. nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
  309. nautobot/project-static/docs/development/apps/index.html +46 -4
  310. nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
  311. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
  312. nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
  313. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
  314. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
  315. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
  316. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
  317. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
  318. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
  319. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
  320. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
  321. nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
  322. nautobot/project-static/docs/development/core/application-registry.html +46 -4
  323. nautobot/project-static/docs/development/core/best-practices.html +46 -4
  324. nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
  325. nautobot/project-static/docs/development/core/caching.html +46 -4
  326. nautobot/project-static/docs/development/core/controllers.html +46 -4
  327. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
  328. nautobot/project-static/docs/development/core/generic-views.html +46 -4
  329. nautobot/project-static/docs/development/core/getting-started.html +249 -224
  330. nautobot/project-static/docs/development/core/homepage.html +49 -7
  331. nautobot/project-static/docs/development/core/index.html +46 -4
  332. nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
  333. nautobot/project-static/docs/development/core/model-checklist.html +56 -12
  334. nautobot/project-static/docs/development/core/model-features.html +46 -4
  335. nautobot/project-static/docs/development/core/natural-keys.html +46 -4
  336. nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
  337. nautobot/project-static/docs/development/core/release-checklist.html +49 -7
  338. nautobot/project-static/docs/development/core/role-internals.html +46 -4
  339. nautobot/project-static/docs/development/core/settings.html +46 -4
  340. nautobot/project-static/docs/development/core/style-guide.html +49 -7
  341. nautobot/project-static/docs/development/core/templates.html +46 -4
  342. nautobot/project-static/docs/development/core/testing.html +46 -4
  343. nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
  344. nautobot/project-static/docs/development/core/user-preferences.html +46 -4
  345. nautobot/project-static/docs/development/index.html +46 -4
  346. nautobot/project-static/docs/development/jobs/index.html +216 -122
  347. nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
  348. nautobot/project-static/docs/index.html +54 -23
  349. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  350. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  351. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  352. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  353. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  354. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  355. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  356. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  357. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  358. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  359. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  360. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  361. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  362. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  363. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  364. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  365. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  366. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  367. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  368. nautobot/project-static/docs/objects.inv +0 -0
  369. nautobot/project-static/docs/overview/application_stack.html +47 -7
  370. nautobot/project-static/docs/overview/design_philosophy.html +46 -4
  371. nautobot/project-static/docs/release-notes/index.html +52 -12
  372. nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
  373. nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
  374. nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
  375. nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
  376. nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
  377. nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
  378. nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
  379. nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
  380. nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
  381. nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
  382. nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
  383. nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
  384. nautobot/project-static/docs/requirements.txt +2 -2
  385. nautobot/project-static/docs/search/search_index.json +1 -1
  386. nautobot/project-static/docs/sitemap.xml +295 -287
  387. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  388. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
  389. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
  390. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
  391. nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
  392. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
  393. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
  394. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
  395. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
  396. nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
  397. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
  398. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
  399. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
  400. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
  401. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
  402. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
  403. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
  404. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
  405. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
  406. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
  407. nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
  408. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
  409. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
  410. nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
  411. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
  412. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
  413. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
  414. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
  415. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
  416. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
  417. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
  418. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
  419. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
  420. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
  421. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
  422. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
  423. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
  424. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
  425. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
  426. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
  427. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
  428. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
  429. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
  430. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
  431. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
  432. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
  433. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
  434. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
  435. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
  436. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
  437. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
  438. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
  439. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
  440. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
  441. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
  442. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
  443. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
  444. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
  445. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
  446. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
  447. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
  448. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
  449. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
  450. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
  451. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
  452. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
  453. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
  454. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
  455. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
  456. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
  457. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
  458. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
  459. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
  460. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
  461. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
  462. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
  463. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
  464. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
  465. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
  466. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
  467. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
  468. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
  469. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
  470. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
  471. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
  472. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
  473. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
  474. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
  475. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
  476. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
  477. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
  478. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
  479. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
  480. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
  481. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
  482. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
  483. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
  484. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
  485. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
  486. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
  487. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
  488. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
  489. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
  490. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
  491. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
  492. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
  493. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
  494. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
  495. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
  496. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
  497. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
  498. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
  499. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
  500. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
  501. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
  502. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
  503. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
  504. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
  505. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
  506. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
  507. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
  508. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
  509. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
  510. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
  511. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
  512. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
  513. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
  514. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
  515. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
  516. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  517. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  518. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  519. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  520. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  521. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  522. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  523. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  524. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  525. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  526. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  527. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  528. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  529. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
  530. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
  531. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
  532. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  533. nautobot/project-static/docs/user-guide/index.html +46 -4
  534. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
  535. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
  536. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
  537. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
  538. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
  539. nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
  540. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
  541. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
  542. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
  543. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
  544. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
  545. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
  546. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
  547. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
  548. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
  549. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
  550. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
  551. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  552. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
  553. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
  554. nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
  555. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
  556. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
  557. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
  558. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
  559. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
  560. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
  561. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
  562. nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
  563. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
  564. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
  565. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
  566. nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
  567. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
  568. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
  569. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
  570. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
  571. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
  572. nautobot/project-static/js/forms.js +1 -1
  573. nautobot/tenancy/api/views.py +9 -13
  574. nautobot/tenancy/views.py +4 -2
  575. nautobot/users/admin.py +1 -1
  576. nautobot/users/api/serializers.py +5 -4
  577. nautobot/users/api/views.py +3 -3
  578. nautobot/virtualization/api/serializers.py +4 -4
  579. nautobot/virtualization/api/views.py +5 -24
  580. nautobot/virtualization/filters.py +20 -3
  581. nautobot/virtualization/models.py +1 -1
  582. nautobot/virtualization/tables.py +2 -2
  583. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  584. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  585. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  586. nautobot/virtualization/tests/test_filters.py +17 -0
  587. nautobot/wireless/filters.py +2 -2
  588. nautobot/wireless/forms.py +1 -1
  589. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
  590. nautobot/wireless/tests/integration/__init__.py +0 -0
  591. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  592. nautobot/wireless/tests/test_filters.py +29 -1
  593. nautobot/wireless/tests/test_views.py +22 -1
  594. nautobot/wireless/views.py +0 -10
  595. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
  596. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
  597. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
  598. nautobot/core/fixtures/user-data.json +0 -59
  599. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
  600. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
  601. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
  <link rel="icon" href="../../assets/favicon.ico">
21
- <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.5.46">
21
+ <meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.5.49">
22
22
 
23
23
 
24
24
 
@@ -2117,6 +2117,27 @@
2117
2117
 
2118
2118
 
2119
2119
 
2120
+
2121
+
2122
+
2123
+
2124
+
2125
+
2126
+ <li class="md-nav__item">
2127
+ <a href="../feature-guides/wireless-networks-and-controllers.html" class="md-nav__link">
2128
+
2129
+
2130
+ <span class="md-ellipsis">
2131
+ Wireless Networks and Controllers
2132
+ </span>
2133
+
2134
+
2135
+ </a>
2136
+ </li>
2137
+
2138
+
2139
+
2140
+
2120
2141
  </ul>
2121
2142
  </nav>
2122
2143
 
@@ -5138,6 +5159,27 @@
5138
5159
 
5139
5160
 
5140
5161
 
5162
+ <li class="md-nav__item">
5163
+ <a href="jobs/kubernetes-job-support.html" class="md-nav__link">
5164
+
5165
+
5166
+ <span class="md-ellipsis">
5167
+ Kubernetes Job Support
5168
+ </span>
5169
+
5170
+
5171
+ </a>
5172
+ </li>
5173
+
5174
+
5175
+
5176
+
5177
+
5178
+
5179
+
5180
+
5181
+
5182
+
5141
5183
  <li class="md-nav__item">
5142
5184
  <a href="jobs/jobbutton.html" class="md-nav__link">
5143
5185
 
@@ -8162,11 +8204,11 @@
8162
8204
 
8163
8205
 
8164
8206
  <li class="md-nav__item">
8165
- <a href="../../development/core/local-k8s.html" class="md-nav__link">
8207
+ <a href="../../development/core/minikube-dev-environment-for-k8s-jobs.html" class="md-nav__link">
8166
8208
 
8167
8209
 
8168
8210
  <span class="md-ellipsis">
8169
- Local Kubernetes Cluster
8211
+ Minikube Dev Environment for K8s Jobs
8170
8212
  </span>
8171
8213
 
8172
8214
 
@@ -9420,7 +9462,7 @@
9420
9462
  <script id="__config" type="application/json">{"base": "../..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "navigation.footer", "navigation.tabs", "navigation.tabs.sticky", "navigation.tracking", "search.highlight", "search.share", "search.suggest"], "search": "../../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
9421
9463
 
9422
9464
 
9423
- <script src="../../assets/javascripts/bundle.83f73b43.min.js"></script>
9465
+ <script src="../../assets/javascripts/bundle.88dd0f4e.min.js"></script>
9424
9466
 
9425
9467
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
9426
9468
 
@@ -210,7 +210,7 @@ function initializeDynamicChoiceSelection(context, dropdownParent=null){
210
210
  this_context = $(context);
211
211
  this_context.find('.nautobot-select2-api').each(function(){
212
212
  thisobj = $(this);
213
- placeholder = thisobj.attr("data-null-option") || "---------";
213
+ placeholder = "---------";
214
214
  thisobj.select2({
215
215
  allowClear: true,
216
216
  placeholder: placeholder,
@@ -26,19 +26,15 @@ class TenantGroupViewSet(NautobotModelViewSet):
26
26
 
27
27
 
28
28
  class TenantViewSet(NautobotModelViewSet):
29
- queryset = (
30
- Tenant.objects.select_related("tenant_group")
31
- .prefetch_related("tags")
32
- .annotate(
33
- circuit_count=count_related(Circuit, "tenant"),
34
- device_count=count_related(Device, "tenant"),
35
- ipaddress_count=count_related(IPAddress, "tenant"),
36
- prefix_count=count_related(Prefix, "tenant"),
37
- rack_count=count_related(Rack, "tenant"),
38
- virtualmachine_count=count_related(VirtualMachine, "tenant"),
39
- vlan_count=count_related(VLAN, "tenant"),
40
- vrf_count=count_related(VRF, "tenant"),
41
- )
29
+ queryset = Tenant.objects.annotate(
30
+ circuit_count=count_related(Circuit, "tenant"),
31
+ device_count=count_related(Device, "tenant"),
32
+ ipaddress_count=count_related(IPAddress, "tenant"),
33
+ prefix_count=count_related(Prefix, "tenant"),
34
+ rack_count=count_related(Rack, "tenant"),
35
+ virtualmachine_count=count_related(VirtualMachine, "tenant"),
36
+ vlan_count=count_related(VLAN, "tenant"),
37
+ vrf_count=count_related(VRF, "tenant"),
42
38
  )
43
39
  serializer_class = serializers.TenantSerializer
44
40
  filterset_class = filters.TenantFilterSet
nautobot/tenancy/views.py CHANGED
@@ -5,7 +5,7 @@ from nautobot.core.ui.choices import SectionChoices
5
5
  from nautobot.core.ui.object_detail import ObjectDetailContent, ObjectFieldsPanel, StatsPanel
6
6
  from nautobot.core.views import generic
7
7
  from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
8
- from nautobot.dcim.models import Device, Location, Rack, RackReservation
8
+ from nautobot.dcim.models import Controller, ControllerManagedDeviceGroup, Device, Location, Rack, RackReservation
9
9
  from nautobot.extras.models import DynamicGroup
10
10
  from nautobot.ipam.models import IPAddress, Prefix, VLAN, VRF
11
11
  from nautobot.virtualization.models import Cluster, VirtualMachine
@@ -93,14 +93,16 @@ class TenantView(generic.ObjectView):
93
93
  related_models=[
94
94
  Circuit,
95
95
  Cluster,
96
+ Controller,
97
+ ControllerManagedDeviceGroup,
96
98
  Device,
99
+ DynamicGroup,
97
100
  IPAddress,
98
101
  # TODO: Should we include child locations of the filtered locations in the location_count below?
99
102
  Location,
100
103
  Prefix,
101
104
  Rack,
102
105
  RackReservation,
103
- DynamicGroup,
104
106
  VirtualMachine,
105
107
  VLAN,
106
108
  VRF,
nautobot/users/admin.py CHANGED
@@ -45,7 +45,7 @@ class ObjectPermissionInline(admin.TabularInline):
45
45
 
46
46
 
47
47
  class GroupObjectPermissionInline(ObjectPermissionInline):
48
- model = AdminGroup.object_permissions.through
48
+ model = AdminGroup.object_permissions.through # pylint: disable=no-member
49
49
 
50
50
 
51
51
  class UserObjectPermissionInline(ObjectPermissionInline):
@@ -18,13 +18,13 @@ class UserSerializer(ValidatedModelSerializer):
18
18
  exclude = ["user_permissions"]
19
19
  extra_kwargs = {"password": {"write_only": True, "required": False, "allow_null": True}}
20
20
 
21
- def validate(self, data):
21
+ def validate(self, attrs):
22
22
  """Handle omission of a password by setting it to the unusable None value."""
23
23
  mock_password = False
24
- if "password" not in data and not self.partial:
25
- data["password"] = make_password(None)
24
+ if "password" not in attrs and not self.partial:
25
+ attrs["password"] = make_password(None)
26
26
  mock_password = True
27
- validated_data = super().validate(data)
27
+ validated_data = super().validate(attrs)
28
28
  if mock_password:
29
29
  validated_data["password"] = None
30
30
  return validated_data
@@ -59,6 +59,7 @@ class UserSerializer(ValidatedModelSerializer):
59
59
 
60
60
 
61
61
  class GroupSerializer(ValidatedModelSerializer):
62
+ id = serializers.IntegerField(read_only=True)
62
63
  url = serializers.HyperlinkedIdentityField(view_name="users-api:group-detail")
63
64
  user_count = serializers.IntegerField(read_only=True)
64
65
 
@@ -22,7 +22,7 @@ from . import serializers
22
22
 
23
23
 
24
24
  class UserViewSet(ModelViewSet):
25
- queryset = RestrictedQuerySet(model=get_user_model()).prefetch_related("groups").order_by("username")
25
+ queryset = RestrictedQuerySet(model=get_user_model()).order_by("username")
26
26
  serializer_class = serializers.UserSerializer
27
27
  filterset_class = filters.UserFilterSet
28
28
 
@@ -43,7 +43,7 @@ class GroupViewSet(ModelViewSet):
43
43
 
44
44
 
45
45
  class TokenViewSet(ModelViewSet):
46
- queryset = RestrictedQuerySet(model=Token).select_related("user")
46
+ queryset = RestrictedQuerySet(model=Token).select_related("user") # pylint: disable=not-callable # no idea why?
47
47
  serializer_class = serializers.TokenSerializer
48
48
  filterset_class = filters.TokenFilterSet
49
49
 
@@ -69,7 +69,7 @@ class TokenViewSet(ModelViewSet):
69
69
 
70
70
 
71
71
  class ObjectPermissionViewSet(ModelViewSet):
72
- queryset = ObjectPermission.objects.prefetch_related("object_types", "groups", "users")
72
+ queryset = ObjectPermission.objects.all()
73
73
  serializer_class = serializers.ObjectPermissionSerializer
74
74
  filterset_class = filters.ObjectPermissionFilterSet
75
75
 
@@ -87,10 +87,10 @@ class VMInterfaceSerializer(
87
87
  model = VMInterface
88
88
  fields = "__all__"
89
89
 
90
- def validate(self, data):
90
+ def validate(self, attrs):
91
91
  # Validate many-to-many VLAN assignments
92
- virtual_machine = self.instance.virtual_machine if self.instance else data.get("virtual_machine")
93
- for vlan in data.get("tagged_vlans", []):
92
+ virtual_machine = self.instance.virtual_machine if self.instance else attrs.get("virtual_machine")
93
+ for vlan in attrs.get("tagged_vlans", []):
94
94
  if vlan.location not in [virtual_machine.location, None]:
95
95
  raise serializers.ValidationError(
96
96
  {
@@ -99,4 +99,4 @@ class VMInterfaceSerializer(
99
99
  }
100
100
  )
101
101
 
102
- return super().validate(data)
102
+ return super().validate(attrs)
@@ -35,13 +35,9 @@ class ClusterGroupViewSet(NautobotModelViewSet):
35
35
 
36
36
 
37
37
  class ClusterViewSet(NautobotModelViewSet):
38
- queryset = (
39
- Cluster.objects.select_related("cluster_type", "cluster_group", "tenant", "location")
40
- .prefetch_related("tags")
41
- .annotate(
42
- device_count=count_related(Device, "cluster"),
43
- virtualmachine_count=count_related(VirtualMachine, "cluster"),
44
- )
38
+ queryset = Cluster.objects.annotate(
39
+ device_count=count_related(Device, "cluster"),
40
+ virtualmachine_count=count_related(VirtualMachine, "cluster"),
45
41
  )
46
42
  serializer_class = serializers.ClusterSerializer
47
43
  filterset_class = filters.ClusterFilterSet
@@ -53,27 +49,12 @@ class ClusterViewSet(NautobotModelViewSet):
53
49
 
54
50
 
55
51
  class VirtualMachineViewSet(ConfigContextQuerySetMixin, NautobotModelViewSet):
56
- queryset = VirtualMachine.objects.select_related(
57
- "cluster__location",
58
- "platform",
59
- "primary_ip4",
60
- "primary_ip6",
61
- "status",
62
- "role",
63
- "software_version",
64
- "tenant",
65
- ).prefetch_related("tags")
52
+ queryset = VirtualMachine.objects.select_related("cluster__location")
66
53
  serializer_class = serializers.VirtualMachineSerializer
67
54
  filterset_class = filters.VirtualMachineFilterSet
68
55
 
69
56
 
70
57
  class VMInterfaceViewSet(NotesViewSetMixin, ModelViewSet):
71
- queryset = VMInterface.objects.select_related(
72
- "virtual_machine",
73
- "parent_interface",
74
- "bridge",
75
- "status",
76
- "untagged_vlan",
77
- ).prefetch_related("tags", "ip_addresses", "tagged_vlans")
58
+ queryset = VMInterface.objects.all()
78
59
  serializer_class = serializers.VMInterfaceSerializer
79
60
  filterset_class = filters.VMInterfaceFilterSet
@@ -30,8 +30,8 @@ __all__ = (
30
30
  "ClusterFilterSet",
31
31
  "ClusterGroupFilterSet",
32
32
  "ClusterTypeFilterSet",
33
- "VirtualMachineFilterSet",
34
33
  "VMInterfaceFilterSet",
34
+ "VirtualMachineFilterSet",
35
35
  )
36
36
 
37
37
 
@@ -224,6 +224,19 @@ class VirtualMachineFilterSet(
224
224
  to_field_name="version",
225
225
  label="Software version (version or ID)",
226
226
  )
227
+ ip_addresses = MultiValueCharFilter(
228
+ method="filter_ip_addresses",
229
+ label="IP addresses (address or ID)",
230
+ distinct=True,
231
+ )
232
+ has_ip_addresses = RelatedMembershipBooleanFilter(field_name="interfaces__ip_addresses", label="Has IP addresses")
233
+
234
+ def filter_ip_addresses(self, queryset, name, value):
235
+ pk_values = set(item for item in value if is_uuid(item))
236
+ addresses = set(item for item in value if item not in pk_values)
237
+
238
+ ip_queryset = IPAddress.objects.filter_address_or_pk_in(addresses, pk_values)
239
+ return queryset.filter(interfaces__ip_addresses__in=ip_queryset).distinct()
227
240
 
228
241
  class Meta:
229
242
  model = VirtualMachine
@@ -340,7 +353,11 @@ class VMInterfaceFilterSet(
340
353
  queryset=VLAN.objects.all(),
341
354
  label="Untagged VLAN (VID or ID)",
342
355
  )
343
- ip_addresses = MultiValueCharFilter(method="filter_ip_addresses", label="IP addresses (address or ID)")
356
+ ip_addresses = MultiValueCharFilter(
357
+ method="filter_ip_addresses",
358
+ label="IP addresses (address or ID)",
359
+ distinct=True,
360
+ )
344
361
  has_ip_addresses = RelatedMembershipBooleanFilter(field_name="ip_addresses", label="Has IP addresses")
345
362
 
346
363
  def filter_ip_addresses(self, queryset, name, value):
@@ -348,7 +365,7 @@ class VMInterfaceFilterSet(
348
365
  addresses = set(item for item in value if item not in pk_values)
349
366
 
350
367
  ip_queryset = IPAddress.objects.filter_address_or_pk_in(addresses, pk_values)
351
- return queryset.filter(ip_addresses__in=ip_queryset)
368
+ return queryset.filter(ip_addresses__in=ip_queryset).distinct()
352
369
 
353
370
  class Meta:
354
371
  model = VMInterface
@@ -22,8 +22,8 @@ __all__ = (
22
22
  "Cluster",
23
23
  "ClusterGroup",
24
24
  "ClusterType",
25
- "VirtualMachine",
26
25
  "VMInterface",
26
+ "VirtualMachine",
27
27
  )
28
28
 
29
29
 
@@ -14,13 +14,13 @@ from nautobot.tenancy.tables import TenantColumn
14
14
  from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
15
15
 
16
16
  __all__ = (
17
- "ClusterTable",
18
17
  "ClusterGroupTable",
18
+ "ClusterTable",
19
19
  "ClusterTypeTable",
20
+ "VMInterfaceTable",
20
21
  "VirtualMachineDetailTable",
21
22
  "VirtualMachineTable",
22
23
  "VirtualMachineVMInterfaceTable",
23
- "VMInterfaceTable",
24
24
  )
25
25
 
26
26
  VMINTERFACE_BUTTONS = """
@@ -11,13 +11,7 @@
11
11
  {% render_field form.location %}
12
12
  </div>
13
13
  </div>
14
- <div class="panel panel-default">
15
- <div class="panel-heading"><strong>Tenancy</strong></div>
16
- <div class="panel-body">
17
- {% render_field form.tenant_group %}
18
- {% render_field form.tenant %}
19
- </div>
20
- </div>
14
+ {% include 'inc/tenancy_form_panel.html' %}
21
15
  {% include 'inc/extras_features_edit_form_fields.html' %}
22
16
  <div class="panel panel-default">
23
17
  <div class="panel-heading"><strong>Comments</strong></div>
@@ -52,15 +52,7 @@
52
52
  {% endif %}
53
53
  </td>
54
54
  </tr>
55
- <tr>
56
- <td>Tenant</td>
57
- <td>
58
- {% if object.tenant and object.tenant.tenant_group %}
59
- {{ object.tenant.tenant_group|hyperlinked_object }} /
60
- {% endif %}
61
- {{ object.tenant|hyperlinked_object }}
62
- </td>
63
- </tr>
55
+ {% include 'inc/tenant_table_row.html' %}
64
56
  <tr>
65
57
  <td>Primary IPv4</td>
66
58
  <td>
@@ -8,6 +8,7 @@
8
8
  <div class="panel-body">
9
9
  {% render_field form.name %}
10
10
  {% render_field form.role %}
11
+ {% render_field form.status %}
11
12
  </div>
12
13
  </div>
13
14
  <div class="panel panel-default">
@@ -26,7 +27,6 @@
26
27
  <div class="panel panel-default">
27
28
  <div class="panel-heading"><strong>Management</strong></div>
28
29
  <div class="panel-body">
29
- {% render_field form.status %}
30
30
  {% render_field form.platform %}
31
31
  {% render_field form.primary_ip4 %}
32
32
  {% render_field form.primary_ip6 %}
@@ -53,13 +53,7 @@
53
53
  {% render_field form.disk %}
54
54
  </div>
55
55
  </div>
56
- <div class="panel panel-default">
57
- <div class="panel-heading"><strong>Tenancy</strong></div>
58
- <div class="panel-body">
59
- {% render_field form.tenant_group %}
60
- {% render_field form.tenant %}
61
- </div>
62
- </div>
56
+ {% include 'inc/tenancy_form_panel.html' %}
63
57
  {% include 'inc/extras_features_edit_form_fields.html' %}
64
58
  <div class="panel panel-default">
65
59
  <div class="panel-heading"><strong>Local Config Context Data</strong></div>
@@ -206,6 +206,7 @@ class VirtualMachineTestCase(FilterTestCases.FilterTestCase, FilterTestCases.Ten
206
206
  tenancy_related_name = "virtual_machines"
207
207
 
208
208
  generic_filter_tests = (
209
+ ["ip_addresses", "interfaces__ip_addresses__id"],
209
210
  ("cluster", "cluster__id"),
210
211
  ("cluster", "cluster__name"),
211
212
  ("cluster_group", "cluster__cluster_group__id"),
@@ -454,6 +455,22 @@ class VirtualMachineTestCase(FilterTestCases.FilterTestCase, FilterTestCases.Ten
454
455
  virtual_machines[i].save()
455
456
  return super().test_filters_generic()
456
457
 
458
+ def test_name(self):
459
+ params = {"name": ["Virtual Machine 1", "Virtual Machine 2"]}
460
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
461
+
462
+ def test_comments(self):
463
+ params = {"comments": ["This is VM 1", "This is VM 2"]}
464
+ self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
465
+
466
+ def test_ip_addresses(self):
467
+ ipaddresses = list(IPAddress.objects.filter(vm_interfaces__isnull=False)[:2])
468
+ params = {"ip_addresses": [ipaddresses[0].address, ipaddresses[1].id]}
469
+ self.assertQuerysetEqualAndNotEmpty(
470
+ self.filterset(params, self.queryset).qs,
471
+ self.queryset.filter(interfaces__ip_addresses__in=ipaddresses).distinct(),
472
+ )
473
+
457
474
  def test_primary_ip4(self):
458
475
  params = {"primary_ip4": ["192.0.2.1/24", self.ipaddresses[0].pk]}
459
476
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
@@ -63,7 +63,7 @@ class RadioProfileFilterSet(NautobotFilterSet):
63
63
  choices=choices.RadioProfileFrequencyChoices,
64
64
  null_value=None,
65
65
  )
66
- controller_managed_device_group = NaturalKeyOrPKMultipleChoiceFilter(
66
+ controller_managed_device_groups = NaturalKeyOrPKMultipleChoiceFilter(
67
67
  queryset=ControllerManagedDeviceGroup.objects.all(),
68
68
  to_field_name="name",
69
69
  label="Controller Managed Device Groups (name or ID)",
@@ -101,7 +101,7 @@ class WirelessNetworkFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
101
101
  to_field_name="name",
102
102
  label="Secrets group (name or ID)",
103
103
  )
104
- controller_managed_device_group = NaturalKeyOrPKMultipleChoiceFilter(
104
+ controller_managed_device_groups = NaturalKeyOrPKMultipleChoiceFilter(
105
105
  queryset=ControllerManagedDeviceGroup.objects.all(),
106
106
  to_field_name="name",
107
107
  label="Controller Managed Device Groups (name or ID)",
@@ -183,7 +183,7 @@ class RadioProfileBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
183
183
  widget=StaticSelect2(),
184
184
  )
185
185
  channel_width = JSONArrayFormField(
186
- choices=add_blank_choice(RadioProfileChannelWidthChoices),
186
+ choices=RadioProfileChannelWidthChoices,
187
187
  base_field=forms.IntegerField(),
188
188
  required=False,
189
189
  )
@@ -41,15 +41,7 @@
41
41
  <td>Hidden</td>
42
42
  <td>{{ object.hidden }}</td>
43
43
  </tr>
44
- <tr>
45
- <td>Tenant</td>
46
- <td>
47
- {% if object.tenant and object.tenant.tenant_group %}
48
- {{ object.tenant.tenant_group|hyperlinked_object }} /
49
- {% endif %}
50
- {{ object.tenant|hyperlinked_object }}
51
- </td>
52
- </tr>
44
+ {% include 'inc/tenant_table_row.html' %}
53
45
  </table>
54
46
  </div>
55
47
  {% endblock content_left_page %}
File without changes
@@ -0,0 +1,42 @@
1
+ from django.urls import reverse
2
+
3
+ from nautobot.core.testing.integration import SeleniumTestCase
4
+ from nautobot.extras.models import JobResult
5
+
6
+
7
+ class RadioProfileTestCase(SeleniumTestCase):
8
+ """
9
+ Perform set of Radio Profile tests using Selenium.
10
+ """
11
+
12
+ def test_radio_profile_bulk_edit(self):
13
+ """
14
+ This test goes through the process of creating a radio profile and performing bulk edit.
15
+ """
16
+ self.user.is_superuser = True
17
+ self.user.save()
18
+ self.login(self.user.username, self.password)
19
+
20
+ # Create a radio profile
21
+ self.click_navbar_entry("Wireless", "Radio Profiles")
22
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("wireless:radioprofile_list"))
23
+ self.click_list_view_add_button()
24
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("wireless:radioprofile_add"))
25
+ self.browser.fill("name", "Test Radio Profile 1")
26
+ self.browser.find_by_xpath("//select[@id='id_regulatory_domain']/option[@value='PL']").click()
27
+ self.click_edit_form_create_button()
28
+
29
+ # Test bulk edit
30
+ self.click_navbar_entry("Wireless", "Radio Profiles")
31
+ self.assertEqual(self.browser.url, self.live_server_url + reverse("wireless:radioprofile_list"))
32
+ self.browser.find_by_xpath("//input[@name='pk']").click()
33
+ bulk_edit_url = reverse("wireless:radioprofile_bulk_edit")
34
+ self.browser.find_by_xpath(f"//button[@formaction='{bulk_edit_url}']").click()
35
+
36
+ # Submit bulk edit form without any changes
37
+ self.browser.find_by_xpath("//button[@name='_apply']", wait_time=5).click()
38
+
39
+ job_result = JobResult.objects.filter(name="Bulk Edit Objects").first()
40
+ self.assertEqual(
41
+ self.browser.url, self.live_server_url + reverse("extras:jobresult", args=[job_result.pk]) + "?tab=main"
42
+ )
@@ -1,4 +1,5 @@
1
1
  from nautobot.core.testing import FilterTestCases
2
+ from nautobot.extras.models import SecretsGroup
2
3
  from nautobot.wireless import filters, models
3
4
 
4
5
 
@@ -7,6 +8,8 @@ class SupportedDataRateTestCase(FilterTestCases.FilterTestCase):
7
8
  filterset = filters.SupportedDataRateFilterSet
8
9
  generic_filter_tests = [
9
10
  ("mcs_index",),
11
+ ("radio_profiles", "radio_profiles__id"),
12
+ ("radio_profiles", "radio_profiles__name"),
10
13
  ("rate",),
11
14
  ("standard",),
12
15
  ]
@@ -17,20 +20,45 @@ class RadioProfileTestCase(FilterTestCases.FilterTestCase):
17
20
  filterset = filters.RadioProfileFilterSet
18
21
  generic_filter_tests = [
19
22
  ("name",),
20
- ("regulatory_domain",),
23
+ ("controller_managed_device_groups", "controller_managed_device_groups__id"),
24
+ ("controller_managed_device_groups", "controller_managed_device_groups__name"),
21
25
  ("frequency",),
26
+ ("regulatory_domain",),
22
27
  ]
23
28
 
29
+ def test_channel_width(self):
30
+ self.assertQuerysetEqualAndNotEmpty(
31
+ self.filterset({"channel_width": "80"}, self.queryset).qs,
32
+ self.queryset.filter(channel_width__contains=[80]),
33
+ )
34
+
24
35
 
25
36
  class WirelessNetworkTestCase(FilterTestCases.FilterTestCase):
26
37
  queryset = models.WirelessNetwork.objects.all()
27
38
  filterset = filters.WirelessNetworkFilterSet
28
39
  generic_filter_tests = [
40
+ ("authentication",),
41
+ ("controller_managed_device_groups", "controller_managed_device_groups__id"),
42
+ ("controller_managed_device_groups", "controller_managed_device_groups__name"),
29
43
  ("description",),
44
+ ("mode",),
30
45
  ("name",),
46
+ ("secrets_group", "secrets_group__id"),
47
+ ("secrets_group", "secrets_group__name"),
31
48
  ("ssid",),
32
49
  ]
33
50
 
51
+ @classmethod
52
+ def setUpTestData(cls):
53
+ secrets_groups = (
54
+ SecretsGroup.objects.create(name="Secrets Group 1"),
55
+ SecretsGroup.objects.create(name="Secrets Group 2"),
56
+ SecretsGroup.objects.create(name="Secrets Group 3"),
57
+ )
58
+ for i, wireless_network in enumerate(models.WirelessNetwork.objects.all()[:3]):
59
+ wireless_network.secrets_group = secrets_groups[i]
60
+ wireless_network.validated_save()
61
+
34
62
 
35
63
  class ControllerManagedDeviceGroupWirelessNetworkAssignmentTestCase(FilterTestCases.FilterTestCase):
36
64
  queryset = models.ControllerManagedDeviceGroupWirelessNetworkAssignment.objects.all()
@@ -8,6 +8,7 @@ from tree_queries.models import TreeNode
8
8
 
9
9
  from nautobot.core.testing import utils, ViewTestCases
10
10
  from nautobot.core.utils import lookup
11
+ from nautobot.dcim.models import Controller, ControllerManagedDeviceGroup
11
12
  from nautobot.extras import choices as extras_choices
12
13
  from nautobot.extras.models import SecretsGroup, Tag
13
14
  from nautobot.users import models as users_models
@@ -20,7 +21,7 @@ class WirelessNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
20
21
 
21
22
  @classmethod
22
23
  def setUpTestData(cls):
23
- WirelessNetwork.objects.create(
24
+ cls.wireless_network = WirelessNetwork.objects.create(
24
25
  name="Deletable Wireless Network 1",
25
26
  mode=choices.WirelessNetworkModeChoices.STANDALONE,
26
27
  authentication=choices.WirelessNetworkAuthenticationChoices.WPA2_PERSONAL,
@@ -72,6 +73,26 @@ class WirelessNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
72
73
  "description": "New description",
73
74
  }
74
75
 
76
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
77
+ def test_get_with_controled_manged_device_group_vlan_set_to_none(self):
78
+ """Assert bug report #6763 (Wireless Network tab fails to render under Controller View) has been resolved"""
79
+ instance = self.wireless_network
80
+
81
+ controller = Controller.objects.first()
82
+ cmdg = ControllerManagedDeviceGroup.objects.create(
83
+ name="Test ControllerManagedDeviceGroup",
84
+ controller=controller,
85
+ )
86
+ cmdg.wireless_networks.add(instance)
87
+
88
+ self.add_permissions(
89
+ "wireless.view_wirelessnetwork", "wireless.view_controllermanageddevicegroupwirelessnetworkassignment"
90
+ )
91
+
92
+ # Try GET with model-level permission
93
+ response = self.client.get(instance.get_absolute_url())
94
+ self.assertInHTML("Test ControllerManagedDeviceGroup", response.content.decode(response.charset))
95
+
75
96
 
76
97
  class SupportedDataRateTestCase(ViewTestCases.PrimaryObjectViewTestCase):
77
98
  model = SupportedDataRate