nautobot 3.0.0a2__py3-none-any.whl → 3.0.0rc1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (659) hide show
  1. nautobot/apps/choices.py +4 -2
  2. nautobot/apps/filters.py +7 -9
  3. nautobot/apps/models.py +2 -2
  4. nautobot/apps/ui.py +13 -1
  5. nautobot/apps/utils.py +8 -0
  6. nautobot/circuits/filters.py +3 -2
  7. nautobot/circuits/navigation.py +3 -2
  8. nautobot/circuits/templates/circuits/circuit_create.html +3 -3
  9. nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
  10. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
  11. nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
  12. nautobot/circuits/tests/integration/test_circuit.py +10 -13
  13. nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
  14. nautobot/circuits/views.py +6 -2
  15. nautobot/cloud/filters.py +1 -1
  16. nautobot/cloud/navigation.py +3 -2
  17. nautobot/core/api/schema.py +1 -1
  18. nautobot/core/api/serializers.py +6 -1
  19. nautobot/core/api/urls.py +2 -0
  20. nautobot/core/api/views.py +12 -0
  21. nautobot/core/apps/__init__.py +11 -10
  22. nautobot/core/celery/__init__.py +3 -5
  23. nautobot/core/checks.py +46 -0
  24. nautobot/core/choices.py +1 -1
  25. nautobot/core/cli/bootstrap_v3_to_v5.py +105 -13
  26. nautobot/core/cli/migrate_deprecated_templates.py +227 -0
  27. nautobot/core/constants.py +3 -0
  28. nautobot/core/context_processors.py +9 -1
  29. nautobot/core/filters.py +4 -0
  30. nautobot/core/forms/__init__.py +2 -0
  31. nautobot/core/forms/forms.py +1 -1
  32. nautobot/core/forms/widgets.py +21 -2
  33. nautobot/core/jobs/__init__.py +62 -3
  34. nautobot/core/jobs/groups.py +31 -1
  35. nautobot/core/management/commands/generate_test_data.py +28 -9
  36. nautobot/core/models/__init__.py +11 -0
  37. nautobot/core/models/generics.py +9 -1
  38. nautobot/core/models/tree_queries.py +10 -5
  39. nautobot/core/models/utils.py +1 -1
  40. nautobot/core/settings.py +35 -19
  41. nautobot/core/settings.yaml +17 -33
  42. nautobot/core/signals.py +12 -1
  43. nautobot/core/tables.py +13 -6
  44. nautobot/core/templates/40x.html +1 -1
  45. nautobot/core/templates/500.html +2 -2
  46. nautobot/core/templates/admin/base.html +1 -2
  47. nautobot/core/templates/admin/change_list.html +9 -12
  48. nautobot/core/templates/admin/config/config.html +12 -12
  49. nautobot/core/templates/admin/index.html +3 -3
  50. nautobot/core/templates/base_django.html +1 -2
  51. nautobot/core/templates/buttons/export.html +1 -1
  52. nautobot/core/templates/components/button/dropdown.html +5 -3
  53. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
  54. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  55. nautobot/core/templates/components/panel/panel.html +3 -3
  56. nautobot/core/templates/components/tab/content_wrapper.html +6 -7
  57. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
  58. nautobot/core/templates/echarts/echarts.html +22 -9
  59. nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
  60. nautobot/core/templates/generic/object_bulk_create.html +6 -5
  61. nautobot/core/templates/generic/object_bulk_delete.html +1 -1
  62. nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
  63. nautobot/core/templates/generic/object_bulk_edit.html +1 -1
  64. nautobot/core/templates/generic/object_bulk_import.html +1 -1
  65. nautobot/core/templates/generic/object_bulk_remove.html +2 -2
  66. nautobot/core/templates/generic/object_bulk_update.html +5 -4
  67. nautobot/core/templates/generic/object_create.html +5 -4
  68. nautobot/core/templates/generic/object_delete.html +1 -1
  69. nautobot/core/templates/generic/object_detail.html +1 -1
  70. nautobot/core/templates/generic/object_edit.html +1 -1
  71. nautobot/core/templates/generic/object_import.html +2 -1
  72. nautobot/core/templates/generic/object_list.html +12 -4
  73. nautobot/core/templates/generic/object_notes.html +5 -3
  74. nautobot/core/templates/generic/object_retrieve.html +4 -5
  75. nautobot/core/templates/graphene/graphiql.html +7 -8
  76. nautobot/core/templates/home.html +1 -1
  77. nautobot/core/templates/import_success.html +2 -1
  78. nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
  79. nautobot/core/templates/inc/created_updated.html +7 -3
  80. nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
  81. nautobot/core/templates/inc/footer.html +3 -1
  82. nautobot/core/templates/inc/form_static_field.html +6 -0
  83. nautobot/core/templates/inc/header.html +11 -1
  84. nautobot/core/templates/inc/image_attachments.html +2 -1
  85. nautobot/core/templates/inc/media.html +14 -0
  86. nautobot/core/templates/inc/nav_menu.html +3 -9
  87. nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
  88. nautobot/core/templates/inc/search_panel.html +4 -4
  89. nautobot/core/templates/login.html +4 -2
  90. nautobot/core/templates/nautobot_config.py.j2 +6 -11
  91. nautobot/core/templates/redoc_ui.html +7 -0
  92. nautobot/core/templates/rest_framework/api.html +103 -2
  93. nautobot/core/templates/search.html +1 -1
  94. nautobot/core/templates/swagger_ui.html +17 -3
  95. nautobot/core/templates/system_jobs/import_objects.html +1 -2
  96. nautobot/core/templates/utilities/confirmation_form.html +2 -2
  97. nautobot/core/templates/utilities/obj_table.html +10 -2
  98. nautobot/core/templates/utilities/render_field.html +7 -7
  99. nautobot/core/templates/utilities/render_jinja2.html +2 -2
  100. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +37 -4
  101. nautobot/core/templates/utilities/theme_preview.html +19 -3
  102. nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
  103. nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
  104. nautobot/core/templatetags/helpers.py +76 -18
  105. nautobot/core/testing/api.py +68 -9
  106. nautobot/core/testing/filters.py +0 -23
  107. nautobot/core/testing/integration.py +41 -17
  108. nautobot/core/testing/mixins.py +2 -0
  109. nautobot/core/testing/utils.py +18 -4
  110. nautobot/core/testing/views.py +104 -13
  111. nautobot/core/tests/integration/test_app_home.py +34 -30
  112. nautobot/core/tests/integration/test_app_navbar.py +3 -0
  113. nautobot/core/tests/integration/test_filters.py +48 -11
  114. nautobot/core/tests/integration/test_theme.py +22 -21
  115. nautobot/core/tests/nautobot_config.py +3 -0
  116. nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
  117. nautobot/core/tests/runner.py +8 -1
  118. nautobot/core/tests/test_api.py +5 -3
  119. nautobot/core/tests/test_breadcrumbs.py +27 -28
  120. nautobot/core/tests/test_checks.py +28 -0
  121. nautobot/core/tests/test_cli.py +40 -0
  122. nautobot/core/tests/test_config.py +2 -1
  123. nautobot/core/tests/test_forms.py +55 -13
  124. nautobot/core/tests/test_jobs.py +144 -3
  125. nautobot/core/tests/test_nautobot_server.py +2 -0
  126. nautobot/core/tests/test_navigations.py +76 -1
  127. nautobot/core/tests/test_patch_social_django.py +42 -0
  128. nautobot/core/tests/test_renderers.py +59 -0
  129. nautobot/core/tests/test_settings_schema.py +1 -0
  130. nautobot/core/tests/test_tables.py +3 -1
  131. nautobot/core/tests/test_templatetags_helpers.py +62 -13
  132. nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
  133. nautobot/core/tests/test_titles.py +0 -16
  134. nautobot/core/tests/test_tree_queries.py +14 -1
  135. nautobot/core/tests/test_ui.py +123 -4
  136. nautobot/core/tests/test_utils.py +72 -5
  137. nautobot/core/tests/test_views.py +159 -31
  138. nautobot/core/ui/breadcrumbs.py +70 -29
  139. nautobot/core/ui/bulk_buttons.py +1 -1
  140. nautobot/core/ui/choices.py +143 -27
  141. nautobot/core/ui/constants.py +76 -12
  142. nautobot/core/ui/echarts.py +15 -20
  143. nautobot/core/ui/object_detail.py +143 -55
  144. nautobot/core/ui/titles.py +3 -6
  145. nautobot/core/urls.py +20 -9
  146. nautobot/core/utils/cache.py +2 -1
  147. nautobot/core/utils/filtering.py +28 -18
  148. nautobot/core/utils/lookup.py +49 -8
  149. nautobot/core/utils/module_loading.py +21 -0
  150. nautobot/core/utils/patch_social_django.py +128 -0
  151. nautobot/core/views/__init__.py +38 -1
  152. nautobot/core/views/generic.py +3 -3
  153. nautobot/core/views/mixins.py +45 -22
  154. nautobot/core/views/renderers.py +4 -3
  155. nautobot/core/views/viewsets.py +2 -1
  156. nautobot/data_validation/apps.py +1 -5
  157. nautobot/data_validation/custom_validators.py +4 -4
  158. nautobot/data_validation/filters.py +1 -1
  159. nautobot/data_validation/forms.py +40 -0
  160. nautobot/data_validation/migrations/0001_initial.py +0 -7
  161. nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -14
  162. nautobot/data_validation/models.py +16 -7
  163. nautobot/data_validation/navigation.py +8 -1
  164. nautobot/data_validation/tables.py +12 -5
  165. nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
  166. nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
  167. nautobot/data_validation/tests/__init__.py +2 -2
  168. nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
  169. nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
  170. nautobot/data_validation/tests/test_filters.py +8 -6
  171. nautobot/data_validation/tests/test_models.py +15 -0
  172. nautobot/data_validation/tests/test_views.py +190 -32
  173. nautobot/data_validation/urls.py +2 -5
  174. nautobot/data_validation/views.py +73 -40
  175. nautobot/dcim/api/serializers.py +3 -13
  176. nautobot/dcim/apps.py +4 -0
  177. nautobot/dcim/choices.py +65 -0
  178. nautobot/dcim/constants.py +7 -0
  179. nautobot/dcim/custom_validators.py +84 -0
  180. nautobot/dcim/factory.py +1 -1
  181. nautobot/dcim/filter_mixins.py +353 -4
  182. nautobot/dcim/{filters/__init__.py → filters.py} +15 -36
  183. nautobot/dcim/forms.py +90 -4
  184. nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
  185. nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
  186. nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
  187. nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
  188. nautobot/dcim/migrations/0079_remove_device_location_tenant_name_uniqueness.py +16 -0
  189. nautobot/dcim/migrations/0080_device_name_data_migration.py +59 -0
  190. nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
  191. nautobot/dcim/models/device_component_templates.py +33 -1
  192. nautobot/dcim/models/device_components.py +98 -64
  193. nautobot/dcim/models/devices.py +30 -20
  194. nautobot/dcim/navigation.py +7 -6
  195. nautobot/dcim/tables/devices.py +18 -0
  196. nautobot/dcim/tables/devicetypes.py +8 -1
  197. nautobot/dcim/tables/racks.py +0 -2
  198. nautobot/dcim/tables/template_code.py +15 -15
  199. nautobot/dcim/templates/dcim/cable_connect.html +28 -112
  200. nautobot/dcim/templates/dcim/cable_trace.html +0 -4
  201. nautobot/dcim/templates/dcim/{cable_edit.html → cable_update.html} +1 -1
  202. nautobot/dcim/templates/dcim/consoleport.html +7 -6
  203. nautobot/dcim/templates/dcim/consoleserverport.html +7 -6
  204. nautobot/dcim/templates/dcim/device/config.html +2 -2
  205. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
  206. nautobot/dcim/templates/dcim/device/status.html +8 -8
  207. nautobot/dcim/templates/dcim/device.html +1 -1
  208. nautobot/dcim/templates/dcim/device_component_add.html +2 -2
  209. nautobot/dcim/templates/dcim/device_create.html +5 -3
  210. nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
  211. nautobot/dcim/templates/dcim/device_list.html +73 -10
  212. nautobot/dcim/templates/dcim/devicebay.html +1 -1
  213. nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
  214. nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
  215. nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
  216. nautobot/dcim/templates/dcim/frontport.html +10 -9
  217. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  218. nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
  219. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
  220. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  221. nautobot/dcim/templates/dcim/interface.html +35 -7
  222. nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
  223. nautobot/dcim/templates/dcim/interface_edit.html +2 -0
  224. nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
  225. nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
  226. nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
  227. nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
  228. nautobot/dcim/templates/dcim/module/base.html +49 -9
  229. nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
  230. nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
  231. nautobot/dcim/templates/dcim/module_frontports.html +1 -1
  232. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  233. nautobot/dcim/templates/dcim/module_list.html +57 -8
  234. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  235. nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
  236. nautobot/dcim/templates/dcim/module_powerports.html +1 -1
  237. nautobot/dcim/templates/dcim/module_rearports.html +1 -1
  238. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  239. nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
  240. nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
  241. nautobot/dcim/templates/dcim/platform_create.html +1 -1
  242. nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
  243. nautobot/dcim/templates/dcim/powerport.html +6 -5
  244. nautobot/dcim/templates/dcim/rack_elevation_list.html +17 -5
  245. nautobot/dcim/templates/dcim/rack_retrieve.html +22 -15
  246. nautobot/dcim/templates/dcim/rearport.html +8 -7
  247. nautobot/dcim/templates/dcim/trace/cable.html +1 -1
  248. nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
  249. nautobot/dcim/templates/dcim/virtualchassis_update.html +15 -7
  250. nautobot/dcim/tests/integration/test_controller.py +4 -6
  251. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
  252. nautobot/dcim/tests/integration/test_create_device.py +0 -2
  253. nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
  254. nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
  255. nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
  256. nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
  257. nautobot/dcim/tests/test_api.py +194 -6
  258. nautobot/dcim/tests/test_custom_validators.py +229 -0
  259. nautobot/dcim/tests/test_filters.py +55 -7
  260. nautobot/dcim/tests/test_forms.py +110 -8
  261. nautobot/dcim/tests/test_graphql.py +44 -1
  262. nautobot/dcim/tests/test_models.py +328 -4
  263. nautobot/dcim/tests/test_tables.py +160 -0
  264. nautobot/dcim/tests/test_views.py +132 -29
  265. nautobot/dcim/urls.py +64 -21
  266. nautobot/dcim/utils.py +3 -3
  267. nautobot/dcim/views.py +777 -397
  268. nautobot/extras/api/views.py +60 -45
  269. nautobot/extras/choices.py +2 -13
  270. nautobot/extras/datasources/git.py +3 -1
  271. nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
  272. nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
  273. nautobot/extras/{filters/__init__.py → filters.py} +33 -48
  274. nautobot/extras/forms/forms.py +14 -15
  275. nautobot/extras/forms/mixins.py +0 -41
  276. nautobot/extras/jobs.py +2 -0
  277. nautobot/extras/jobs_ui.py +4 -3
  278. nautobot/extras/management/__init__.py +11 -0
  279. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
  280. nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
  281. nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
  282. nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
  283. nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
  284. nautobot/extras/models/__init__.py +1 -2
  285. nautobot/extras/models/approvals.py +33 -14
  286. nautobot/extras/models/change_logging.py +4 -0
  287. nautobot/extras/models/contacts.py +2 -0
  288. nautobot/extras/models/groups.py +44 -5
  289. nautobot/extras/models/jobs.py +60 -4
  290. nautobot/extras/models/mixins.py +28 -0
  291. nautobot/extras/models/models.py +23 -2
  292. nautobot/extras/models/secrets.py +1 -0
  293. nautobot/extras/models/statuses.py +0 -15
  294. nautobot/extras/navigation.py +13 -9
  295. nautobot/extras/plugins/__init__.py +33 -55
  296. nautobot/extras/plugins/marketplace_manifest.yml +49 -1
  297. nautobot/extras/plugins/tables.py +3 -3
  298. nautobot/extras/plugins/urls.py +2 -21
  299. nautobot/extras/plugins/utils.py +1 -33
  300. nautobot/extras/plugins/views.py +0 -9
  301. nautobot/extras/querysets.py +8 -0
  302. nautobot/extras/signals.py +20 -19
  303. nautobot/extras/tables.py +64 -68
  304. nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
  305. nautobot/extras/templates/extras/approval_dashboard.html +7 -5
  306. nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
  307. nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
  308. nautobot/extras/templates/extras/configcontext_update.html +1 -0
  309. nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
  310. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
  311. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  312. nautobot/extras/templates/extras/gitrepository_result.html +0 -2
  313. nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
  314. nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
  315. nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
  316. nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
  317. nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
  318. nautobot/extras/templates/extras/inc/json_format.html +10 -3
  319. nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
  320. nautobot/extras/templates/extras/job.html +29 -12
  321. nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
  322. nautobot/extras/templates/extras/job_edit.html +52 -46
  323. nautobot/extras/templates/extras/job_list.html +29 -25
  324. nautobot/extras/templates/extras/marketplace.html +5 -9
  325. nautobot/extras/templates/extras/object_configcontext.html +1 -1
  326. nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
  327. nautobot/extras/templates/extras/objectchange_retrieve.html +19 -39
  328. nautobot/extras/templates/extras/plugin_detail.html +29 -24
  329. nautobot/extras/templates/extras/plugins_list.html +16 -26
  330. nautobot/extras/templates/extras/role_retrieve.html +64 -0
  331. nautobot/extras/templates/extras/scheduledjob.html +4 -2
  332. nautobot/extras/templates/extras/secret_create.html +1 -1
  333. nautobot/extras/templatetags/custom_links.py +12 -12
  334. nautobot/extras/templatetags/job_buttons.py +14 -12
  335. nautobot/extras/test_jobs/invalid_import.py +9 -0
  336. nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
  337. nautobot/extras/test_jobs/missing_import.py +11 -0
  338. nautobot/extras/tests/integration/test_computedfields.py +8 -9
  339. nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
  340. nautobot/extras/tests/integration/test_customfields.py +9 -10
  341. nautobot/extras/tests/integration/test_dynamicgroups.py +12 -9
  342. nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
  343. nautobot/extras/tests/integration/test_plugins.py +18 -6
  344. nautobot/extras/tests/integration/test_relationships.py +0 -2
  345. nautobot/extras/tests/test_api.py +90 -18
  346. nautobot/extras/tests/test_approvals.py +38 -38
  347. nautobot/extras/tests/test_changelog.py +59 -5
  348. nautobot/extras/tests/test_customfields.py +22 -13
  349. nautobot/extras/tests/test_customfields_filters.py +479 -0
  350. nautobot/extras/tests/test_dynamicgroups.py +39 -1
  351. nautobot/extras/tests/test_filters.py +57 -22
  352. nautobot/extras/tests/test_forms.py +18 -21
  353. nautobot/extras/tests/test_jobs.py +25 -4
  354. nautobot/extras/tests/test_migrations.py +1 -0
  355. nautobot/extras/tests/test_models.py +51 -33
  356. nautobot/extras/tests/test_plugins.py +36 -10
  357. nautobot/extras/tests/test_utils.py +3 -4
  358. nautobot/extras/tests/test_views.py +52 -112
  359. nautobot/extras/urls.py +0 -14
  360. nautobot/extras/views.py +164 -71
  361. nautobot/ipam/factory.py +7 -0
  362. nautobot/ipam/filter_mixins.py +38 -0
  363. nautobot/ipam/filters.py +53 -38
  364. nautobot/ipam/formfields.py +1 -1
  365. nautobot/ipam/forms.py +6 -3
  366. nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
  367. nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
  368. nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
  369. nautobot/ipam/models.py +29 -2
  370. nautobot/ipam/navigation.py +3 -2
  371. nautobot/ipam/signals.py +71 -0
  372. nautobot/ipam/tables.py +19 -6
  373. nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
  374. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
  375. nautobot/ipam/templates/ipam/ipaddress.html +14 -0
  376. nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
  377. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
  378. nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
  379. nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
  380. nautobot/ipam/templates/ipam/namespace_update.html +15 -0
  381. nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
  382. nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
  383. nautobot/ipam/templates/ipam/prefix_list.html +14 -13
  384. nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
  385. nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
  386. nautobot/ipam/tests/migration/test_migrations.py +89 -0
  387. nautobot/ipam/tests/test_api.py +13 -6
  388. nautobot/ipam/tests/test_filters.py +36 -1
  389. nautobot/ipam/tests/test_forms.py +1 -1
  390. nautobot/ipam/tests/test_models.py +44 -2
  391. nautobot/ipam/tests/test_tables.py +1 -2
  392. nautobot/ipam/tests/test_utils.py +1 -1
  393. nautobot/ipam/tests/test_views.py +13 -14
  394. nautobot/ipam/ui.py +0 -17
  395. nautobot/ipam/utils/migrations.py +16 -2
  396. nautobot/ipam/utils/testing.py +9 -3
  397. nautobot/ipam/views.py +53 -11
  398. nautobot/load_balancers/__init__.py +0 -0
  399. nautobot/load_balancers/api/__init__.py +1 -0
  400. nautobot/load_balancers/api/serializers.py +75 -0
  401. nautobot/load_balancers/api/urls.py +23 -0
  402. nautobot/load_balancers/api/views.py +61 -0
  403. nautobot/load_balancers/apps.py +17 -0
  404. nautobot/load_balancers/choices.py +167 -0
  405. nautobot/load_balancers/filters.py +225 -0
  406. nautobot/load_balancers/forms.py +532 -0
  407. nautobot/load_balancers/management/commands/__init__.py +0 -0
  408. nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
  409. nautobot/load_balancers/migrations/0001_initial.py +465 -0
  410. nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
  411. nautobot/load_balancers/migrations/__init__.py +0 -0
  412. nautobot/load_balancers/models.py +423 -0
  413. nautobot/load_balancers/navigation.py +80 -0
  414. nautobot/load_balancers/tables.py +255 -0
  415. nautobot/load_balancers/tests/__init__.py +474 -0
  416. nautobot/load_balancers/tests/test_api.py +353 -0
  417. nautobot/load_balancers/tests/test_filters.py +134 -0
  418. nautobot/load_balancers/tests/test_forms.py +266 -0
  419. nautobot/load_balancers/tests/test_models.py +195 -0
  420. nautobot/load_balancers/tests/test_views.py +229 -0
  421. nautobot/load_balancers/urls.py +17 -0
  422. nautobot/load_balancers/views.py +248 -0
  423. nautobot/project-static/dist/css/github-dark.min.css +10 -0
  424. nautobot/project-static/dist/css/github.min.css +10 -0
  425. nautobot/project-static/dist/css/nautobot.css +1 -11
  426. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  427. nautobot/project-static/dist/js/libraries.js +1 -1
  428. nautobot/project-static/dist/js/libraries.js.map +1 -1
  429. nautobot/project-static/dist/js/nautobot.js +1 -1
  430. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  431. nautobot/project-static/js/cabletrace.js +1 -1
  432. nautobot/project-static/js/forms.js +13 -0
  433. nautobot/project-static/js/interface_filtering.js +20 -16
  434. nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
  435. nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
  436. nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
  437. nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
  438. nautobot/project-static/nautobot-icons/cloud.svg +1 -1
  439. nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
  440. nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
  441. nautobot/project-static/nautobot-icons/elements.svg +1 -1
  442. nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
  443. nautobot/project-static/nautobot-icons/hammer.svg +1 -1
  444. nautobot/project-static/nautobot-icons/organization.svg +3 -0
  445. nautobot/project-static/nautobot-icons/secrets.svg +1 -1
  446. nautobot/project-static/nautobot-icons/security.svg +3 -0
  447. nautobot/project-static/nautobot-icons/server.svg +1 -1
  448. nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
  449. nautobot/project-static/nautobot-icons/star.svg +1 -1
  450. nautobot/tenancy/api/serializers.py +1 -0
  451. nautobot/tenancy/api/views.py +2 -1
  452. nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
  453. nautobot/tenancy/navigation.py +3 -1
  454. nautobot/tenancy/tests/test_filters.py +0 -2
  455. nautobot/tenancy/views.py +2 -1
  456. nautobot/ui/package-lock.json +87 -4
  457. nautobot/ui/package.json +2 -1
  458. nautobot/ui/src/js/collapse.js +3 -3
  459. nautobot/ui/src/js/nautobot.js +16 -1
  460. nautobot/ui/src/js/select2.js +53 -2
  461. nautobot/ui/src/scss/colors.scss +1 -1
  462. nautobot/ui/src/scss/nautobot.scss +112 -30
  463. nautobot/ui/webpack.config.js +13 -0
  464. nautobot/users/templates/users/preferences.html +11 -2
  465. nautobot/users/templates/users/profile.html +45 -12
  466. nautobot/users/templates/users/sessionkey_delete.html +1 -1
  467. nautobot/users/tests/test_api.py +4 -0
  468. nautobot/users/views.py +4 -2
  469. nautobot/virtualization/filters.py +6 -1
  470. nautobot/virtualization/models.py +1 -68
  471. nautobot/virtualization/navigation.py +3 -2
  472. nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
  473. nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
  474. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
  475. nautobot/virtualization/tests/test_api.py +3 -0
  476. nautobot/virtualization/tests/test_filters.py +10 -1
  477. nautobot/virtualization/tests/test_models.py +45 -4
  478. nautobot/virtualization/views.py +4 -1
  479. nautobot/vpn/__init__.py +0 -0
  480. nautobot/vpn/api/serializers.py +113 -0
  481. nautobot/vpn/api/urls.py +19 -0
  482. nautobot/vpn/api/views.py +70 -0
  483. nautobot/vpn/apps.py +8 -0
  484. nautobot/vpn/choices.py +171 -0
  485. nautobot/vpn/factory.py +219 -0
  486. nautobot/vpn/filters.py +234 -0
  487. nautobot/vpn/forms.py +487 -0
  488. nautobot/vpn/homepage.py +19 -0
  489. nautobot/vpn/migrations/0001_initial.py +541 -0
  490. nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
  491. nautobot/vpn/migrations/__init__.py +0 -0
  492. nautobot/vpn/models.py +535 -0
  493. nautobot/vpn/navigation.py +98 -0
  494. nautobot/vpn/tables.py +383 -0
  495. nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
  496. nautobot/vpn/tests/__init__.py +0 -0
  497. nautobot/vpn/tests/test_api.py +336 -0
  498. nautobot/vpn/tests/test_filters.py +139 -0
  499. nautobot/vpn/tests/test_forms.py +293 -0
  500. nautobot/vpn/tests/test_models.py +147 -0
  501. nautobot/vpn/tests/test_views.py +300 -0
  502. nautobot/vpn/urls.py +16 -0
  503. nautobot/vpn/views.py +495 -0
  504. nautobot/wireless/navigation.py +3 -2
  505. nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
  506. nautobot/wireless/tests/test_api.py +1 -1
  507. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +15 -15
  508. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +514 -572
  509. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +1 -0
  510. nautobot/circuits/templates/circuits/circuit.html +0 -2
  511. nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
  512. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
  513. nautobot/circuits/templates/circuits/circuit_update.html +0 -1
  514. nautobot/circuits/templates/circuits/circuittermination.html +0 -2
  515. nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
  516. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
  517. nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
  518. nautobot/circuits/templates/circuits/circuittype.html +0 -2
  519. nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
  520. nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
  521. nautobot/circuits/templates/circuits/provider.html +0 -2
  522. nautobot/circuits/templates/circuits/provider_edit.html +0 -2
  523. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
  524. nautobot/circuits/templates/circuits/provider_update.html +0 -1
  525. nautobot/circuits/templates/circuits/providernetwork.html +0 -2
  526. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
  527. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
  528. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
  529. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
  530. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
  531. nautobot/core/templates/buttons/import.html +0 -9
  532. nautobot/data_validation/template_content.py +0 -42
  533. nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
  534. nautobot/dcim/filters/mixins.py +0 -354
  535. nautobot/dcim/templates/dcim/controller/base.html +0 -2
  536. nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
  537. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
  538. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
  539. nautobot/dcim/templates/dcim/device/base.html +0 -2
  540. nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
  541. nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
  542. nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
  543. nautobot/dcim/templates/dcim/device/frontports.html +0 -2
  544. nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
  545. nautobot/dcim/templates/dcim/device/inventory.html +0 -2
  546. nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
  547. nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
  548. nautobot/dcim/templates/dcim/device/powerports.html +0 -2
  549. nautobot/dcim/templates/dcim/device/rearports.html +0 -2
  550. nautobot/dcim/templates/dcim/device/wireless.html +0 -2
  551. nautobot/dcim/templates/dcim/device_component.html +0 -2
  552. nautobot/dcim/templates/dcim/device_edit.html +0 -2
  553. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
  554. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
  555. nautobot/dcim/templates/dcim/devicetype.html +0 -2
  556. nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
  557. nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
  558. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
  559. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
  560. nautobot/dcim/templates/dcim/location.html +0 -2
  561. nautobot/dcim/templates/dcim/location_edit.html +0 -2
  562. nautobot/dcim/templates/dcim/location_retrieve.html +0 -243
  563. nautobot/dcim/templates/dcim/locationtype.html +0 -2
  564. nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
  565. nautobot/dcim/templates/dcim/manufacturer.html +0 -2
  566. nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
  567. nautobot/dcim/templates/dcim/platform.html +0 -2
  568. nautobot/dcim/templates/dcim/powerfeed.html +0 -2
  569. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
  570. nautobot/dcim/templates/dcim/powerpanel.html +0 -2
  571. nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
  572. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
  573. nautobot/dcim/templates/dcim/rack.html +0 -2
  574. nautobot/dcim/templates/dcim/rack_edit.html +0 -2
  575. nautobot/dcim/templates/dcim/rackgroup.html +0 -2
  576. nautobot/dcim/templates/dcim/rackreservation.html +0 -2
  577. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
  578. nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
  579. nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
  580. nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
  581. nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
  582. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
  583. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
  584. nautobot/dcim/ui.py +0 -29
  585. nautobot/extras/templates/extras/computedfield.html +0 -2
  586. nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
  587. nautobot/extras/templates/extras/configcontext.html +0 -2
  588. nautobot/extras/templates/extras/configcontext_edit.html +0 -2
  589. nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
  590. nautobot/extras/templates/extras/configcontextschema.html +0 -2
  591. nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
  592. nautobot/extras/templates/extras/contact_retrieve.html +0 -2
  593. nautobot/extras/templates/extras/customfield.html +0 -2
  594. nautobot/extras/templates/extras/customfield_edit.html +0 -2
  595. nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
  596. nautobot/extras/templates/extras/customlink.html +0 -2
  597. nautobot/extras/templates/extras/dynamicgroup.html +0 -2
  598. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
  599. nautobot/extras/templates/extras/exporttemplate.html +0 -2
  600. nautobot/extras/templates/extras/gitrepository.html +0 -2
  601. nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
  602. nautobot/extras/templates/extras/graphqlquery.html +0 -2
  603. nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
  604. nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -97
  605. nautobot/extras/templates/extras/job_detail.html +0 -2
  606. nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
  607. nautobot/extras/templates/extras/jobhook.html +0 -2
  608. nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
  609. nautobot/extras/templates/extras/jobresult.html +0 -2
  610. nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
  611. nautobot/extras/templates/extras/note.html +0 -2
  612. nautobot/extras/templates/extras/note_retrieve.html +0 -1
  613. nautobot/extras/templates/extras/object_changelog.html +0 -2
  614. nautobot/extras/templates/extras/object_notes.html +0 -2
  615. nautobot/extras/templates/extras/objectchange.html +0 -2
  616. nautobot/extras/templates/extras/objectchange_list.html +0 -3
  617. nautobot/extras/templates/extras/relationship.html +0 -1
  618. nautobot/extras/templates/extras/secret.html +0 -1
  619. nautobot/extras/templates/extras/secret_edit.html +0 -1
  620. nautobot/extras/templates/extras/secretsgroup.html +0 -2
  621. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
  622. nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
  623. nautobot/extras/templates/extras/status.html +0 -2
  624. nautobot/extras/templates/extras/tag.html +0 -2
  625. nautobot/extras/templates/extras/tag_edit.html +0 -2
  626. nautobot/extras/templates/extras/tag_retrieve.html +0 -2
  627. nautobot/extras/templates/extras/team_retrieve.html +0 -2
  628. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
  629. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
  630. nautobot/ipam/templates/ipam/prefix.html +0 -2
  631. nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
  632. nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
  633. nautobot/ipam/templates/ipam/rir.html +0 -2
  634. nautobot/ipam/templates/ipam/routetarget.html +0 -1
  635. nautobot/ipam/templates/ipam/service.html +0 -2
  636. nautobot/ipam/templates/ipam/service_edit.html +0 -2
  637. nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
  638. nautobot/ipam/templates/ipam/vlan.html +0 -2
  639. nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
  640. nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
  641. nautobot/ipam/templates/ipam/vlangroup.html +0 -2
  642. nautobot/ipam/templates/ipam/vrf.html +0 -1
  643. nautobot/tenancy/templates/tenancy/tenant.html +0 -2
  644. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
  645. nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
  646. nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
  647. nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
  648. nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
  649. nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
  650. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
  651. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
  652. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
  653. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
  654. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
  655. /nautobot/dcim/templates/dcim/{cable.html → cable_retrieve.html} +0 -0
  656. /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
  657. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
  658. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
  659. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
@@ -29,6 +29,7 @@ from nautobot.core.utils.permissions import get_permission_for_model
29
29
  from nautobot.dcim.models import (
30
30
  ConsolePort,
31
31
  Device,
32
+ DeviceFamily,
32
33
  DeviceType,
33
34
  Interface,
34
35
  Location,
@@ -96,7 +97,6 @@ from nautobot.extras.models import (
96
97
  from nautobot.extras.templatetags.job_buttons import NO_CONFIRM_BUTTON
97
98
  from nautobot.extras.tests.constants import BIG_GRAPHQL_DEVICE_QUERY
98
99
  from nautobot.extras.tests.test_jobs import get_job_class_and_model
99
- from nautobot.extras.tests.test_relationships import RequiredRelationshipTestMixin
100
100
  from nautobot.extras.utils import get_pending_approval_workflow_stages, RoleModelsQuery, TaggableClassesQuery
101
101
  from nautobot.ipam.models import IPAddress, Prefix, VLAN, VLANGroup, VRF
102
102
  from nautobot.tenancy.models import Tenant
@@ -132,14 +132,14 @@ class ApprovalWorkflowDefinitionViewTestCase(
132
132
  ApprovalWorkflowDefinition.objects.create(
133
133
  name=f"Test Approval Workflow {i}",
134
134
  model_content_type=cls.scheduledjob_ct,
135
- priority=i,
135
+ weight=i,
136
136
  )
137
137
 
138
138
  cls.form_data = {
139
139
  "name": "Test Approval Workflow Definition 5",
140
140
  "model_content_type": cls.scheduledjob_ct.pk,
141
141
  "model_constraints": '{"name": "Bulk Delete Objects"}',
142
- "priority": 5,
142
+ "weight": 5,
143
143
  # These are the "management_form" fields required by the dynamic CustomFieldChoice formsets.
144
144
  "approval_workflow_stage_definitions-TOTAL_FORMS": "0", # Set to 0 so validation succeeds until we need it
145
145
  "approval_workflow_stage_definitions-INITIAL_FORMS": "1",
@@ -161,14 +161,14 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
161
161
  cls.approval_workflow_definition = ApprovalWorkflowDefinition.objects.create(
162
162
  name="Test Approval Workflow Definition 1",
163
163
  model_content_type=cls.scheduledjob_ct,
164
- priority=10,
164
+ weight=10,
165
165
  )
166
166
  cls.approver_group = Group.objects.create(name="Test Group 1")
167
167
  cls.updated_approver_group = Group.objects.create(name="Test Group 2")
168
168
  # Deletable objects
169
169
  ApprovalWorkflowStageDefinition.objects.create(
170
170
  approval_workflow_definition=cls.approval_workflow_definition,
171
- weight=100,
171
+ sequence=100,
172
172
  name="Test Approval Workflow 1 Stage 1 Definition",
173
173
  min_approvers=2,
174
174
  denial_message="Stage 1 Denial Message",
@@ -176,7 +176,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
176
176
  )
177
177
  ApprovalWorkflowStageDefinition.objects.create(
178
178
  approval_workflow_definition=cls.approval_workflow_definition,
179
- weight=200,
179
+ sequence=200,
180
180
  name="Test Approval Workflow 1 Stage 2 Definition",
181
181
  min_approvers=3,
182
182
  denial_message="Stage 2 Denial Message",
@@ -184,7 +184,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
184
184
  )
185
185
  ApprovalWorkflowStageDefinition.objects.create(
186
186
  approval_workflow_definition=cls.approval_workflow_definition,
187
- weight=300,
187
+ sequence=300,
188
188
  name="Test Approval Workflow 1 Stage 3 Definition",
189
189
  min_approvers=4,
190
190
  denial_message="Stage 3 Denial Message",
@@ -192,7 +192,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
192
192
  )
193
193
  ApprovalWorkflowStageDefinition.objects.create(
194
194
  approval_workflow_definition=cls.approval_workflow_definition,
195
- weight=400,
195
+ sequence=400,
196
196
  name="Test Approval Workflow 1 Stage 4 Definition",
197
197
  min_approvers=4,
198
198
  denial_message="Stage 4 Denial Message",
@@ -200,7 +200,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
200
200
  )
201
201
  ApprovalWorkflowStageDefinition.objects.create(
202
202
  approval_workflow_definition=cls.approval_workflow_definition,
203
- weight=500,
203
+ sequence=500,
204
204
  name="Test Approval Workflow 1 Stage 5 Definition",
205
205
  min_approvers=4,
206
206
  denial_message="Stage 5 Denial Message",
@@ -209,7 +209,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
209
209
 
210
210
  cls.form_data = {
211
211
  "approval_workflow_definition": cls.approval_workflow_definition.pk,
212
- "weight": 600,
212
+ "sequence": 600,
213
213
  "name": "Approval Workflow Stage 1 Definition",
214
214
  "min_approvers": 2,
215
215
  "denial_message": "Stage 1 is denied",
@@ -218,7 +218,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
218
218
 
219
219
  cls.update_data = {
220
220
  "approval_workflow_definition": cls.approval_workflow_definition.pk,
221
- "weight": 700,
221
+ "sequence": 700,
222
222
  "name": "Updated approval workflow stage 1",
223
223
  "min_approvers": 3,
224
224
  "denial_message": "updated message",
@@ -226,7 +226,7 @@ class ApprovalWorkflowStageDefinitionViewTestCase(ViewTestCases.PrimaryObjectVie
226
226
  }
227
227
 
228
228
  cls.bulk_edit_data = {
229
- "weight": 800,
229
+ "sequence": 800,
230
230
  "min_approvers": 5,
231
231
  "denial_message": "updated denial message",
232
232
  }
@@ -264,7 +264,7 @@ class ApprovalWorkflowViewTestCase(
264
264
  ]
265
265
  approval_workflow_definitions = [
266
266
  ApprovalWorkflowDefinition.objects.create(
267
- name=f"Test Approval Workflow {i}", model_content_type=cls.scheduledjob_ct, priority=i
267
+ name=f"Test Approval Workflow {i}", model_content_type=cls.scheduledjob_ct, weight=i
268
268
  )
269
269
  for i in range(5)
270
270
  ]
@@ -332,7 +332,7 @@ class ApprovalWorkflowStageViewTestCase(
332
332
  ApprovalWorkflowDefinition.objects.create(
333
333
  name=f"Test Approval Workflow {i}",
334
334
  model_content_type=cls.scheduledjob_ct,
335
- priority=i,
335
+ weight=i,
336
336
  )
337
337
  for i in range(5)
338
338
  ]
@@ -342,7 +342,7 @@ class ApprovalWorkflowStageViewTestCase(
342
342
  cls.approval_workflow_stage_definitions.append(
343
343
  ApprovalWorkflowStageDefinition.objects.create(
344
344
  approval_workflow_definition=approval_workflow_definition,
345
- weight=i * 100,
345
+ sequence=i * 100,
346
346
  name=f"Test Approval Workflow Stage {i} Definition",
347
347
  min_approvers=i + 1,
348
348
  denial_message=f"Stage {i} Denial Message",
@@ -516,7 +516,7 @@ class ApprovalWorkflowStageResponseViewTestCase(
516
516
  ApprovalWorkflowDefinition.objects.create(
517
517
  name=f"Test Approval Workflow {i} Definition",
518
518
  model_content_type=cls.scheduledjob_ct,
519
- priority=i,
519
+ weight=i,
520
520
  )
521
521
  for i in range(5)
522
522
  ]
@@ -526,7 +526,7 @@ class ApprovalWorkflowStageResponseViewTestCase(
526
526
  cls.approval_workflow_stage_definitions.append(
527
527
  ApprovalWorkflowStageDefinition.objects.create(
528
528
  approval_workflow_definition=approval_workflow_definition,
529
- weight=i * 100,
529
+ sequence=i * 100,
530
530
  name=f"Test Approval Workflow Stage {i} Definition",
531
531
  min_approvers=i + 1,
532
532
  denial_message=f"Stage {i} Denial Message",
@@ -730,6 +730,7 @@ class ConfigContextTestCase(
730
730
  "regions": [],
731
731
  "locations": [location.pk],
732
732
  "roles": [],
733
+ "device_families": [DeviceFamily.objects.first().pk],
733
734
  "device_types": [],
734
735
  "platforms": [],
735
736
  "tenant_groups": [],
@@ -764,6 +765,7 @@ class ConfigContextTestCase(
764
765
  "regions": [],
765
766
  "locations": [],
766
767
  "roles": [],
768
+ "device_families": [],
767
769
  "device_types": [],
768
770
  "platforms": [],
769
771
  "tenant_groups": [],
@@ -803,6 +805,7 @@ class ConfigContextTestCase(
803
805
  "regions": [],
804
806
  "locations": [],
805
807
  "roles": [],
808
+ "device_families": [],
806
809
  "device_types": [],
807
810
  "platforms": [],
808
811
  "tenant_groups": [],
@@ -2346,6 +2349,7 @@ class SavedViewTest(ModelViewTestCase):
2346
2349
  self.assertIn(str(sv_shared.pk), response_body, msg=response_body)
2347
2350
  self.assertNotIn(str(sv_not_shared.pk), response_body, msg=response_body)
2348
2351
 
2352
+ @tag("example_app")
2349
2353
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2350
2354
  def test_create_saved_views_contain_boolean_filter_params(self):
2351
2355
  """
@@ -2754,59 +2758,6 @@ class ScheduledJobTestCase(
2754
2758
  crontab="15 10 * * *",
2755
2759
  )
2756
2760
 
2757
- def test_only_enabled_is_listed(self):
2758
- self.add_permissions("extras.view_scheduledjob")
2759
-
2760
- # this should not appear, since it's not enabled
2761
- ScheduledJob.objects.create(
2762
- enabled=False,
2763
- name="test4",
2764
- task="pass_job.TestPassJob",
2765
- interval=JobExecutionType.TYPE_IMMEDIATELY,
2766
- user=self.user,
2767
- start_time=timezone.now(),
2768
- )
2769
-
2770
- response = self.client.get(self._get_url("list"))
2771
- self.assertHttpStatus(response, 200)
2772
- self.assertNotIn("test4", extract_page_body(response.content.decode(response.charset)))
2773
-
2774
- def test_approved_required_jobs_are_listed_only_when_approved(self):
2775
- self.add_permissions("extras.view_scheduledjob")
2776
-
2777
- # this should not appear, since it's not approved
2778
- ScheduledJob.objects.create(
2779
- enabled=True,
2780
- approval_required=True,
2781
- decision_date=None,
2782
- name="test4",
2783
- task="pass_job.TestPassJob",
2784
- interval=JobExecutionType.TYPE_IMMEDIATELY,
2785
- user=self.user,
2786
- start_time=timezone.now(),
2787
- )
2788
- ScheduledJob.objects.create(
2789
- enabled=True,
2790
- approval_required=False,
2791
- name="test5",
2792
- task="pass_job.TestPassJob",
2793
- interval=JobExecutionType.TYPE_IMMEDIATELY,
2794
- user=self.user,
2795
- start_time=timezone.now(),
2796
- )
2797
- response = self.client.get(self._get_url("list"))
2798
- self.assertHttpStatus(response, 200)
2799
- self.assertNotIn("test4", extract_page_body(response.content.decode(response.charset)))
2800
- self.assertIn("test5", extract_page_body(response.content.decode(response.charset)))
2801
-
2802
- scheduled_job = ScheduledJob.objects.get(name="test4")
2803
- scheduled_job.decision_date = timezone.now()
2804
- scheduled_job.save()
2805
-
2806
- response = self.client.get(self._get_url("list"))
2807
- self.assertHttpStatus(response, 200)
2808
- self.assertIn("test4", extract_page_body(response.content.decode(response.charset)))
2809
-
2810
2761
  def test_non_valid_crontab_syntax(self):
2811
2762
  self.add_permissions("extras.view_scheduledjob")
2812
2763
 
@@ -3290,7 +3241,6 @@ class JobTestCase(
3290
3241
 
3291
3242
  result = JobResult.objects.latest()
3292
3243
  self.assertRedirects(response, reverse("extras:jobresult", kwargs={"pk": result.pk}))
3293
- mock_begin_approval_workflow.assert_not_called()
3294
3244
 
3295
3245
  def test_rerun_job(self):
3296
3246
  self.add_permissions("extras.run_job")
@@ -3327,7 +3277,8 @@ class JobTestCase(
3327
3277
  )
3328
3278
  self.assertInHTML('<input type="hidden" name="_profile" value="True" id="id__profile">', content)
3329
3279
  self.assertInHTML(
3330
- '<input type="checkbox" name="_ignore_singleton_lock" id="id__ignore_singleton_lock" checked>', content
3280
+ '<input type="checkbox" name="_ignore_singleton_lock" id="id__ignore_singleton_lock" class="form-check-input" checked>',
3281
+ content,
3331
3282
  )
3332
3283
 
3333
3284
  @mock.patch("nautobot.extras.views.get_worker_count", return_value=1)
@@ -3461,7 +3412,7 @@ class JobTestCase(
3461
3412
  ApprovalWorkflowDefinition.objects.create(
3462
3413
  name="Test Approval Workflow Definition 1",
3463
3414
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3464
- priority=0,
3415
+ weight=0,
3465
3416
  )
3466
3417
 
3467
3418
  self.add_permissions("extras.run_job")
@@ -3491,7 +3442,7 @@ class JobTestCase(
3491
3442
  ApprovalWorkflowDefinition.objects.create(
3492
3443
  name="Approval Definition",
3493
3444
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3494
- priority=0,
3445
+ weight=0,
3495
3446
  )
3496
3447
  data = {
3497
3448
  "_schedule_type": "immediately",
@@ -3510,11 +3461,13 @@ class JobTestCase(
3510
3461
  self.add_permissions("extras.run_job")
3511
3462
  self.add_permissions("extras.view_scheduledjob")
3512
3463
 
3513
- ApprovalWorkflowDefinition.objects.create(
3464
+ workflow = ApprovalWorkflowDefinition(
3514
3465
  name="Approval Definition",
3515
3466
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3516
- priority=0,
3467
+ weight=0,
3468
+ model_constraints={"job_model__name": self.test_pass.name},
3517
3469
  )
3470
+ workflow.validated_save()
3518
3471
  data = {
3519
3472
  "_schedule_type": "future",
3520
3473
  "_schedule_name": "test",
@@ -3522,14 +3475,15 @@ class JobTestCase(
3522
3475
  }
3523
3476
 
3524
3477
  for i, run_url in enumerate(self.run_urls):
3525
- if "_schedule_name" in data:
3526
- data["_schedule_name"] = f"test {i}"
3527
- response = self.client.post(run_url, data)
3528
- scheduled_job = ScheduledJob.objects.last()
3529
- self.assertRedirects(
3530
- response,
3531
- reverse("extras:scheduledjob_approvalworkflow", args=[scheduled_job.pk]),
3532
- )
3478
+ with self.subTest(run_url=run_url):
3479
+ if "_schedule_name" in data:
3480
+ data["_schedule_name"] = f"test {i}"
3481
+ response = self.client.post(run_url, data)
3482
+ scheduled_job = ScheduledJob.objects.last()
3483
+ self.assertRedirects(
3484
+ response,
3485
+ reverse("extras:scheduledjob_approvalworkflow", args=[scheduled_job.pk]),
3486
+ )
3533
3487
 
3534
3488
  @mock.patch("nautobot.extras.views.get_worker_count", return_value=1)
3535
3489
  def test_run_scheduled_job_with_no_approval_workflow_defined(self, _):
@@ -3574,7 +3528,7 @@ class JobTestCase(
3574
3528
  ApprovalWorkflowDefinition.objects.create(
3575
3529
  name="Approval Definition",
3576
3530
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3577
- priority=0,
3531
+ weight=0,
3578
3532
  )
3579
3533
 
3580
3534
  data = {
@@ -3599,7 +3553,7 @@ class JobTestCase(
3599
3553
  ApprovalWorkflowDefinition.objects.create(
3600
3554
  name="Approval Definition",
3601
3555
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3602
- priority=0,
3556
+ weight=0,
3603
3557
  )
3604
3558
 
3605
3559
  data = {
@@ -3625,7 +3579,7 @@ class JobTestCase(
3625
3579
  ApprovalWorkflowDefinition.objects.create(
3626
3580
  name="Approval Definition",
3627
3581
  model_content_type=ContentType.objects.get_for_model(ScheduledJob),
3628
- priority=0,
3582
+ weight=0,
3629
3583
  )
3630
3584
  data = {
3631
3585
  "_schedule_type": "future",
@@ -3765,14 +3719,12 @@ class JobButtonRenderingTestCase(TestCase):
3765
3719
 
3766
3720
  self.location_type = LocationType.objects.get(name="Campus")
3767
3721
 
3768
- @tag("fix_in_v3")
3769
3722
  def test_view_object_with_job_button(self):
3770
3723
  """Ensure that the job button is rendered."""
3771
3724
  response = self.client.get(self.location_type.get_absolute_url(), follow=True)
3772
3725
  self.assertBodyContains(response, f"JobButton {self.location_type.name}")
3773
3726
  self.assertBodyContains(response, "Click me!")
3774
3727
 
3775
- @tag("fix_in_v3")
3776
3728
  def test_task_queue_hidden_input_is_present(self):
3777
3729
  """
3778
3730
  Ensure that the job button respects the job class' task_queues and the job class default job queue is passed as a hidden form input.
@@ -3800,7 +3752,6 @@ class JobButtonRenderingTestCase(TestCase):
3800
3752
  f'<input type="hidden" name="_job_queue" value="{self.job.default_job_queue.pk}">', content, content
3801
3753
  )
3802
3754
 
3803
- @tag("fix_in_v3")
3804
3755
  def test_view_object_with_unsafe_text(self):
3805
3756
  """Ensure that JobButton text can't be used as a vector for XSS."""
3806
3757
  self.job_button_1.text = '<script>alert("Hello world!")</script>'
@@ -3820,7 +3771,6 @@ class JobButtonRenderingTestCase(TestCase):
3820
3771
  self.assertNotIn("<script>alert", content, content)
3821
3772
  self.assertIn("&lt;script&gt;alert", content, content)
3822
3773
 
3823
- @tag("fix_in_v3")
3824
3774
  def test_view_object_with_unsafe_name(self):
3825
3775
  """Ensure that JobButton names can't be used as a vector for XSS."""
3826
3776
  self.job_button_1.text = "JobButton {{ obj"
@@ -3832,7 +3782,6 @@ class JobButtonRenderingTestCase(TestCase):
3832
3782
  self.assertNotIn("<script>alert", content, content)
3833
3783
  self.assertIn("&lt;script&gt;alert", content, content)
3834
3784
 
3835
- @tag("fix_in_v3")
3836
3785
  def test_render_constrained_run_permissions(self):
3837
3786
  obj_perm = ObjectPermission(
3838
3787
  name="Test permission",
@@ -3851,8 +3800,9 @@ class JobButtonRenderingTestCase(TestCase):
3851
3800
  NO_CONFIRM_BUTTON.format(
3852
3801
  button_id=self.job_button_1.pk,
3853
3802
  button_text=f"JobButton {self.location_type.name}",
3854
- button_class=self.job_button_1.button_class,
3803
+ button_class=self.job_button_1.button_class_css_class,
3855
3804
  disabled="",
3805
+ menu_item="",
3856
3806
  ),
3857
3807
  content,
3858
3808
  )
@@ -3860,8 +3810,9 @@ class JobButtonRenderingTestCase(TestCase):
3860
3810
  NO_CONFIRM_BUTTON.format(
3861
3811
  button_id=self.job_button_2.pk,
3862
3812
  button_text="Click me!",
3863
- button_class=self.job_button_2.button_class,
3813
+ button_class=self.job_button_2.button_class_css_class,
3864
3814
  disabled="disabled",
3815
+ menu_item="",
3865
3816
  ),
3866
3817
  content,
3867
3818
  )
@@ -3882,6 +3833,7 @@ class JobButtonRenderingTestCase(TestCase):
3882
3833
  button_text=f"JobButton {self.location_type.name}",
3883
3834
  button_class="link",
3884
3835
  disabled="",
3836
+ menu_item="dropdown-item",
3885
3837
  )
3886
3838
  + "</li>",
3887
3839
  content,
@@ -3893,12 +3845,14 @@ class JobButtonRenderingTestCase(TestCase):
3893
3845
  button_text="Click me!",
3894
3846
  button_class="link",
3895
3847
  disabled="disabled",
3848
+ menu_item="dropdown-item",
3896
3849
  )
3897
3850
  + "</li>",
3898
3851
  content,
3899
3852
  )
3900
3853
 
3901
3854
 
3855
+ @tag("example_app")
3902
3856
  class JobCustomTemplateTestCase(TestCase):
3903
3857
  @classmethod
3904
3858
  def setUpTestData(cls):
@@ -4067,17 +4021,7 @@ class ObjectMetadataTestCase(
4067
4021
  self.assertNotIn(instance2.assigned_object.get_absolute_url(), content, msg=content)
4068
4022
 
4069
4023
 
4070
- class RelationshipTestCase(
4071
- ViewTestCases.CreateObjectViewTestCase,
4072
- ViewTestCases.DeleteObjectViewTestCase,
4073
- ViewTestCases.EditObjectViewTestCase,
4074
- ViewTestCases.BulkDeleteObjectsViewTestCase,
4075
- ViewTestCases.GetObjectViewTestCase,
4076
- ViewTestCases.GetObjectChangelogViewTestCase,
4077
- ViewTestCases.ListObjectsViewTestCase,
4078
- RequiredRelationshipTestMixin,
4079
- ViewTestCases.BulkEditObjectsViewTestCase,
4080
- ):
4024
+ class RelationshipTestCase(ViewTestCases.PrimaryObjectViewTestCase):
4081
4025
  model = Relationship
4082
4026
  slug_source = "label"
4083
4027
  slugify_function = staticmethod(slugify_dashes_to_underscores)
@@ -4591,7 +4535,6 @@ class RoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase, ViewTestCases
4591
4535
  "remove_content_types": [device_ct.pk],
4592
4536
  }
4593
4537
 
4594
- @tag("fix_in_v3")
4595
4538
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
4596
4539
  def test_view_with_content_types(self):
4597
4540
  """
@@ -4610,13 +4553,10 @@ class RoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase, ViewTestCases
4610
4553
  if content_type not in role_content_types:
4611
4554
  if result == "Contact Associations":
4612
4555
  # AssociationContact Table in the contact tab should be there.
4613
- self.assertInHTML(
4614
- f'<strong>{result}</strong><div class="pull-right d-print-none">',
4615
- response_body,
4616
- )
4617
- # ContactAssociationTable related to this role instances should not be there.
4556
+ self.assertInHTML(f"<strong>{result}</strong>", response_body)
4557
+ # ContactAssociationTable related to this role instances in the main tab should not be there.
4618
4558
  self.assertNotIn(
4619
- f'<strong>{result}</strong>\n </div>\n \n\n<table class="table table-hover nb-table-headings">\n',
4559
+ f'<strong>{result}</strong>\n </div>\n \n\n\n\n <table class="table table-hover nb-table-headings">',
4620
4560
  response_body,
4621
4561
  )
4622
4562
  else:
nautobot/extras/urls.py CHANGED
@@ -5,7 +5,6 @@ from nautobot.core.views.routers import NautobotUIViewSetRouter
5
5
  from nautobot.extras import views
6
6
  from nautobot.extras.models import (
7
7
  Job,
8
- Relationship,
9
8
  ScheduledJob,
10
9
  )
11
10
 
@@ -135,19 +134,6 @@ urlpatterns = [
135
134
  name="scheduledjob_approvalworkflow",
136
135
  kwargs={"model": ScheduledJob},
137
136
  ),
138
- # Custom relationships
139
- path(
140
- "relationships/<uuid:pk>/changelog/",
141
- views.ObjectChangeLogView.as_view(),
142
- name="relationship_changelog",
143
- kwargs={"model": Relationship},
144
- ),
145
- path(
146
- "relationships/<uuid:pk>/notes/",
147
- views.ObjectNotesView.as_view(),
148
- name="relationship_notes",
149
- kwargs={"model": Relationship},
150
- ),
151
137
  # Secrets
152
138
  path(
153
139
  "secrets/provider/<str:provider_slug>/form/",