nautobot 2.4.0b1__py3-none-any.whl → 2.4.2__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 (668) 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/tests/integration/test_circuits_bulk_operations.py +43 -0
  22. nautobot/circuits/tests/integration/test_relationships.py +1 -1
  23. nautobot/circuits/views.py +3 -3
  24. nautobot/cloud/api/views.py +6 -10
  25. nautobot/cloud/models.py +1 -1
  26. nautobot/cloud/views.py +0 -16
  27. nautobot/core/api/constants.py +11 -0
  28. nautobot/core/api/fields.py +5 -5
  29. nautobot/core/api/filter_backends.py +3 -9
  30. nautobot/core/api/schema.py +13 -2
  31. nautobot/core/api/serializers.py +40 -34
  32. nautobot/core/api/views.py +56 -4
  33. nautobot/core/apps/__init__.py +0 -5
  34. nautobot/core/celery/log.py +4 -4
  35. nautobot/core/celery/schedulers.py +2 -2
  36. nautobot/core/choices.py +2 -2
  37. nautobot/core/events/__init__.py +3 -3
  38. nautobot/core/filters.py +67 -35
  39. nautobot/core/forms/__init__.py +19 -19
  40. nautobot/core/forms/fields.py +14 -11
  41. nautobot/core/forms/forms.py +33 -2
  42. nautobot/core/graphql/types.py +1 -1
  43. nautobot/core/jobs/__init__.py +28 -7
  44. nautobot/core/jobs/bulk_actions.py +285 -0
  45. nautobot/core/jobs/cleanup.py +48 -12
  46. nautobot/core/jobs/groups.py +1 -1
  47. nautobot/core/management/commands/validate_models.py +1 -1
  48. nautobot/core/models/__init__.py +3 -1
  49. nautobot/core/models/query_functions.py +2 -2
  50. nautobot/core/models/tree_queries.py +6 -3
  51. nautobot/core/settings.py +29 -2
  52. nautobot/core/settings.yaml +21 -0
  53. nautobot/core/tables.py +79 -61
  54. nautobot/core/templates/about.html +67 -0
  55. nautobot/core/templates/generic/object_bulk_destroy.html +1 -1
  56. nautobot/core/templates/inc/media.html +3 -0
  57. nautobot/core/templates/inc/nav_menu.html +1 -0
  58. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  59. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  60. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  61. nautobot/core/templates/search.html +7 -0
  62. nautobot/core/templates/utilities/render_jinja2.html +1 -1
  63. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  64. nautobot/core/templates/utilities/theme_preview.html +7 -0
  65. nautobot/core/templatetags/helpers.py +11 -2
  66. nautobot/core/testing/__init__.py +8 -8
  67. nautobot/core/testing/api.py +170 -15
  68. nautobot/core/testing/filters.py +45 -10
  69. nautobot/core/testing/forms.py +2 -0
  70. nautobot/core/testing/integration.py +514 -5
  71. nautobot/core/testing/mixins.py +7 -2
  72. nautobot/core/testing/views.py +44 -29
  73. nautobot/core/tests/integration/test_app_home.py +0 -1
  74. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  75. nautobot/core/tests/integration/test_filters.py +0 -2
  76. nautobot/core/tests/integration/test_home.py +0 -1
  77. nautobot/core/tests/integration/test_navbar.py +0 -1
  78. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  79. nautobot/core/tests/runner.py +1 -1
  80. nautobot/core/tests/test_api.py +98 -1
  81. nautobot/core/tests/test_csv.py +25 -3
  82. nautobot/core/tests/test_filters.py +209 -246
  83. nautobot/core/tests/test_forms.py +1 -0
  84. nautobot/core/tests/test_jobs.py +492 -1
  85. nautobot/core/tests/test_models.py +9 -0
  86. nautobot/core/tests/test_settings_schema.py +7 -0
  87. nautobot/core/tests/test_tables.py +100 -0
  88. nautobot/core/tests/test_utils.py +63 -1
  89. nautobot/core/tests/test_views.py +30 -3
  90. nautobot/core/ui/nav.py +1 -0
  91. nautobot/core/ui/object_detail.py +15 -1
  92. nautobot/core/urls.py +11 -0
  93. nautobot/core/utils/git.py +7 -2
  94. nautobot/core/utils/lookup.py +11 -8
  95. nautobot/core/utils/querysets.py +64 -0
  96. nautobot/core/utils/requests.py +24 -9
  97. nautobot/core/views/__init__.py +42 -0
  98. nautobot/core/views/generic.py +131 -197
  99. nautobot/core/views/mixins.py +136 -41
  100. nautobot/core/views/renderers.py +6 -6
  101. nautobot/core/views/utils.py +2 -2
  102. nautobot/dcim/api/serializers.py +56 -64
  103. nautobot/dcim/api/views.py +47 -113
  104. nautobot/dcim/constants.py +6 -13
  105. nautobot/dcim/factory.py +6 -1
  106. nautobot/dcim/filters/__init__.py +31 -2
  107. nautobot/dcim/forms.py +48 -17
  108. nautobot/dcim/graphql/types.py +2 -2
  109. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  110. nautobot/dcim/models/__init__.py +1 -1
  111. nautobot/dcim/models/device_component_templates.py +2 -2
  112. nautobot/dcim/models/device_components.py +22 -20
  113. nautobot/dcim/models/devices.py +10 -1
  114. nautobot/dcim/models/locations.py +3 -3
  115. nautobot/dcim/models/power.py +6 -5
  116. nautobot/dcim/models/racks.py +4 -4
  117. nautobot/dcim/tables/__init__.py +3 -3
  118. nautobot/dcim/tables/devices.py +9 -6
  119. nautobot/dcim/tables/devicetypes.py +2 -2
  120. nautobot/dcim/tables/racks.py +1 -1
  121. nautobot/dcim/templates/dcim/cable.html +1 -1
  122. nautobot/dcim/templates/dcim/controller_create.html +1 -7
  123. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
  124. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
  125. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
  126. nautobot/dcim/templates/dcim/device/base.html +1 -1
  127. nautobot/dcim/templates/dcim/device.html +3 -11
  128. nautobot/dcim/templates/dcim/device_component.html +1 -1
  129. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  130. nautobot/dcim/templates/dcim/devicetype.html +1 -1
  131. nautobot/dcim/templates/dcim/location.html +2 -10
  132. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  133. nautobot/dcim/templates/dcim/locationtype.html +1 -1
  134. nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -1
  135. nautobot/dcim/templates/dcim/manufacturer.html +1 -1
  136. nautobot/dcim/templates/dcim/platform.html +1 -1
  137. nautobot/dcim/templates/dcim/powerfeed.html +1 -1
  138. nautobot/dcim/templates/dcim/powerpanel.html +1 -1
  139. nautobot/dcim/templates/dcim/rack.html +2 -10
  140. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  141. nautobot/dcim/templates/dcim/rackgroup.html +1 -1
  142. nautobot/dcim/templates/dcim/rackreservation.html +3 -11
  143. nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
  144. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
  145. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
  146. nautobot/dcim/tests/integration/test_controller.py +62 -0
  147. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  148. nautobot/dcim/tests/integration/test_device_bulk_operations.py +30 -0
  149. nautobot/dcim/tests/integration/test_location_bulk_operations.py +43 -0
  150. nautobot/dcim/tests/test_api.py +16 -5
  151. nautobot/dcim/tests/test_filters.py +33 -0
  152. nautobot/dcim/tests/test_forms.py +51 -2
  153. nautobot/dcim/tests/test_graphql.py +52 -0
  154. nautobot/dcim/tests/test_jobs.py +118 -0
  155. nautobot/dcim/tests/test_models.py +52 -9
  156. nautobot/dcim/tests/test_views.py +30 -84
  157. nautobot/dcim/views.py +13 -28
  158. nautobot/extras/api/customfields.py +2 -2
  159. nautobot/extras/api/serializers.py +123 -85
  160. nautobot/extras/api/views.py +33 -30
  161. nautobot/extras/constants.py +3 -0
  162. nautobot/extras/datasources/git.py +125 -0
  163. nautobot/extras/filters/__init__.py +8 -6
  164. nautobot/extras/forms/base.py +2 -2
  165. nautobot/extras/forms/forms.py +139 -31
  166. nautobot/extras/forms/mixins.py +14 -6
  167. nautobot/extras/group_sync.py +3 -3
  168. nautobot/extras/health_checks.py +1 -2
  169. nautobot/extras/jobs.py +85 -18
  170. nautobot/extras/managers.py +3 -1
  171. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  172. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  173. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  174. nautobot/extras/migrations/0122_add_graphqlquery_owner_content_type.py +34 -0
  175. nautobot/extras/models/__init__.py +1 -1
  176. nautobot/extras/models/contacts.py +1 -1
  177. nautobot/extras/models/customfields.py +41 -23
  178. nautobot/extras/models/datasources.py +85 -0
  179. nautobot/extras/models/groups.py +11 -9
  180. nautobot/extras/models/jobs.py +23 -4
  181. nautobot/extras/models/models.py +17 -2
  182. nautobot/extras/models/relationships.py +17 -5
  183. nautobot/extras/plugins/__init__.py +13 -2
  184. nautobot/extras/plugins/marketplace_manifest.yml +84 -79
  185. nautobot/extras/plugins/tables.py +16 -14
  186. nautobot/extras/plugins/views.py +65 -69
  187. nautobot/extras/registry.py +1 -1
  188. nautobot/extras/secrets/__init__.py +2 -2
  189. nautobot/extras/signals.py +15 -1
  190. nautobot/extras/tables.py +7 -5
  191. nautobot/extras/templates/extras/computedfield.html +1 -1
  192. nautobot/extras/templates/extras/configcontext.html +1 -1
  193. nautobot/extras/templates/extras/configcontextschema.html +1 -1
  194. nautobot/extras/templates/extras/customfield.html +1 -1
  195. nautobot/extras/templates/extras/customlink.html +1 -1
  196. nautobot/extras/templates/extras/dynamicgroup.html +2 -10
  197. nautobot/extras/templates/extras/exporttemplate.html +1 -1
  198. nautobot/extras/templates/extras/gitrepository.html +1 -1
  199. nautobot/extras/templates/extras/graphqlquery.html +1 -1
  200. nautobot/extras/templates/extras/job_detail.html +17 -1
  201. nautobot/extras/templates/extras/job_edit.html +1 -0
  202. nautobot/extras/templates/extras/jobbutton_retrieve.html +1 -1
  203. nautobot/extras/templates/extras/jobhook.html +1 -1
  204. nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
  205. nautobot/extras/templates/extras/jobresult.html +1 -1
  206. nautobot/extras/templates/extras/marketplace.html +29 -11
  207. nautobot/extras/templates/extras/objectchange.html +1 -1
  208. nautobot/extras/templates/extras/plugin_detail.html +33 -16
  209. nautobot/extras/templates/extras/plugins_tiles.html +21 -10
  210. nautobot/extras/templates/extras/relationship.html +1 -63
  211. nautobot/extras/templates/extras/role_retrieve.html +1 -1
  212. nautobot/extras/templates/extras/scheduledjob.html +1 -1
  213. nautobot/extras/templates/extras/secret.html +1 -1
  214. nautobot/extras/templates/extras/secretsgroup.html +1 -1
  215. nautobot/extras/templates/extras/status.html +1 -1
  216. nautobot/extras/templates/extras/tag.html +1 -1
  217. nautobot/extras/templates/extras/webhook.html +1 -1
  218. nautobot/extras/templatetags/job_buttons.py +4 -4
  219. nautobot/extras/test_jobs/api_test_job.py +1 -1
  220. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  221. nautobot/extras/test_jobs/dry_run.py +1 -1
  222. nautobot/extras/test_jobs/fail.py +5 -5
  223. nautobot/extras/test_jobs/file_output.py +1 -1
  224. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  225. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  226. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  227. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  228. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  229. nautobot/extras/test_jobs/log_redaction.py +1 -1
  230. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  231. nautobot/extras/test_jobs/modify_db.py +1 -1
  232. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  233. nautobot/extras/test_jobs/object_var_required.py +1 -1
  234. nautobot/extras/test_jobs/object_vars.py +1 -1
  235. nautobot/extras/test_jobs/pass.py +3 -3
  236. nautobot/extras/test_jobs/profiling.py +1 -1
  237. nautobot/extras/test_jobs/relative_import.py +3 -3
  238. nautobot/extras/test_jobs/singleton.py +16 -0
  239. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  240. nautobot/extras/test_jobs/task_queues.py +1 -1
  241. nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_interfaces.gql +8 -0
  242. nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_names.gql +5 -0
  243. nautobot/extras/tests/git_data/02-invalid-files/graphql_queries/bad_device_names.gql +5 -0
  244. nautobot/extras/tests/git_helper.py +9 -1
  245. nautobot/extras/tests/integration/__init__.py +29 -16
  246. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  247. nautobot/extras/tests/test_api.py +19 -13
  248. nautobot/extras/tests/test_customfields.py +50 -52
  249. nautobot/extras/tests/test_datasources.py +29 -1
  250. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  251. nautobot/extras/tests/test_filters.py +6 -6
  252. nautobot/extras/tests/test_forms.py +33 -1
  253. nautobot/extras/tests/test_jobs.py +178 -32
  254. nautobot/extras/tests/test_models.py +299 -10
  255. nautobot/extras/tests/test_plugins.py +62 -9
  256. nautobot/extras/tests/test_relationships.py +120 -9
  257. nautobot/extras/tests/test_utils.py +22 -1
  258. nautobot/extras/tests/test_views.py +56 -194
  259. nautobot/extras/utils.py +20 -10
  260. nautobot/extras/views.py +85 -110
  261. nautobot/ipam/api/fields.py +3 -3
  262. nautobot/ipam/api/serializers.py +41 -33
  263. nautobot/ipam/api/views.py +68 -117
  264. nautobot/ipam/factory.py +1 -1
  265. nautobot/ipam/filters.py +3 -2
  266. nautobot/ipam/lookups.py +101 -62
  267. nautobot/ipam/models.py +74 -18
  268. nautobot/ipam/querysets.py +2 -2
  269. nautobot/ipam/tables.py +25 -9
  270. nautobot/ipam/templates/ipam/ipaddress.html +2 -10
  271. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  272. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  273. nautobot/ipam/templates/ipam/prefix.html +2 -10
  274. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  275. nautobot/ipam/templates/ipam/rir.html +1 -1
  276. nautobot/ipam/templates/ipam/routetarget.html +1 -1
  277. nautobot/ipam/templates/ipam/service.html +1 -1
  278. nautobot/ipam/templates/ipam/vlan.html +2 -10
  279. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  280. nautobot/ipam/templates/ipam/vlangroup.html +1 -1
  281. nautobot/ipam/templates/ipam/vrf.html +1 -1
  282. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  283. nautobot/ipam/tests/test_api.py +436 -3
  284. nautobot/ipam/tests/test_forms.py +49 -47
  285. nautobot/ipam/tests/test_migrations.py +30 -30
  286. nautobot/ipam/tests/test_models.py +119 -34
  287. nautobot/ipam/tests/test_querysets.py +63 -1
  288. nautobot/ipam/tests/test_utils.py +41 -2
  289. nautobot/ipam/tests/test_views.py +3 -0
  290. nautobot/ipam/utils/__init__.py +54 -17
  291. nautobot/ipam/views.py +61 -87
  292. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  293. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  294. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  295. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  296. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  297. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  298. nautobot/project-static/docs/404.html +131 -14
  299. nautobot/project-static/docs/apps/index.html +131 -14
  300. nautobot/project-static/docs/apps/nautobot-apps.html +132 -16
  301. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  302. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.60a45f97.min.js} +2 -2
  303. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.60a45f97.min.js.map} +2 -2
  304. nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js → search.f8cc74c7.min.js} +1 -1
  305. nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js.map → search.f8cc74c7.min.js.map} +1 -1
  306. nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css → main.a40c8224.min.css} +1 -1
  307. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +147 -20
  308. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +144 -17
  309. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +459 -132
  310. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +175 -28
  311. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +180 -31
  312. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +138 -16
  313. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +137 -15
  314. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +164 -27
  315. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +187 -38
  316. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +193 -31
  317. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +216 -48
  318. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +324 -75
  319. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +666 -175
  320. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +194 -46
  321. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +538 -177
  322. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +578 -221
  323. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +145 -18
  324. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +156 -25
  325. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +492 -65
  326. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +705 -215
  327. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +943 -422
  328. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +144 -17
  329. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +619 -200
  330. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +474 -159
  331. nautobot/project-static/docs/development/apps/api/configuration-view.html +131 -14
  332. nautobot/project-static/docs/development/apps/api/database-backend-config.html +131 -14
  333. nautobot/project-static/docs/development/apps/api/models/django-admin.html +131 -14
  334. nautobot/project-static/docs/development/apps/api/models/global-search.html +131 -14
  335. nautobot/project-static/docs/development/apps/api/models/graphql.html +131 -14
  336. nautobot/project-static/docs/development/apps/api/models/index.html +131 -14
  337. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +131 -14
  338. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +131 -14
  339. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +131 -14
  340. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +131 -14
  341. nautobot/project-static/docs/development/apps/api/platform-features/index.html +131 -14
  342. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +131 -14
  343. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +131 -14
  344. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +131 -14
  345. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +131 -14
  346. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +153 -17
  347. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +131 -14
  348. nautobot/project-static/docs/development/apps/api/prometheus.html +131 -14
  349. nautobot/project-static/docs/development/apps/api/setup.html +131 -14
  350. nautobot/project-static/docs/development/apps/api/testing.html +131 -14
  351. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +131 -14
  352. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +131 -14
  353. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +131 -14
  354. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +131 -14
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +131 -14
  356. nautobot/project-static/docs/development/apps/api/views/base-template.html +131 -14
  357. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +131 -14
  358. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +131 -14
  359. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +131 -14
  360. nautobot/project-static/docs/development/apps/api/views/index.html +131 -14
  361. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +131 -14
  362. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +131 -14
  363. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +131 -14
  364. nautobot/project-static/docs/development/apps/api/views/notes.html +131 -14
  365. nautobot/project-static/docs/development/apps/api/views/rest-api.html +137 -16
  366. nautobot/project-static/docs/development/apps/api/views/urls.html +131 -14
  367. nautobot/project-static/docs/development/apps/index.html +131 -14
  368. nautobot/project-static/docs/development/apps/migration/code-updates.html +131 -14
  369. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +131 -14
  370. nautobot/project-static/docs/development/apps/migration/from-v1.html +131 -14
  371. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +131 -14
  372. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +131 -14
  373. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +131 -14
  374. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +131 -14
  375. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +135 -18
  376. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +131 -14
  377. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +297 -25
  378. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +131 -14
  379. nautobot/project-static/docs/development/apps/porting-from-netbox.html +131 -14
  380. nautobot/project-static/docs/development/core/application-registry.html +131 -14
  381. nautobot/project-static/docs/development/core/best-practices.html +131 -14
  382. nautobot/project-static/docs/development/core/bootstrap-ui.html +131 -14
  383. nautobot/project-static/docs/development/core/caching.html +131 -14
  384. nautobot/project-static/docs/development/core/controllers.html +131 -14
  385. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +158 -84
  386. nautobot/project-static/docs/development/core/generic-views.html +131 -14
  387. nautobot/project-static/docs/development/core/getting-started.html +334 -234
  388. nautobot/project-static/docs/development/core/homepage.html +134 -17
  389. nautobot/project-static/docs/development/core/index.html +131 -14
  390. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9829 -0
  391. nautobot/project-static/docs/development/core/model-checklist.html +141 -22
  392. nautobot/project-static/docs/development/core/model-features.html +131 -14
  393. nautobot/project-static/docs/development/core/natural-keys.html +131 -14
  394. nautobot/project-static/docs/development/core/navigation-menu.html +131 -14
  395. nautobot/project-static/docs/development/core/release-checklist.html +134 -17
  396. nautobot/project-static/docs/development/core/role-internals.html +131 -14
  397. nautobot/project-static/docs/development/core/settings.html +131 -14
  398. nautobot/project-static/docs/development/core/style-guide.html +134 -17
  399. nautobot/project-static/docs/development/core/templates.html +132 -15
  400. nautobot/project-static/docs/development/core/testing.html +131 -14
  401. nautobot/project-static/docs/development/core/ui-component-framework.html +454 -283
  402. nautobot/project-static/docs/development/core/user-preferences.html +131 -14
  403. nautobot/project-static/docs/development/index.html +131 -14
  404. nautobot/project-static/docs/development/jobs/index.html +301 -132
  405. nautobot/project-static/docs/development/jobs/migration/from-v1.html +131 -14
  406. nautobot/project-static/docs/index.html +139 -33
  407. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  408. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  409. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  410. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  411. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  412. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  413. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  414. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  415. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  416. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  417. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  418. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  419. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  420. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  421. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  422. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  423. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  424. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  425. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  426. nautobot/project-static/docs/objects.inv +0 -0
  427. nautobot/project-static/docs/overview/application_stack.html +132 -17
  428. nautobot/project-static/docs/overview/design_philosophy.html +131 -14
  429. nautobot/project-static/docs/release-notes/index.html +137 -22
  430. nautobot/project-static/docs/release-notes/version-1.0.html +319 -203
  431. nautobot/project-static/docs/release-notes/version-1.1.html +316 -200
  432. nautobot/project-static/docs/release-notes/version-1.2.html +391 -275
  433. nautobot/project-static/docs/release-notes/version-1.3.html +417 -301
  434. nautobot/project-static/docs/release-notes/version-1.4.html +502 -387
  435. nautobot/project-static/docs/release-notes/version-1.5.html +690 -576
  436. nautobot/project-static/docs/release-notes/version-1.6.html +989 -457
  437. nautobot/project-static/docs/release-notes/version-2.0.html +613 -499
  438. nautobot/project-static/docs/release-notes/version-2.1.html +448 -334
  439. nautobot/project-static/docs/release-notes/version-2.2.html +441 -327
  440. nautobot/project-static/docs/release-notes/version-2.3.html +1171 -451
  441. nautobot/project-static/docs/release-notes/version-2.4.html +800 -111
  442. nautobot/project-static/docs/requirements.txt +2 -2
  443. nautobot/project-static/docs/search/search_index.json +1 -1
  444. nautobot/project-static/docs/sitemap.xml +303 -287
  445. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  446. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +131 -14
  447. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +131 -14
  448. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +133 -16
  449. nautobot/project-static/docs/user-guide/administration/configuration/index.html +131 -14
  450. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +131 -14
  451. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +195 -18
  452. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +131 -14
  453. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +134 -17
  454. nautobot/project-static/docs/user-guide/administration/guides/docker.html +131 -14
  455. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +131 -14
  456. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +131 -14
  457. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -14
  458. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +131 -14
  459. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +131 -14
  460. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +133 -16
  461. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +131 -14
  462. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +131 -14
  463. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +131 -14
  464. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +151 -18
  465. nautobot/project-static/docs/user-guide/administration/installation/index.html +131 -14
  466. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +132 -15
  467. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +131 -14
  468. nautobot/project-static/docs/user-guide/administration/installation/services.html +131 -14
  469. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +131 -14
  470. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +131 -14
  471. nautobot/project-static/docs/user-guide/administration/security/index.html +9420 -0
  472. nautobot/project-static/docs/user-guide/administration/security/notices.html +9843 -0
  473. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +131 -14
  474. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +131 -14
  475. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +131 -14
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +131 -14
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +131 -14
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +131 -14
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +131 -14
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +134 -18
  481. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +131 -14
  482. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +131 -14
  483. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +131 -14
  484. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +131 -14
  485. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +131 -14
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +131 -14
  487. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +131 -14
  488. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +131 -14
  489. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +131 -14
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +131 -14
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +131 -14
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +131 -14
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +131 -14
  494. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +131 -14
  495. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +131 -14
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +131 -14
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +131 -14
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +131 -14
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +131 -14
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +131 -14
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +131 -14
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +131 -14
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +131 -14
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +131 -14
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +131 -14
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +131 -14
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +131 -14
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +131 -14
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +131 -14
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +131 -14
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +131 -14
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +131 -14
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +131 -14
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +131 -14
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +131 -14
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +131 -14
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +131 -14
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +131 -14
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +131 -14
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +131 -14
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +131 -14
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +131 -14
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +131 -14
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +131 -14
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +131 -14
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +131 -14
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +131 -14
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +131 -14
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +131 -14
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +131 -14
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +131 -14
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +131 -14
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +131 -14
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +131 -14
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +131 -14
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +131 -14
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +131 -14
  538. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +135 -22
  539. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +131 -14
  540. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +131 -14
  541. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +131 -14
  542. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +131 -14
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +131 -14
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +131 -14
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +131 -14
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +131 -14
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +131 -14
  548. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +131 -14
  549. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +131 -14
  550. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +131 -14
  551. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +134 -17
  552. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +131 -14
  553. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +131 -14
  554. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +131 -14
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +131 -14
  556. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +131 -14
  557. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +131 -14
  558. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +131 -14
  559. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +131 -14
  560. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +131 -14
  561. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +131 -14
  562. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +131 -14
  563. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +131 -14
  564. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +131 -14
  565. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +131 -14
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +131 -14
  567. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +134 -17
  568. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +131 -14
  569. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +131 -14
  570. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +131 -14
  571. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +131 -14
  572. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +131 -14
  573. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +131 -14
  574. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +236 -34
  575. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +131 -14
  576. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  577. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  578. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  579. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  580. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  581. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  582. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  583. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  584. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  585. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  586. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  587. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  589. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +131 -14
  590. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +131 -14
  591. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +134 -17
  592. nautobot/project-static/docs/{development/core/local-k8s.html → user-guide/feature-guides/wireless-networks-and-controllers.html} +632 -566
  593. nautobot/project-static/docs/user-guide/index.html +131 -14
  594. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +131 -14
  595. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +135 -18
  596. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +131 -14
  597. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +131 -14
  598. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +131 -14
  599. nautobot/project-static/docs/user-guide/platform-functionality/events.html +131 -14
  600. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +131 -14
  601. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +131 -14
  602. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +451 -16
  603. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +131 -14
  604. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +131 -14
  605. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +131 -14
  606. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +135 -17
  607. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +131 -14
  608. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +134 -17
  609. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +131 -14
  610. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +131 -14
  611. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9797 -0
  612. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +131 -14
  613. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +131 -14
  614. nautobot/project-static/docs/user-guide/platform-functionality/note.html +131 -14
  615. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +131 -14
  616. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +132 -15
  617. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +131 -14
  618. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +131 -14
  619. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +179 -35
  620. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +159 -15
  621. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +131 -14
  622. nautobot/project-static/docs/user-guide/platform-functionality/role.html +131 -14
  623. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +131 -14
  624. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +131 -14
  625. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +131 -14
  626. nautobot/project-static/docs/user-guide/platform-functionality/status.html +131 -14
  627. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +131 -14
  628. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +131 -14
  629. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +131 -14
  630. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +131 -14
  631. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +131 -14
  632. nautobot/project-static/js/forms.js +1 -1
  633. nautobot/tenancy/api/views.py +9 -13
  634. nautobot/tenancy/templates/tenancy/tenant.html +1 -2
  635. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  636. nautobot/tenancy/views.py +4 -2
  637. nautobot/users/admin.py +1 -1
  638. nautobot/users/api/serializers.py +5 -4
  639. nautobot/users/api/views.py +3 -3
  640. nautobot/virtualization/api/serializers.py +4 -4
  641. nautobot/virtualization/api/views.py +5 -24
  642. nautobot/virtualization/filters.py +20 -3
  643. nautobot/virtualization/models.py +1 -1
  644. nautobot/virtualization/tables.py +2 -2
  645. nautobot/virtualization/templates/virtualization/cluster.html +1 -1
  646. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  647. nautobot/virtualization/templates/virtualization/clustergroup.html +1 -1
  648. nautobot/virtualization/templates/virtualization/clustertype.html +1 -1
  649. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -10
  650. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  651. nautobot/virtualization/templates/virtualization/vminterface.html +1 -1
  652. nautobot/virtualization/tests/test_filters.py +17 -0
  653. nautobot/wireless/filters.py +2 -2
  654. nautobot/wireless/forms.py +1 -1
  655. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
  656. nautobot/wireless/tests/integration/__init__.py +0 -0
  657. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  658. nautobot/wireless/tests/test_filters.py +29 -1
  659. nautobot/wireless/tests/test_views.py +22 -1
  660. nautobot/wireless/views.py +0 -10
  661. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/METADATA +9 -9
  662. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/RECORD +667 -610
  663. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/WHEEL +1 -1
  664. nautobot/core/fixtures/user-data.json +0 -59
  665. /nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css.map → main.a40c8224.min.css.map} +0 -0
  666. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/LICENSE.txt +0 -0
  667. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/NOTICE +0 -0
  668. {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/entry_points.txt +0 -0
@@ -30,6 +30,7 @@ from nautobot.extras.models import (
30
30
  DynamicGroup,
31
31
  ExportTemplate,
32
32
  GitRepository,
33
+ GraphQLQuery,
33
34
  Job,
34
35
  JobQueue,
35
36
  JobResult,
@@ -935,6 +936,120 @@ def delete_git_export_templates(repository_record, job_result, preserve=None):
935
936
  job_result.log(msg, level_choice=LogLevelChoices.LOG_WARNING, grouping="export templates")
936
937
 
937
938
 
939
+ #
940
+ # GraphQL handling
941
+ #
942
+
943
+
944
+ def refresh_git_graphql_queries(repository_record, job_result, delete=False):
945
+ """Callback function for GitRepository updates - refresh all GraphQLQuery managed by this repository."""
946
+ if "extras.graphqlquery" in repository_record.provided_contents and not delete:
947
+ update_git_graphql_queries(repository_record, job_result)
948
+ else:
949
+ delete_git_graphql_queries(repository_record, job_result)
950
+
951
+
952
+ logger = logging.getLogger(__name__)
953
+
954
+
955
+ def update_git_graphql_queries(repository_record, job_result):
956
+ """Refresh any GraphQL queries provided by this Git repository."""
957
+ graphql_query_path = os.path.join(repository_record.filesystem_path, "graphql_queries")
958
+ git_repository_content_type = ContentType.objects.get_for_model(GitRepository)
959
+ graphql_queries = []
960
+
961
+ if os.path.isdir(graphql_query_path):
962
+ for file in os.listdir(graphql_query_path):
963
+ file_path = os.path.join(graphql_query_path, file)
964
+ if not os.path.isfile(file_path):
965
+ continue
966
+
967
+ # Remove `.gql` extension from the name if it exists
968
+ query_name = file.rsplit(".gql", 1)[0] if file.endswith(".gql") else file
969
+
970
+ try:
971
+ with open(file_path, "r") as fd:
972
+ query_content = fd.read().strip()
973
+
974
+ graphql_query, created = GraphQLQuery.objects.get_or_create(
975
+ name=query_name,
976
+ owner_content_type=git_repository_content_type,
977
+ owner_object_id=repository_record.pk,
978
+ defaults={"query": query_content},
979
+ )
980
+ modified = graphql_query.query != query_content
981
+ graphql_queries.append(query_name)
982
+ # Only attempt to update if the content has changed
983
+ if modified:
984
+ try:
985
+ graphql_query.query = query_content
986
+ graphql_query.validated_save()
987
+ msg = (
988
+ f"Successfully created GraphQL query: {query_name}"
989
+ if created
990
+ else f"Successfully updated GraphQL query: {query_name}"
991
+ )
992
+ logger.info(msg)
993
+ job_result.log(
994
+ msg, obj=graphql_query, level_choice=LogLevelChoices.LOG_INFO, grouping="graphql queries"
995
+ )
996
+ except Exception as exc:
997
+ # Log validation error and retain the existing query
998
+ error_msg = (
999
+ f"Invalid GraphQL syntax for query '{query_name}'. "
1000
+ f"Retaining the existing query. Error: {exc}"
1001
+ )
1002
+ logger.error(error_msg)
1003
+ job_result.log(error_msg, level_choice=LogLevelChoices.LOG_ERROR, grouping="graphql queries")
1004
+ continue
1005
+ else:
1006
+ msg = f"No changes to GraphQL query: {query_name}"
1007
+ logger.info(msg)
1008
+ job_result.log(
1009
+ msg, obj=graphql_query, level_choice=LogLevelChoices.LOG_INFO, grouping="graphql queries"
1010
+ )
1011
+
1012
+ except Exception as exc:
1013
+ # Check if a query with the same name already exists
1014
+ existing_query = GraphQLQuery.objects.filter(name=query_name).first()
1015
+ if existing_query and existing_query.owner_object_id != repository_record.pk:
1016
+ error_msg = (
1017
+ f"GraphQL query '{query_name}' already exists "
1018
+ f"Please rename the query in the repository and try again."
1019
+ )
1020
+ else:
1021
+ error_msg = f"Error processing GraphQL query file '{file}': {exc}"
1022
+
1023
+ # Log the error
1024
+ logger.error(error_msg)
1025
+ job_result.log(error_msg, level_choice=LogLevelChoices.LOG_ERROR, grouping="graphql queries")
1026
+
1027
+ # Delete any queries not in the preserved list
1028
+ delete_git_graphql_queries(repository_record, job_result, preserve=graphql_queries)
1029
+
1030
+
1031
+ def delete_git_graphql_queries(repository_record, job_result, preserve=None):
1032
+ """Delete GraphQL queries owned by the given Git repository that are not in the preserve list."""
1033
+ git_repository_content_type = ContentType.objects.get_for_model(GitRepository)
1034
+ if preserve is None:
1035
+ preserve = []
1036
+
1037
+ for graphql_query in GraphQLQuery.objects.filter(
1038
+ owner_content_type=git_repository_content_type,
1039
+ owner_object_id=repository_record.pk,
1040
+ ):
1041
+ if graphql_query.name not in preserve:
1042
+ try:
1043
+ graphql_query.delete()
1044
+ msg = f"Deleted GraphQL query: {graphql_query.name}"
1045
+ logger.warning(msg)
1046
+ job_result.log(msg, level_choice=LogLevelChoices.LOG_WARNING, grouping="graphql queries")
1047
+ except Exception as exc:
1048
+ error_msg = f"Unable to delete '{graphql_query.name}': {exc}"
1049
+ logger.error(error_msg)
1050
+ job_result.log(error_msg, level_choice=LogLevelChoices.LOG_ERROR, grouping="graphql queries")
1051
+
1052
+
938
1053
  # Register built-in callbacks for data types potentially provided by a GitRepository
939
1054
  register_datasource_contents(
940
1055
  [
@@ -978,5 +1093,15 @@ register_datasource_contents(
978
1093
  callback=refresh_git_export_templates,
979
1094
  ),
980
1095
  ),
1096
+ (
1097
+ "extras.gitrepository",
1098
+ DatasourceContent(
1099
+ name="graphql queries",
1100
+ content_identifier="extras.graphqlquery",
1101
+ icon="mdi-graphql",
1102
+ weight=400,
1103
+ callback=refresh_git_graphql_queries,
1104
+ ),
1105
+ ),
981
1106
  ]
982
1107
  )
@@ -119,13 +119,13 @@ __all__ = (
119
119
  "CustomFieldDateFilter",
120
120
  "CustomFieldFilterMixin",
121
121
  "CustomFieldJSONFilter",
122
+ "CustomFieldModelFilterSet",
123
+ "CustomFieldModelFilterSetMixin",
122
124
  "CustomFieldMultiSelectFilter",
123
125
  "CustomFieldMultiValueCharFilter",
124
126
  "CustomFieldMultiValueDateFilter",
125
127
  "CustomFieldMultiValueNumberFilter",
126
128
  "CustomFieldNumberFilter",
127
- "CustomFieldModelFilterSet",
128
- "CustomFieldModelFilterSetMixin",
129
129
  "CustomLinkFilterSet",
130
130
  "DynamicGroupFilterSet",
131
131
  "DynamicGroupMembershipFilterSet",
@@ -136,25 +136,25 @@ __all__ = (
136
136
  "ImageAttachmentFilterSet",
137
137
  "JobFilterSet",
138
138
  "JobLogEntryFilterSet",
139
- "JobQueueFilterSet",
140
139
  "JobQueueAssignmentFilterSet",
140
+ "JobQueueFilterSet",
141
141
  "JobResultFilterSet",
142
142
  "LocalContextFilterSet",
143
143
  "LocalContextModelFilterSetMixin",
144
- "MetadataTypeFilterSet",
145
144
  "MetadataChoiceFilterSet",
145
+ "MetadataTypeFilterSet",
146
146
  "NautobotFilterSet",
147
147
  "NoteFilterSet",
148
148
  "ObjectChangeFilterSet",
149
+ "RelationshipAssociationFilterSet",
149
150
  "RelationshipFilter",
150
151
  "RelationshipFilterSet",
151
- "RelationshipAssociationFilterSet",
152
152
  "RoleFilterSet",
153
153
  "RoleModelFilterSetMixin",
154
154
  "ScheduledJobFilterSet",
155
155
  "SecretFilterSet",
156
- "SecretsGroupFilterSet",
157
156
  "SecretsGroupAssociationFilterSet",
157
+ "SecretsGroupFilterSet",
158
158
  "StatusFilter",
159
159
  "StatusFilterSet",
160
160
  "StatusModelFilterSetMixin",
@@ -874,6 +874,7 @@ class JobFilterSet(BaseFilterSet, CustomFieldModelFilterSetMixin):
874
874
  "is_job_button_receiver",
875
875
  "soft_time_limit",
876
876
  "time_limit",
877
+ "is_singleton",
877
878
  "grouping_override",
878
879
  "name_override",
879
880
  "approval_required_override",
@@ -883,6 +884,7 @@ class JobFilterSet(BaseFilterSet, CustomFieldModelFilterSetMixin):
883
884
  "soft_time_limit_override",
884
885
  "time_limit_override",
885
886
  "has_sensitive_variables_override",
887
+ "is_singleton_override",
886
888
  "tags",
887
889
  ]
888
890
 
@@ -14,9 +14,9 @@ from .mixins import (
14
14
  )
15
15
 
16
16
  __all__ = (
17
- "NautobotModelForm",
18
- "NautobotFilterForm",
19
17
  "NautobotBulkEditForm",
18
+ "NautobotFilterForm",
19
+ "NautobotModelForm",
20
20
  )
21
21
 
22
22
 
@@ -1,5 +1,7 @@
1
1
  import inspect
2
+ import logging
2
3
 
4
+ from celery import chain
3
5
  from django import forms
4
6
  from django.conf import settings
5
7
  from django.contrib.auth import get_user_model
@@ -7,7 +9,7 @@ from django.contrib.contenttypes.models import ContentType
7
9
  from django.core.exceptions import ValidationError
8
10
  from django.core.validators import MinValueValidator
9
11
  from django.db.models.fields import TextField
10
- from django.forms import inlineformset_factory, ModelMultipleChoiceField
12
+ from django.forms import inlineformset_factory, ModelMultipleChoiceField, MultipleHiddenInput
11
13
  from django.urls.base import reverse
12
14
  from django.utils.timezone import get_current_timezone_name
13
15
 
@@ -35,6 +37,7 @@ from nautobot.core.forms import (
35
37
  TagFilterField,
36
38
  )
37
39
  from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
40
+ from nautobot.core.forms.forms import ConfirmationForm
38
41
  from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
39
42
  from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
40
43
  from nautobot.extras.choices import (
@@ -88,9 +91,12 @@ from nautobot.extras.models import (
88
91
  Webhook,
89
92
  )
90
93
  from nautobot.extras.registry import registry
94
+ from nautobot.extras.signals import change_context_state
95
+ from nautobot.extras.tasks import delete_custom_field_data
91
96
  from nautobot.extras.utils import (
92
97
  ChangeLoggedModelsQuery,
93
98
  FeatureQuery,
99
+ get_worker_count,
94
100
  RoleModelsQuery,
95
101
  TaggableClassesQuery,
96
102
  )
@@ -111,87 +117,90 @@ from .mixins import (
111
117
  TagsBulkEditFormMixin,
112
118
  )
113
119
 
120
+ logger = logging.getLogger(__name__)
121
+
114
122
  __all__ = (
115
123
  "BaseDynamicGroupMembershipFormSet",
116
- "ComputedFieldForm",
117
124
  "ComputedFieldFilterForm",
118
- "ConfigContextForm",
125
+ "ComputedFieldForm",
119
126
  "ConfigContextBulkEditForm",
120
127
  "ConfigContextFilterForm",
121
- "ConfigContextSchemaForm",
128
+ "ConfigContextForm",
122
129
  "ConfigContextSchemaBulkEditForm",
123
130
  "ConfigContextSchemaFilterForm",
124
- "CustomFieldForm",
125
- "CustomFieldFilterForm",
126
- "CustomFieldModelCSVForm",
131
+ "ConfigContextSchemaForm",
127
132
  "CustomFieldBulkCreateForm", # 2.0 TODO remove this deprecated class
133
+ "CustomFieldBulkDeleteForm",
128
134
  "CustomFieldChoiceFormSet",
129
- "CustomLinkForm",
135
+ "CustomFieldFilterForm",
136
+ "CustomFieldForm",
137
+ "CustomFieldModelCSVForm",
130
138
  "CustomLinkFilterForm",
139
+ "CustomLinkForm",
131
140
  "DynamicGroupBulkAssignForm",
132
- "DynamicGroupForm",
133
141
  "DynamicGroupFilterForm",
142
+ "DynamicGroupForm",
134
143
  "DynamicGroupMembershipFormSet",
135
- "ExportTemplateForm",
136
144
  "ExportTemplateFilterForm",
145
+ "ExportTemplateForm",
146
+ "ExternalIntegrationBulkEditForm",
137
147
  "ExternalIntegrationFilterForm",
138
148
  "ExternalIntegrationForm",
139
- "ExternalIntegrationBulkEditForm",
140
- "GitRepositoryForm",
141
149
  "GitRepositoryBulkEditForm",
142
150
  "GitRepositoryFilterForm",
143
- "GraphQLQueryForm",
151
+ "GitRepositoryForm",
144
152
  "GraphQLQueryFilterForm",
153
+ "GraphQLQueryForm",
145
154
  "ImageAttachmentForm",
146
- "JobForm",
147
155
  "JobBulkEditForm",
148
- "JobButtonForm",
149
156
  "JobButtonBulkEditForm",
150
157
  "JobButtonFilterForm",
158
+ "JobButtonForm",
151
159
  "JobEditForm",
152
160
  "JobFilterForm",
153
- "JobHookForm",
161
+ "JobForm",
154
162
  "JobHookFilterForm",
163
+ "JobHookForm",
155
164
  "JobQueueBulkEditForm",
156
165
  "JobQueueFilterForm",
157
166
  "JobQueueForm",
158
- "JobScheduleForm",
159
167
  "JobResultFilterForm",
168
+ "JobScheduleForm",
160
169
  "LocalContextFilterForm",
161
- "LocalContextModelForm",
162
170
  "LocalContextModelBulkEditForm",
171
+ "LocalContextModelForm",
172
+ "MetadataChoiceFormSet",
163
173
  "MetadataTypeBulkEditForm",
164
- "MetadataTypeForm",
165
174
  "MetadataTypeFilterForm",
166
- "MetadataChoiceFormSet",
167
- "NoteForm",
175
+ "MetadataTypeForm",
168
176
  "NoteFilterForm",
177
+ "NoteForm",
169
178
  "ObjectChangeFilterForm",
170
179
  "ObjectMetadataFilterForm",
171
180
  "PasswordInputWithPlaceholder",
172
- "RelationshipForm",
173
- "RelationshipFilterForm",
174
181
  "RelationshipAssociationFilterForm",
182
+ "RelationshipFilterForm",
183
+ "RelationshipForm",
175
184
  "RoleBulkEditForm",
176
185
  "RoleFilterForm",
177
186
  "RoleForm",
178
187
  "SavedViewForm",
179
188
  "SavedViewModalForm",
180
189
  "ScheduledJobFilterForm",
181
- "SecretForm",
182
190
  "SecretFilterForm",
183
- "SecretsGroupForm",
184
- "SecretsGroupFilterForm",
191
+ "SecretForm",
185
192
  "SecretsGroupAssociationFormSet",
193
+ "SecretsGroupFilterForm",
194
+ "SecretsGroupForm",
186
195
  "StaticGroupAssociationFilterForm",
187
- "StatusForm",
188
- "StatusFilterForm",
189
196
  "StatusBulkEditForm",
190
- "TagForm",
191
- "TagFilterForm",
197
+ "StatusFilterForm",
198
+ "StatusForm",
192
199
  "TagBulkEditForm",
193
- "WebhookForm",
200
+ "TagFilterForm",
201
+ "TagForm",
194
202
  "WebhookFilterForm",
203
+ "WebhookForm",
195
204
  )
196
205
 
197
206
 
@@ -491,6 +500,44 @@ class CustomFieldBulkCreateForm(CustomFieldModelBulkEditFormMixin):
491
500
  """No longer needed as a separate class - use CustomFieldModelBulkEditFormMixin instead."""
492
501
 
493
502
 
503
+ class CustomFieldBulkDeleteForm(ConfirmationForm):
504
+ def __init__(self, *args, delete_all=False, **kwargs):
505
+ super().__init__(*args, **kwargs)
506
+ queryset = CustomField.objects.all()
507
+ self.fields["pk"] = ModelMultipleChoiceField(
508
+ queryset=queryset, widget=MultipleHiddenInput, required=not delete_all
509
+ )
510
+
511
+ def construct_custom_field_delete_tasks(self, queryset):
512
+ """
513
+ Helper method to construct a list of celery tasks to execute when bulk deleting custom fields.
514
+ """
515
+ change_context = change_context_state.get()
516
+ if change_context is None:
517
+ context = None
518
+ else:
519
+ context = change_context.as_dict(queryset)
520
+ context["context_detail"] = "bulk delete custom field data"
521
+ tasks = [
522
+ delete_custom_field_data.si(obj.key, set(obj.content_types.values_list("pk", flat=True)), context)
523
+ for obj in queryset
524
+ ]
525
+ return tasks
526
+
527
+ def perform_pre_delete(self, queryset):
528
+ """
529
+ Remove all Custom Field Keys/Values from _custom_field_data of the related ContentType in the background.
530
+ """
531
+ if not get_worker_count():
532
+ logger.error("Celery worker process not running. Object custom fields may fail to reflect this deletion.")
533
+ return
534
+ tasks = self.construct_custom_field_delete_tasks(queryset)
535
+ # Executing the tasks in the background sequentially using chain() aligns with how a single
536
+ # CustomField object is deleted. We decided to not check the result because it needs at least one worker
537
+ # to be active and comes with extra performance penalty.
538
+ chain(*tasks).apply_async()
539
+
540
+
494
541
  #
495
542
  # Custom Links
496
543
  #
@@ -990,6 +1037,8 @@ class JobEditForm(NautobotModelForm):
990
1037
  "job_queues",
991
1038
  "default_job_queue_override",
992
1039
  "default_job_queue",
1040
+ "is_singleton",
1041
+ "is_singleton_override",
993
1042
  "tags",
994
1043
  ]
995
1044
 
@@ -1089,6 +1138,11 @@ class JobBulkEditForm(NautobotBulkEditForm):
1089
1138
  required=False,
1090
1139
  help_text="Default Job Queue the job runs on if no Job Queue is specified",
1091
1140
  )
1141
+ is_singleton = forms.NullBooleanField(
1142
+ required=False,
1143
+ widget=BulkEditNullBooleanSelect,
1144
+ help_text="Whether this job should fail to run if another instance of this job is already running",
1145
+ )
1092
1146
  # Flags to indicate whether the above properties are inherited from the source code or overridden by the database
1093
1147
  # Text field overrides
1094
1148
  clear_grouping_override = forms.BooleanField(
@@ -1132,10 +1186,62 @@ class JobBulkEditForm(NautobotBulkEditForm):
1132
1186
  required=False,
1133
1187
  help_text="If checked, the values of has sensitive variables will be reverted to the default values defined in each Job's source code",
1134
1188
  )
1189
+ is_singleton_override = forms.BooleanField(
1190
+ required=False,
1191
+ help_text="If checked, the values of is singleton will be reverted to the default values defined in each Job's source code",
1192
+ )
1135
1193
 
1136
1194
  class Meta:
1137
1195
  model = Job
1138
1196
 
1197
+ def post_save(self, obj):
1198
+ super().post_save(obj)
1199
+
1200
+ cleaned_data = self.cleaned_data
1201
+
1202
+ # Handle text related fields
1203
+ for overridable_field in JOB_OVERRIDABLE_FIELDS:
1204
+ override_field = overridable_field + "_override"
1205
+ clear_override_field = "clear_" + overridable_field + "_override"
1206
+ reset_override = cleaned_data.get(clear_override_field, False)
1207
+ override_value = cleaned_data.get(overridable_field)
1208
+ if reset_override:
1209
+ setattr(obj, override_field, False)
1210
+ elif not reset_override and override_value not in [None, ""]:
1211
+ setattr(obj, override_field, True)
1212
+ setattr(obj, overridable_field, override_value)
1213
+
1214
+ # Handle job queues
1215
+ clear_override_field = "clear_job_queues_override"
1216
+ reset_override = cleaned_data.get(clear_override_field, False)
1217
+ if reset_override:
1218
+ meta_task_queues = obj.job_class.task_queues
1219
+ job_queues = []
1220
+ for queue_name in meta_task_queues:
1221
+ try:
1222
+ job_queues.append(JobQueue.objects.get(name=queue_name))
1223
+ except JobQueue.DoesNotExist:
1224
+ # Do we want to create the Job Queue for the users here if we do not have it in the database?
1225
+ pass
1226
+ obj.job_queues_override = False
1227
+ obj.job_queues.set(job_queues)
1228
+ elif cleaned_data["job_queues"]:
1229
+ obj.job_queues_override = True
1230
+
1231
+ # Handle default job queue
1232
+ clear_override_field = "clear_default_job_queue_override"
1233
+ reset_override = cleaned_data.get(clear_override_field, False)
1234
+ if reset_override:
1235
+ meta_task_queues = obj.job_class.task_queues
1236
+ obj.default_job_queue_override = False
1237
+ obj.default_job_queue, _ = JobQueue.objects.get_or_create(
1238
+ name=meta_task_queues[0] if meta_task_queues else settings.CELERY_TASK_DEFAULT_QUEUE
1239
+ )
1240
+ elif cleaned_data["default_job_queue"]:
1241
+ obj.default_job_queue_override = True
1242
+
1243
+ obj.validated_save()
1244
+
1139
1245
 
1140
1246
  class JobFilterForm(BootstrapMixin, forms.Form):
1141
1247
  model = Job
@@ -1779,6 +1885,8 @@ class RoleBulkEditForm(NautobotBulkEditForm):
1779
1885
 
1780
1886
  pk = forms.ModelMultipleChoiceField(queryset=Role.objects.all(), widget=forms.MultipleHiddenInput)
1781
1887
  color = forms.CharField(max_length=6, required=False, widget=ColorSelect())
1888
+ description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
1889
+ weight = forms.IntegerField(required=False)
1782
1890
  content_types = MultipleContentTypeField(
1783
1891
  queryset=RoleModelsQuery().as_queryset(), required=False, label="Content Type(s)"
1784
1892
  )
@@ -34,7 +34,7 @@ from nautobot.extras.utils import remove_prefix_from_cf_key
34
34
  logger = logging.getLogger(__name__)
35
35
 
36
36
 
37
- __all__ = (
37
+ __all__ = ( # noqa:RUF022
38
38
  "ContactTeamModelFilterFormMixin",
39
39
  "CustomFieldModelBulkEditFormMixin",
40
40
  "CustomFieldModelFilterFormMixin",
@@ -327,7 +327,7 @@ class RelationshipModelBulkEditFormMixin(BulkEditForm):
327
327
  field_name,
328
328
  instance,
329
329
  )
330
- if field_name in self.nullable_fields and field_name in nullified_fields:
330
+ if field_name in self.nullable_fields and nullified_fields and field_name in nullified_fields:
331
331
  logger.debug("Deleting existing relationship associations for %s on %s", relationship, instance)
332
332
  relationshipassociation_queryset.delete()
333
333
  elif field_name in self.cleaned_data:
@@ -673,7 +673,7 @@ class RelationshipModelFormMixin(forms.ModelForm):
673
673
  for peer_id in target_peer_ids:
674
674
  relationship = self.fields[field_name].model
675
675
  if not relationship.symmetric:
676
- association = RelationshipAssociation(
676
+ association = RelationshipAssociation( # pylint: disable=repeated-keyword
677
677
  relationship=relationship,
678
678
  **{
679
679
  f"{side}_type": self.obj_type,
@@ -837,13 +837,21 @@ class StatusModelFilterFormMixin(forms.Form):
837
837
  self.order_fields(self.field_order) # Reorder fields again
838
838
 
839
839
 
840
- class TagsBulkEditFormMixin(forms.Form):
840
+ class TagsBulkEditFormMixin(BulkEditForm):
841
841
  def __init__(self, *args, **kwargs):
842
842
  super().__init__(*args, **kwargs)
843
843
 
844
844
  # Add add/remove tags fields
845
- self.fields["add_tags"] = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False)
846
- self.fields["remove_tags"] = DynamicModelMultipleChoiceField(queryset=Tag.objects.all(), required=False)
845
+ self.fields["add_tags"] = DynamicModelMultipleChoiceField(
846
+ queryset=Tag.objects.all(),
847
+ query_params={"content_types": self.model._meta.label_lower},
848
+ required=False,
849
+ )
850
+ self.fields["remove_tags"] = DynamicModelMultipleChoiceField(
851
+ queryset=Tag.objects.all(),
852
+ query_params={"content_types": self.model._meta.label_lower},
853
+ required=False,
854
+ )
847
855
 
848
856
 
849
857
  # 2.2 TODO: Names below are only for backward compatibility with Nautobot 1.3 and earlier. Remove in 2.2
@@ -8,15 +8,15 @@ from django.contrib.auth.models import Group
8
8
  logger = logging.getLogger(__name__)
9
9
 
10
10
 
11
- CLAIMS_GROUP_NAME = getattr(settings, "NAUTOBOT_SSO_CLAIMS_GROUP", "groups")
11
+ CLAIMS_GROUP_NAME = getattr(settings, "SSO_CLAIMS_GROUP", "groups")
12
12
  """ Which claim to look at in the OAuth2/OIDC response
13
13
 
14
14
  For Okta you can look at `Okta -> Authorization Servers -> Claims`. And a reasonable
15
15
  default is "groups". For Azure a reasonable default is "roles".
16
16
  """
17
17
 
18
- SUPERUSER_GROUPS = getattr(settings, "NAUTOBOT_SSO_SUPERUSER_GROUPS", [])
19
- STAFF_GROUPS = getattr(settings, "NAUTOBOT_SSO_STAFF_GROUPS", [])
18
+ SUPERUSER_GROUPS = getattr(settings, "SSO_SUPERUSER_GROUPS", [])
19
+ STAFF_GROUPS = getattr(settings, "SSO_STAFF_GROUPS", [])
20
20
 
21
21
 
22
22
  def group_sync(uid, user=None, response=None, *args, **kwargs):
@@ -160,5 +160,4 @@ class RedisBackend(RedisHealthCheck):
160
160
  elif client_class == "django_redis.client.DefaultClient":
161
161
  self.check_redis(redis_url=location, **options.get("CONNECTION_POOL_KWARGS", {}))
162
162
  else:
163
- if self.redis_url is None:
164
- self.add_error(ServiceUnavailable(f"{client_class} is an unsupported CLIENT_CLASS!"))
163
+ self.add_error(ServiceUnavailable(f"{client_class} is an unsupported CLIENT_CLASS!"))