nautobot 2.0.0a3__py3-none-any.whl → 2.0.0b1__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 (780) hide show
  1. nautobot/apps/api.py +6 -8
  2. nautobot/apps/forms.py +0 -2
  3. nautobot/apps/ui.py +0 -8
  4. nautobot/circuits/api/serializers.py +9 -117
  5. nautobot/circuits/api/urls.py +1 -1
  6. nautobot/circuits/api/views.py +0 -1
  7. nautobot/circuits/forms.py +0 -65
  8. nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
  9. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  10. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  11. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  12. nautobot/circuits/models.py +3 -87
  13. nautobot/circuits/navigation.py +14 -69
  14. nautobot/circuits/signals.py +0 -2
  15. nautobot/circuits/tables.py +39 -1
  16. nautobot/circuits/tests/integration/test_relationships.py +9 -9
  17. nautobot/circuits/tests/test_api.py +4 -8
  18. nautobot/circuits/tests/test_filters.py +10 -4
  19. nautobot/circuits/tests/test_models.py +5 -1
  20. nautobot/circuits/tests/test_views.py +27 -5
  21. nautobot/circuits/views.py +18 -10
  22. nautobot/core/api/__init__.py +8 -2
  23. nautobot/core/api/fields.py +15 -6
  24. nautobot/core/api/filter_backends.py +3 -2
  25. nautobot/core/api/metadata.py +237 -30
  26. nautobot/core/api/mixins.py +94 -0
  27. nautobot/core/api/pagination.py +4 -0
  28. nautobot/core/api/parsers.py +154 -0
  29. nautobot/core/api/renderers.py +153 -2
  30. nautobot/core/api/schema.py +46 -2
  31. nautobot/core/api/serializers.py +377 -35
  32. nautobot/core/api/urls.py +11 -3
  33. nautobot/core/api/utils.py +174 -2
  34. nautobot/core/api/versioning.py +32 -10
  35. nautobot/core/api/views.py +266 -72
  36. nautobot/core/apps/__init__.py +138 -220
  37. nautobot/core/celery/__init__.py +112 -41
  38. nautobot/core/celery/backends.py +19 -12
  39. nautobot/core/celery/control.py +46 -0
  40. nautobot/core/celery/encoders.py +53 -0
  41. nautobot/core/celery/log.py +38 -0
  42. nautobot/core/celery/schedulers.py +23 -4
  43. nautobot/core/celery/task.py +1 -16
  44. nautobot/core/checks.py +0 -27
  45. nautobot/core/choices.py +0 -113
  46. nautobot/core/{cli.py → cli/__init__.py} +1 -1
  47. nautobot/core/cli/__main__.py +3 -0
  48. nautobot/core/constants.py +0 -24
  49. nautobot/core/context_processors.py +12 -0
  50. nautobot/core/filters.py +2 -2
  51. nautobot/core/forms/__init__.py +0 -4
  52. nautobot/core/forms/fields.py +38 -65
  53. nautobot/core/forms/forms.py +4 -1
  54. nautobot/core/forms/utils.py +0 -52
  55. nautobot/core/graphql/schema.py +4 -27
  56. nautobot/core/jobs/__init__.py +75 -0
  57. nautobot/core/management/commands/build_ui.py +255 -0
  58. nautobot/core/management/commands/generate_test_data.py +3 -2
  59. nautobot/core/management/commands/post_upgrade.py +24 -24
  60. nautobot/core/models/__init__.py +26 -1
  61. nautobot/core/models/fields.py +24 -5
  62. nautobot/core/models/generics.py +2 -42
  63. nautobot/core/models/managers.py +5 -0
  64. nautobot/core/models/name_color_content_types.py +0 -14
  65. nautobot/core/models/tree_queries.py +14 -4
  66. nautobot/core/models/utils.py +5 -6
  67. nautobot/core/models/validators.py +17 -8
  68. nautobot/core/releases.py +8 -10
  69. nautobot/core/settings.py +80 -42
  70. nautobot/core/tables.py +5 -5
  71. nautobot/core/tasks.py +4 -7
  72. nautobot/core/templates/base.html +1 -49
  73. nautobot/core/templates/base_django.html +49 -0
  74. nautobot/core/templates/base_react.html +55 -0
  75. nautobot/core/templates/buttons/export.html +6 -4
  76. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  77. nautobot/core/templates/generic/object_list.html +3 -1
  78. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  79. nautobot/core/templates/inc/footer.html +1 -0
  80. nautobot/core/templates/inc/javascript.html +0 -14
  81. nautobot/core/templates/inc/nav_menu.html +28 -33
  82. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  83. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  84. nautobot/core/templates/nautobot_config.py.j2 +8 -20
  85. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  86. nautobot/core/templates/rest_framework/api.html +8 -0
  87. nautobot/core/templatetags/buttons.py +32 -28
  88. nautobot/core/testing/__init__.py +47 -44
  89. nautobot/core/testing/api.py +362 -47
  90. nautobot/core/testing/filters.py +1 -1
  91. nautobot/core/testing/migrations.py +2 -0
  92. nautobot/core/testing/mixins.py +22 -9
  93. nautobot/core/testing/schema.py +2 -1
  94. nautobot/core/testing/views.py +21 -46
  95. nautobot/core/tests/integration/test_filters.py +17 -8
  96. nautobot/core/tests/integration/test_navbar.py +11 -34
  97. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  98. nautobot/core/tests/nautobot_config.py +2 -3
  99. nautobot/core/tests/test_api.py +290 -21
  100. nautobot/core/tests/test_checks.py +0 -7
  101. nautobot/core/tests/test_filters.py +107 -59
  102. nautobot/core/tests/test_forms.py +26 -92
  103. nautobot/core/tests/test_graphql.py +110 -77
  104. nautobot/core/tests/test_logging.py +4 -0
  105. nautobot/core/tests/test_managers.py +3 -1
  106. nautobot/core/tests/test_models.py +2 -0
  107. nautobot/core/tests/test_paginator.py +3 -1
  108. nautobot/core/tests/test_releases.py +12 -12
  109. nautobot/core/tests/test_templatetags_helpers.py +4 -4
  110. nautobot/core/tests/test_utils.py +32 -68
  111. nautobot/core/tests/test_views.py +12 -15
  112. nautobot/core/utils/data.py +17 -0
  113. nautobot/core/utils/deprecation.py +9 -6
  114. nautobot/core/utils/filtering.py +8 -3
  115. nautobot/core/utils/git.py +12 -4
  116. nautobot/core/utils/lookup.py +3 -1
  117. nautobot/core/utils/requests.py +1 -104
  118. nautobot/core/views/__init__.py +1 -0
  119. nautobot/core/views/generic.py +75 -110
  120. nautobot/core/views/mixins.py +52 -61
  121. nautobot/core/views/renderers.py +6 -7
  122. nautobot/core/views/utils.py +80 -0
  123. nautobot/dcim/api/serializers.py +160 -667
  124. nautobot/dcim/api/urls.py +1 -1
  125. nautobot/dcim/api/views.py +7 -44
  126. nautobot/dcim/choices.py +2 -0
  127. nautobot/dcim/filters/__init__.py +21 -0
  128. nautobot/dcim/form_mixins.py +1 -27
  129. nautobot/dcim/forms.py +19 -765
  130. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
  131. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
  132. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
  133. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
  134. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  135. nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
  136. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
  137. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  138. nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
  139. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  140. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  141. nautobot/dcim/models/cables.py +3 -33
  142. nautobot/dcim/models/device_component_templates.py +6 -0
  143. nautobot/dcim/models/device_components.py +12 -198
  144. nautobot/dcim/models/devices.py +30 -143
  145. nautobot/dcim/models/locations.py +3 -64
  146. nautobot/dcim/models/power.py +3 -50
  147. nautobot/dcim/models/racks.py +7 -84
  148. nautobot/dcim/navigation.py +141 -467
  149. nautobot/dcim/signals.py +0 -2
  150. nautobot/dcim/tables/locations.py +2 -2
  151. nautobot/dcim/tables/power.py +1 -2
  152. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  153. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  154. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  155. nautobot/dcim/templates/dcim/location.html +16 -1
  156. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  157. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  158. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  159. nautobot/dcim/tests/test_api.py +166 -81
  160. nautobot/dcim/tests/test_cablepaths.py +41 -35
  161. nautobot/dcim/tests/test_filters.py +67 -23
  162. nautobot/dcim/tests/test_forms.py +5 -205
  163. nautobot/dcim/tests/test_graphql.py +7 -2
  164. nautobot/dcim/tests/test_migrations.py +6 -11
  165. nautobot/dcim/tests/test_models.py +182 -110
  166. nautobot/dcim/tests/test_natural_ordering.py +11 -8
  167. nautobot/dcim/tests/test_signals.py +6 -3
  168. nautobot/dcim/tests/test_views.py +197 -175
  169. nautobot/dcim/urls.py +11 -16
  170. nautobot/dcim/views.py +7 -134
  171. nautobot/docs/additional-features/caching.md +6 -87
  172. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  173. nautobot/docs/additional-features/jobs.md +177 -195
  174. nautobot/docs/administration/nautobot-server.md +6 -21
  175. nautobot/docs/administration/replicating-nautobot.md +0 -10
  176. nautobot/docs/configuration/optional-settings.md +32 -41
  177. nautobot/docs/configuration/required-settings.md +11 -52
  178. nautobot/docs/development/application-registry.md +2 -13
  179. nautobot/docs/development/extending-models.md +15 -17
  180. nautobot/docs/development/generic-views.md +0 -2
  181. nautobot/docs/development/getting-started.md +55 -5
  182. nautobot/docs/development/navigation-menu.md +22 -93
  183. nautobot/docs/development/react-ui.md +105 -0
  184. nautobot/docs/development/role-internals.md +1 -3
  185. nautobot/docs/development/style-guide.md +6 -4
  186. nautobot/docs/index.md +3 -2
  187. nautobot/docs/installation/migrating-from-netbox.md +11 -42
  188. nautobot/docs/installation/nautobot.md +1 -1
  189. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  190. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  191. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  192. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  193. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  194. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  195. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  196. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  197. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  198. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  199. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  200. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  201. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  202. nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
  203. nautobot/docs/models/dcim/device.md +3 -0
  204. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  205. nautobot/docs/models/extras/computedfield.md +4 -4
  206. nautobot/docs/models/extras/gitrepository.md +3 -0
  207. nautobot/docs/models/extras/job.md +1 -0
  208. nautobot/docs/models/extras/jobbutton.md +18 -13
  209. nautobot/docs/models/extras/jobhook.md +7 -4
  210. nautobot/docs/models/extras/jobresult.md +6 -2
  211. nautobot/docs/models/extras/relationship.md +2 -2
  212. nautobot/docs/models/extras/status.md +6 -19
  213. nautobot/docs/models/ipam/ipaddress.md +3 -0
  214. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  215. nautobot/docs/plugins/development.md +83 -21
  216. nautobot/docs/release-notes/version-1.5.md +53 -0
  217. nautobot/docs/release-notes/version-2.0.md +180 -0
  218. nautobot/docs/requirements.txt +1 -0
  219. nautobot/docs/rest-api/overview.md +384 -215
  220. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  221. nautobot/extras/admin.py +3 -5
  222. nautobot/extras/api/customfields.py +15 -39
  223. nautobot/extras/api/fields.py +0 -11
  224. nautobot/extras/api/mixins.py +45 -0
  225. nautobot/extras/api/relationships.py +63 -158
  226. nautobot/extras/api/serializers.py +165 -700
  227. nautobot/extras/api/urls.py +1 -1
  228. nautobot/extras/api/views.py +294 -280
  229. nautobot/extras/apps.py +4 -7
  230. nautobot/extras/choices.py +11 -9
  231. nautobot/extras/constants.py +9 -3
  232. nautobot/extras/datasources/__init__.py +2 -0
  233. nautobot/extras/datasources/git.py +135 -186
  234. nautobot/extras/datasources/registry.py +25 -35
  235. nautobot/extras/filters/__init__.py +20 -19
  236. nautobot/extras/filters/mixins.py +4 -4
  237. nautobot/extras/forms/forms.py +63 -127
  238. nautobot/extras/forms/mixins.py +23 -51
  239. nautobot/extras/health_checks.py +0 -33
  240. nautobot/extras/jobs.py +387 -565
  241. nautobot/extras/management/commands/runjob.py +24 -62
  242. nautobot/extras/managers.py +30 -7
  243. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  244. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
  245. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
  246. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
  247. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
  248. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
  249. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
  250. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  251. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
  252. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
  253. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
  254. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
  255. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  256. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
  257. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  258. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
  259. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
  260. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  261. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  262. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  263. nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
  264. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  265. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  266. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  267. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  268. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  269. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  270. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  271. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  272. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  273. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  274. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  275. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  276. nautobot/extras/models/__init__.py +2 -3
  277. nautobot/extras/models/change_logging.py +0 -36
  278. nautobot/extras/models/customfields.py +39 -33
  279. nautobot/extras/models/datasources.py +48 -50
  280. nautobot/extras/models/groups.py +5 -6
  281. nautobot/extras/models/jobs.py +189 -321
  282. nautobot/extras/models/mixins.py +0 -71
  283. nautobot/extras/models/models.py +0 -19
  284. nautobot/extras/models/relationships.py +19 -13
  285. nautobot/extras/models/roles.py +0 -34
  286. nautobot/extras/models/secrets.py +2 -26
  287. nautobot/extras/models/statuses.py +6 -5
  288. nautobot/extras/models/tags.py +2 -17
  289. nautobot/extras/navigation.py +89 -307
  290. nautobot/extras/plugins/__init__.py +3 -120
  291. nautobot/extras/plugins/utils.py +0 -3
  292. nautobot/extras/plugins/validators.py +5 -4
  293. nautobot/extras/plugins/views.py +16 -3
  294. nautobot/extras/querysets.py +1 -7
  295. nautobot/extras/registry.py +3 -0
  296. nautobot/extras/signals.py +26 -60
  297. nautobot/extras/tables.py +34 -40
  298. nautobot/extras/tasks.py +0 -12
  299. nautobot/extras/templates/extras/configcontext.html +1 -1
  300. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  301. nautobot/extras/templates/extras/customfield.html +0 -13
  302. nautobot/extras/templates/extras/gitrepository.html +3 -3
  303. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  304. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  305. nautobot/extras/templates/extras/job.html +35 -25
  306. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  307. nautobot/extras/templates/extras/job_detail.html +13 -31
  308. nautobot/extras/templates/extras/job_edit.html +15 -17
  309. nautobot/extras/templates/extras/jobresult.html +24 -6
  310. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  311. nautobot/extras/templates/extras/secret.html +28 -0
  312. nautobot/extras/templatetags/job_buttons.py +1 -0
  313. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  314. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  315. nautobot/extras/test_jobs/dry_run.py +29 -0
  316. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  317. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  318. nautobot/extras/test_jobs/fail.py +23 -0
  319. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  320. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  321. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  322. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  323. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  324. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  325. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  326. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  327. nautobot/extras/test_jobs/job_variables.py +88 -0
  328. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  329. nautobot/extras/test_jobs/log_redaction.py +20 -0
  330. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  331. nautobot/extras/test_jobs/modify_db.py +25 -0
  332. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  333. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  334. nautobot/extras/test_jobs/object_var_required.py +21 -0
  335. nautobot/extras/test_jobs/object_vars.py +26 -0
  336. nautobot/extras/test_jobs/pass.py +25 -0
  337. nautobot/extras/test_jobs/profiling.py +32 -0
  338. nautobot/extras/test_jobs/read_only_job.py +15 -0
  339. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  340. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  341. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  342. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  343. nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
  344. nautobot/extras/tests/integration/test_customfields.py +4 -2
  345. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  346. nautobot/extras/tests/integration/test_jobs.py +25 -27
  347. nautobot/extras/tests/integration/test_notes.py +8 -4
  348. nautobot/extras/tests/integration/test_relationships.py +2 -2
  349. nautobot/extras/tests/test_api.py +649 -642
  350. nautobot/extras/tests/test_changelog.py +3 -3
  351. nautobot/extras/tests/test_context_managers.py +5 -3
  352. nautobot/extras/tests/test_customfields.py +92 -50
  353. nautobot/extras/tests/test_datasources.py +189 -112
  354. nautobot/extras/tests/test_dynamicgroups.py +7 -8
  355. nautobot/extras/tests/test_filters.py +137 -89
  356. nautobot/extras/tests/test_forms.py +73 -75
  357. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  358. nautobot/extras/tests/test_jobs.py +262 -263
  359. nautobot/extras/tests/test_migrations.py +4 -3
  360. nautobot/extras/tests/test_models.py +116 -161
  361. nautobot/extras/tests/test_plugins.py +38 -60
  362. nautobot/extras/tests/test_relationships.py +167 -120
  363. nautobot/extras/tests/test_tags.py +6 -11
  364. nautobot/extras/tests/test_utils.py +31 -1
  365. nautobot/extras/tests/test_views.py +201 -145
  366. nautobot/extras/tests/test_webhooks.py +6 -2
  367. nautobot/extras/urls.py +42 -42
  368. nautobot/extras/utils.py +137 -163
  369. nautobot/extras/views.py +78 -152
  370. nautobot/ipam/api/fields.py +17 -0
  371. nautobot/ipam/api/serializers.py +58 -164
  372. nautobot/ipam/api/urls.py +1 -1
  373. nautobot/ipam/api/views.py +3 -2
  374. nautobot/ipam/apps.py +1 -2
  375. nautobot/ipam/filters.py +1 -10
  376. nautobot/ipam/forms.py +4 -177
  377. nautobot/ipam/lookups.py +1 -0
  378. nautobot/ipam/management/commands/__init__.py +0 -0
  379. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  380. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
  381. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
  382. nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
  383. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
  384. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  385. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  386. nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
  387. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  388. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  389. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  390. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  391. nautobot/ipam/models.py +100 -236
  392. nautobot/ipam/navigation.py +36 -181
  393. nautobot/ipam/querysets.py +20 -25
  394. nautobot/ipam/signals.py +49 -6
  395. nautobot/ipam/tables.py +10 -3
  396. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  397. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  398. nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
  399. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  400. nautobot/ipam/templates/ipam/prefix.html +1 -1
  401. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  402. nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
  403. nautobot/ipam/tests/integration/test_prefixes.py +3 -26
  404. nautobot/ipam/tests/test_api.py +22 -19
  405. nautobot/ipam/tests/test_filters.py +59 -23
  406. nautobot/ipam/tests/test_migrations.py +6 -10
  407. nautobot/ipam/tests/test_models.py +323 -198
  408. nautobot/ipam/tests/test_ordering.py +2 -2
  409. nautobot/ipam/tests/test_querysets.py +44 -24
  410. nautobot/ipam/tests/test_views.py +73 -26
  411. nautobot/ipam/urls.py +16 -0
  412. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  413. nautobot/ipam/utils/migrations.py +713 -0
  414. nautobot/ipam/views.py +137 -20
  415. nautobot/project-static/docs/404.html +1178 -10
  416. nautobot/project-static/docs/additional-features/caching.html +1224 -159
  417. nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
  418. nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
  419. nautobot/project-static/docs/additional-features/graphql.html +1179 -11
  420. nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
  421. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
  422. nautobot/project-static/docs/additional-features/jobs.html +1514 -328
  423. nautobot/project-static/docs/additional-features/napalm.html +1180 -12
  424. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
  425. nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
  426. nautobot/project-static/docs/administration/celery-queues.html +1178 -10
  427. nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
  428. nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
  429. nautobot/project-static/docs/administration/permissions.html +1178 -10
  430. nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
  431. nautobot/project-static/docs/apps/index.html +1178 -10
  432. nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
  433. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
  434. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
  435. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
  436. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
  437. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
  438. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
  439. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
  440. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
  441. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
  442. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
  443. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
  444. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
  445. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
  446. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
  447. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
  448. nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
  449. nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
  450. nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
  451. nautobot/project-static/docs/configuration/index.html +1178 -10
  452. nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
  453. nautobot/project-static/docs/configuration/required-settings.html +1312 -211
  454. nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
  455. nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
  456. nautobot/project-static/docs/core-functionality/devices.html +1182 -10
  457. nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
  458. nautobot/project-static/docs/core-functionality/power.html +1178 -10
  459. nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
  460. nautobot/project-static/docs/core-functionality/services.html +1178 -10
  461. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
  462. nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
  463. nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
  464. nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
  465. nautobot/project-static/docs/development/application-registry.html +1190 -42
  466. nautobot/project-static/docs/development/best-practices.html +1178 -10
  467. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
  468. nautobot/project-static/docs/development/extending-models.html +1238 -83
  469. nautobot/project-static/docs/development/generic-views.html +1180 -14
  470. nautobot/project-static/docs/development/getting-started.html +1365 -90
  471. nautobot/project-static/docs/development/homepage.html +1178 -10
  472. nautobot/project-static/docs/development/index.html +1178 -10
  473. nautobot/project-static/docs/development/model-features.html +1178 -10
  474. nautobot/project-static/docs/development/natural-keys.html +1178 -10
  475. nautobot/project-static/docs/development/navigation-menu.html +1215 -125
  476. nautobot/project-static/docs/development/react-ui.html +4199 -0
  477. nautobot/project-static/docs/development/release-checklist.html +1178 -10
  478. nautobot/project-static/docs/development/role-internals.html +1179 -12
  479. nautobot/project-static/docs/development/style-guide.html +1188 -19
  480. nautobot/project-static/docs/development/templates.html +1178 -10
  481. nautobot/project-static/docs/development/testing.html +1178 -10
  482. nautobot/project-static/docs/development/user-preferences.html +1178 -10
  483. nautobot/project-static/docs/docker/index.html +1178 -10
  484. nautobot/project-static/docs/index.html +1183 -12
  485. nautobot/project-static/docs/installation/centos.html +1178 -10
  486. nautobot/project-static/docs/installation/external-authentication.html +1178 -10
  487. nautobot/project-static/docs/installation/http-server.html +1178 -10
  488. nautobot/project-static/docs/installation/index.html +1178 -10
  489. nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
  490. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
  491. nautobot/project-static/docs/installation/nautobot.html +1179 -11
  492. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
  493. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
  494. nautobot/project-static/docs/installation/services.html +1178 -10
  495. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  496. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  497. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  498. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  499. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  500. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  501. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  502. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  503. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  504. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  505. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  506. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  507. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  508. nautobot/project-static/docs/installation/ubuntu.html +1178 -10
  509. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
  510. nautobot/project-static/docs/installation/upgrading.html +1178 -10
  511. nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
  512. nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
  513. nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
  514. nautobot/project-static/docs/models/circuits/provider.html +1293 -103
  515. nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
  516. nautobot/project-static/docs/models/dcim/cable.html +1324 -103
  517. nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
  518. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
  519. nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
  520. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
  521. nautobot/project-static/docs/models/dcim/device.html +1326 -132
  522. nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
  523. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
  524. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
  525. nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
  526. nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
  527. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
  528. nautobot/project-static/docs/models/dcim/interface.html +1293 -103
  529. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
  530. nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
  531. nautobot/project-static/docs/models/dcim/location.html +1293 -103
  532. nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
  533. nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
  534. nautobot/project-static/docs/models/dcim/platform.html +1272 -82
  535. nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
  536. nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
  537. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
  538. nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
  539. nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
  540. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
  541. nautobot/project-static/docs/models/dcim/rack.html +1272 -82
  542. nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
  543. nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
  544. nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
  545. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
  546. nautobot/project-static/docs/models/dcim/region.html +1178 -10
  547. nautobot/project-static/docs/models/dcim/site.html +1178 -10
  548. nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
  549. nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
  550. nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
  551. nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
  552. nautobot/project-static/docs/models/extras/customfield.html +1180 -12
  553. nautobot/project-static/docs/models/extras/customlink.html +1180 -12
  554. nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
  555. nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
  556. nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
  557. nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
  558. nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
  559. nautobot/project-static/docs/models/extras/job.html +1277 -86
  560. nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
  561. nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
  562. nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
  563. nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
  564. nautobot/project-static/docs/models/extras/note.html +1180 -12
  565. nautobot/project-static/docs/models/extras/relationship.html +1182 -14
  566. nautobot/project-static/docs/models/extras/role.html +1320 -86
  567. nautobot/project-static/docs/models/extras/secret.html +1314 -86
  568. nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
  569. nautobot/project-static/docs/models/extras/status.html +1188 -59
  570. nautobot/project-static/docs/models/extras/tag.html +1180 -12
  571. nautobot/project-static/docs/models/extras/webhook.html +1180 -12
  572. nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
  573. nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
  574. nautobot/project-static/docs/models/ipam/rir.html +1276 -86
  575. nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
  576. nautobot/project-static/docs/models/ipam/service.html +1276 -86
  577. nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
  578. nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
  579. nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
  580. nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
  581. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
  582. nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
  583. nautobot/project-static/docs/models/users/token.html +1276 -86
  584. nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
  585. nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
  586. nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
  587. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
  588. nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
  589. nautobot/project-static/docs/objects.inv +0 -0
  590. nautobot/project-static/docs/plugins/development.html +1726 -495
  591. nautobot/project-static/docs/plugins/index.html +1178 -10
  592. nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
  593. nautobot/project-static/docs/release-notes/index.html +1178 -10
  594. nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
  595. nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
  596. nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
  597. nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
  598. nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
  599. nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
  600. nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
  601. nautobot/project-static/docs/requirements.txt +1 -0
  602. nautobot/project-static/docs/rest-api/authentication.html +1179 -11
  603. nautobot/project-static/docs/rest-api/filtering.html +1178 -10
  604. nautobot/project-static/docs/rest-api/overview.html +1841 -446
  605. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  606. nautobot/project-static/docs/search/search_index.json +1 -1
  607. nautobot/project-static/docs/sitemap.xml +197 -187
  608. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  609. nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
  610. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
  611. nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
  612. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
  613. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
  614. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
  615. nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
  616. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
  617. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
  618. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
  619. nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
  620. nautobot/project-static/docs/user-guides/graphql.html +1178 -10
  621. nautobot/project-static/docs/user-guides/relationships.html +1178 -10
  622. nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
  623. nautobot/project-static/js/forms.js +16 -9
  624. nautobot/project-static/js/theme.js +5 -0
  625. nautobot/tenancy/api/serializers.py +4 -32
  626. nautobot/tenancy/api/urls.py +1 -1
  627. nautobot/tenancy/forms.py +0 -28
  628. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  629. nautobot/tenancy/models.py +0 -25
  630. nautobot/tenancy/navigation.py +6 -39
  631. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  632. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  633. nautobot/tenancy/tests/test_api.py +1 -3
  634. nautobot/tenancy/tests/test_filters.py +10 -5
  635. nautobot/tenancy/views.py +0 -2
  636. nautobot/ui/.eslintignore +6 -0
  637. nautobot/ui/.gitignore +10 -0
  638. nautobot/ui/.prettierignore +9 -0
  639. nautobot/ui/.prettierrc +4 -0
  640. nautobot/ui/README.md +33 -0
  641. nautobot/ui/app_imports.js.j2 +7 -0
  642. nautobot/ui/craco.config.js +46 -0
  643. nautobot/ui/jsconfig-base.json +11 -0
  644. nautobot/ui/jsconfig.json +5 -0
  645. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  646. nautobot/ui/package-lock.json +21451 -0
  647. nautobot/ui/package.json +70 -0
  648. nautobot/ui/public/index.html +47 -0
  649. nautobot/ui/public/logo192.png +0 -0
  650. nautobot/ui/public/logo512.png +0 -0
  651. nautobot/ui/public/manifest.json +25 -0
  652. nautobot/ui/public/nautobot_logo.svg +131 -0
  653. nautobot/ui/public/robots.txt +3 -0
  654. nautobot/ui/src/App.js +71 -0
  655. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  656. nautobot/ui/src/components/AppTab.js +40 -0
  657. nautobot/ui/src/components/Apps.js +60 -0
  658. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  659. nautobot/ui/src/components/HomePanel.js +58 -0
  660. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  661. nautobot/ui/src/components/Layout.js +53 -0
  662. nautobot/ui/src/components/LoadingWidget.js +25 -0
  663. nautobot/ui/src/components/Navbar.js +116 -0
  664. nautobot/ui/src/components/NotificationPopover.js +27 -0
  665. nautobot/ui/src/components/ObjectListTable.js +209 -0
  666. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  667. nautobot/ui/src/components/RouterButton.js +10 -0
  668. nautobot/ui/src/components/RouterLink.js +10 -0
  669. nautobot/ui/src/components/SidebarNav.js +147 -0
  670. nautobot/ui/src/components/Table.js +48 -0
  671. nautobot/ui/src/components/TableItem.js +71 -0
  672. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  673. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  674. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  675. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  676. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  677. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  678. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  679. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  680. nautobot/ui/src/components/pagination.js +93 -0
  681. nautobot/ui/src/components/paginator.js +79 -0
  682. nautobot/ui/src/components/paginator_form.js +43 -0
  683. nautobot/ui/src/components/usePagination.js +57 -0
  684. nautobot/ui/src/constants/apiPath.js +10 -0
  685. nautobot/ui/src/constants/icons.js +15 -0
  686. nautobot/ui/src/constants/size.js +15 -0
  687. nautobot/ui/src/index.js +65 -0
  688. nautobot/ui/src/reportWebVitals.js +15 -0
  689. nautobot/ui/src/router.js +77 -0
  690. nautobot/ui/src/utils/api.js +131 -0
  691. nautobot/ui/src/utils/app-import.js +15 -0
  692. nautobot/ui/src/utils/color.js +15 -0
  693. nautobot/ui/src/utils/date.js +14 -0
  694. nautobot/ui/src/utils/index.js +15 -0
  695. nautobot/ui/src/utils/navigation.js +32 -0
  696. nautobot/ui/src/utils/session.js +64 -0
  697. nautobot/ui/src/utils/store.js +242 -0
  698. nautobot/ui/src/utils/string.js +6 -0
  699. nautobot/ui/src/utils/url.js +4 -0
  700. nautobot/ui/src/views/Home.js +138 -0
  701. nautobot/ui/src/views/InstalledApps.js +80 -0
  702. nautobot/ui/src/views/Login.js +48 -0
  703. nautobot/ui/src/views/Logout.js +20 -0
  704. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  705. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  706. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  707. nautobot/ui/src/views/generic/GenericView.js +142 -0
  708. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  709. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  710. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  711. nautobot/users/admin.py +1 -1
  712. nautobot/users/api/serializers.py +51 -61
  713. nautobot/users/api/urls.py +1 -1
  714. nautobot/users/api/views.py +53 -2
  715. nautobot/users/tests/test_api.py +110 -25
  716. nautobot/virtualization/api/serializers.py +18 -130
  717. nautobot/virtualization/api/urls.py +1 -1
  718. nautobot/virtualization/api/views.py +1 -22
  719. nautobot/virtualization/forms.py +13 -99
  720. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
  721. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
  722. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
  723. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
  724. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  725. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  726. nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
  727. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  728. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  729. nautobot/virtualization/models.py +31 -123
  730. nautobot/virtualization/navigation.py +18 -99
  731. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
  732. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  733. nautobot/virtualization/tests/test_api.py +25 -26
  734. nautobot/virtualization/tests/test_filters.py +41 -15
  735. nautobot/virtualization/tests/test_models.py +31 -7
  736. nautobot/virtualization/tests/test_views.py +42 -25
  737. nautobot/virtualization/views.py +7 -6
  738. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
  739. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
  740. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  741. nautobot/circuits/api/nested_serializers.py +0 -69
  742. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  743. nautobot/dcim/api/nested_serializers.py +0 -356
  744. nautobot/dcim/templates/dcim/device_import.html +0 -5
  745. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  746. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  747. nautobot/extras/api/nested_serializers.py +0 -353
  748. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
  749. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
  750. nautobot/extras/reports.py +0 -60
  751. nautobot/extras/scripts.py +0 -72
  752. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  753. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  754. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  755. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  756. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  757. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  758. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  759. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  760. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  761. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
  762. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  763. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  764. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  765. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  766. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  767. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  768. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  769. nautobot/ipam/api/nested_serializers.py +0 -159
  770. nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
  771. nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
  772. nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
  773. nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
  774. nautobot/tenancy/api/nested_serializers.py +0 -31
  775. nautobot/users/api/nested_serializers.py +0 -67
  776. nautobot/virtualization/api/nested_serializers.py +0 -65
  777. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  778. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  779. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  780. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -82,10 +82,17 @@ class GraphQLTestCase(TestCase):
82
82
  GraphQLQuery.objects.create(name="GQL 1", query="{ query: locations {name} }")
83
83
  GraphQLQuery.objects.create(name="GQL 2", query="query ($name: [String!]) { locations(name:$name) {name} }")
84
84
  self.location_type = LocationType.objects.get(name="Campus")
85
+ location_status = Status.objects.get_for_model(Location).first()
85
86
  self.locations = (
86
- Location.objects.create(name="Location-1", slug="location-1", location_type=self.location_type),
87
- Location.objects.create(name="Location-2", slug="location-2", location_type=self.location_type),
88
- Location.objects.create(name="Location-3", slug="location-3", location_type=self.location_type),
87
+ Location.objects.create(
88
+ name="Location-1", slug="location-1", location_type=self.location_type, status=location_status
89
+ ),
90
+ Location.objects.create(
91
+ name="Location-2", slug="location-2", location_type=self.location_type, status=location_status
92
+ ),
93
+ Location.objects.create(
94
+ name="Location-3", slug="location-3", location_type=self.location_type, status=location_status
95
+ ),
89
96
  )
90
97
 
91
98
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
@@ -228,7 +235,6 @@ class GraphQLExtendSchemaType(TestCase):
228
235
  self.assertIsInstance(getattr(schema, "resolve_mode"), types.FunctionType)
229
236
 
230
237
 
231
- @skip("Something really funky is broken here. Setup fails due to content types not existing...")
232
238
  class GraphQLExtendSchemaRelationship(TestCase):
233
239
  def setUp(self):
234
240
  location_ct = ContentType.objects.get_for_model(Location)
@@ -236,8 +242,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
236
242
  vlan_ct = ContentType.objects.get_for_model(VLAN)
237
243
 
238
244
  self.m2m_1 = Relationship(
239
- name="Vlan to Rack",
240
- slug="vlan-rack",
245
+ label="Vlan to Rack",
246
+ key="vlan_rack",
241
247
  source_type=rack_ct,
242
248
  source_label="My Vlans",
243
249
  destination_type=vlan_ct,
@@ -247,8 +253,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
247
253
  self.m2m_1.validated_save()
248
254
 
249
255
  self.m2m_2 = Relationship(
250
- name="Another Vlan to Rack",
251
- slug="vlan-rack-2",
256
+ label="Another Vlan to Rack",
257
+ key="vlan_rack_2",
252
258
  source_type=rack_ct,
253
259
  destination_type=vlan_ct,
254
260
  type="many-to-many",
@@ -256,8 +262,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
256
262
  self.m2m_2.validated_save()
257
263
 
258
264
  self.o2m_1 = Relationship(
259
- name="generic location to vlan",
260
- slug="location-vlan",
265
+ label="generic location to vlan",
266
+ key="location_vlan",
261
267
  source_type=location_ct,
262
268
  destination_type=vlan_ct,
263
269
  type="one-to-many",
@@ -265,8 +271,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
265
271
  self.o2m_1.validated_save()
266
272
 
267
273
  self.o2o_1 = Relationship(
268
- name="Primary Rack per Location",
269
- slug="primary-rack-location",
274
+ label="Primary Rack per Location",
275
+ key="primary_rack_location",
270
276
  source_type=rack_ct,
271
277
  source_hidden=True,
272
278
  destination_type=location_ct,
@@ -276,8 +282,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
276
282
  self.o2o_1.validated_save()
277
283
 
278
284
  self.o2os_1 = Relationship(
279
- name="Redundant Location",
280
- slug="redundant-location",
285
+ label="Redundant Location",
286
+ key="redundant_location",
281
287
  source_type=location_ct,
282
288
  destination_type=location_ct,
283
289
  type="symmetric-one-to-one",
@@ -285,8 +291,8 @@ class GraphQLExtendSchemaRelationship(TestCase):
285
291
  self.o2os_1.validated_save()
286
292
 
287
293
  self.o2m_same_type_1 = Relationship(
288
- name="Some sort of location hierarchy?",
289
- slug="location-hierarchy",
294
+ label="Some sort of location hierarchy?",
295
+ key="location_hierarchy",
290
296
  source_type=location_ct,
291
297
  destination_type=location_ct,
292
298
  type="one-to-many",
@@ -306,7 +312,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
306
312
  (self.m2m_2, "source"),
307
313
  (self.o2m_1, "source"),
308
314
  ]:
309
- field_name = f"rel_{str_to_var_name(rel.slug)}"
315
+ field_name = f"rel_{str_to_var_name(rel.key)}"
310
316
  self.assertIn(field_name, schema._meta.fields.keys())
311
317
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
312
318
  if rel.has_many(peer_side):
@@ -316,7 +322,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
316
322
 
317
323
  # Relationships not on VLAN
318
324
  for rel in [self.o2o_1, self.o2os_1]:
319
- field_name = f"rel_{str_to_var_name(rel.slug)}"
325
+ field_name = f"rel_{str_to_var_name(rel.key)}"
320
326
  self.assertNotIn(field_name, schema._meta.fields.keys())
321
327
 
322
328
  @override_settings(GRAPHQL_RELATIONSHIP_PREFIX="pr")
@@ -330,7 +336,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
330
336
  (self.o2o_1, "source"),
331
337
  (self.o2os_1, "peer"),
332
338
  ]:
333
- field_name = f"pr_{str_to_var_name(rel.slug)}"
339
+ field_name = f"pr_{str_to_var_name(rel.key)}"
334
340
  self.assertIn(field_name, schema._meta.fields.keys())
335
341
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
336
342
  if rel.has_many(peer_side):
@@ -341,7 +347,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
341
347
  # Special handling of same-type non-symmetric relationships
342
348
  for rel in [self.o2m_same_type_1]:
343
349
  for peer_side in ["source", "destination"]:
344
- field_name = f"pr_{str_to_var_name(rel.slug)}_{peer_side}"
350
+ field_name = f"pr_{str_to_var_name(rel.key)}_{peer_side}"
345
351
  self.assertIn(field_name, schema._meta.fields.keys())
346
352
  self.assertIsInstance(schema._meta.fields[field_name], graphene.types.field.Field)
347
353
  if rel.has_many(peer_side):
@@ -351,7 +357,7 @@ class GraphQLExtendSchemaRelationship(TestCase):
351
357
 
352
358
  # Relationships not on Location
353
359
  for rel in [self.m2m_1, self.m2m_2]:
354
- field_name = f"pr_{str_to_var_name(rel.slug)}"
360
+ field_name = f"pr_{str_to_var_name(rel.key)}"
355
361
  self.assertNotIn(field_name, schema._meta.fields.keys())
356
362
 
357
363
 
@@ -375,37 +381,43 @@ class GraphQLSearchParameters(TestCase):
375
381
  class GraphQLAPIPermissionTest(TestCase):
376
382
  client_class = NautobotTestClient
377
383
 
378
- def setUp(self):
384
+ @classmethod
385
+ def setUpTestData(cls):
379
386
  """Initialize the Database with some datas and multiple users associated with different permissions."""
380
- self.groups = (
387
+ cls.groups = (
381
388
  Group.objects.create(name="Group 1"),
382
389
  Group.objects.create(name="Group 2"),
383
390
  )
384
391
 
385
- self.users = (
392
+ cls.users = (
386
393
  User.objects.create(username="User 1", is_active=True),
387
394
  User.objects.create(username="User 2", is_active=True),
388
395
  User.objects.create(username="Super User", is_active=True, is_superuser=True),
389
396
  User.objects.create(username="Nobody", is_active=True),
390
397
  )
391
398
 
392
- self.tokens = (
393
- Token.objects.create(user=self.users[0], key="0123456789abcdef0123456789abcdef01234567"),
394
- Token.objects.create(user=self.users[1], key="abcd456789abcdef0123456789abcdef01234567"),
395
- Token.objects.create(user=self.users[2], key="efgh456789abcdef0123456789abcdef01234567"),
396
- Token.objects.create(user=self.users[3], key="ijkl456789abcdef0123456789abcdef01234567"),
399
+ cls.tokens = (
400
+ Token.objects.create(user=cls.users[0], key="0123456789abcdef0123456789abcdef01234567"),
401
+ Token.objects.create(user=cls.users[1], key="abcd456789abcdef0123456789abcdef01234567"),
402
+ Token.objects.create(user=cls.users[2], key="efgh456789abcdef0123456789abcdef01234567"),
403
+ Token.objects.create(user=cls.users[3], key="ijkl456789abcdef0123456789abcdef01234567"),
397
404
  )
398
405
 
399
- self.clients = [self.client_class(), self.client_class(), self.client_class(), self.client_class()]
400
- self.clients[0].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[0].key}")
401
- self.clients[1].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[1].key}")
402
- self.clients[2].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[2].key}")
403
- self.clients[3].credentials(HTTP_AUTHORIZATION=f"Token {self.tokens[3].key}")
406
+ cls.clients = [cls.client_class(), cls.client_class(), cls.client_class(), cls.client_class()]
407
+ cls.clients[0].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[0].key}")
408
+ cls.clients[1].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[1].key}")
409
+ cls.clients[2].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[2].key}")
410
+ cls.clients[3].credentials(HTTP_AUTHORIZATION=f"Token {cls.tokens[3].key}")
404
411
 
405
- self.location_type = LocationType.objects.get(name="Campus")
406
- self.locations = (
407
- Location.objects.create(name="Location 1", slug="test1", location_type=self.location_type),
408
- Location.objects.create(name="Location 2", slug="test2", location_type=self.location_type),
412
+ cls.location_type = LocationType.objects.get(name="Campus")
413
+ location_status = Status.objects.get_for_model(Location).first()
414
+ cls.locations = (
415
+ Location.objects.create(
416
+ name="Location 1", slug="test1", location_type=cls.location_type, status=location_status
417
+ ),
418
+ Location.objects.create(
419
+ name="Location 2", slug="test2", location_type=cls.location_type, status=location_status
420
+ ),
409
421
  )
410
422
 
411
423
  location_object_type = ContentType.objects.get(app_label="dcim", model="location")
@@ -420,8 +432,8 @@ class GraphQLAPIPermissionTest(TestCase):
420
432
  constraints={"location__slug": f"test{i+1}"},
421
433
  )
422
434
  rack_obj_permission.object_types.add(rack_object_type)
423
- rack_obj_permission.groups.add(self.groups[i])
424
- rack_obj_permission.users.add(self.users[i])
435
+ rack_obj_permission.groups.add(cls.groups[i])
436
+ rack_obj_permission.users.add(cls.users[i])
425
437
 
426
438
  location_obj_permission = ObjectPermission.objects.create(
427
439
  name=f"Permission Location {i+1}",
@@ -429,21 +441,22 @@ class GraphQLAPIPermissionTest(TestCase):
429
441
  constraints={"slug": f"test{i+1}"},
430
442
  )
431
443
  location_obj_permission.object_types.add(location_object_type)
432
- location_obj_permission.groups.add(self.groups[i])
433
- location_obj_permission.users.add(self.users[i])
444
+ location_obj_permission.groups.add(cls.groups[i])
445
+ location_obj_permission.users.add(cls.users[i])
434
446
 
435
- self.rack_grp1 = (
436
- Rack.objects.create(name="Rack 1-1", location=self.locations[0]),
437
- Rack.objects.create(name="Rack 1-2", location=self.locations[0]),
447
+ rack_status = Status.objects.get_for_model(Rack).first()
448
+ cls.rack_grp1 = (
449
+ Rack.objects.create(name="Rack 1-1", location=cls.locations[0], status=rack_status),
450
+ Rack.objects.create(name="Rack 1-2", location=cls.locations[0], status=rack_status),
438
451
  )
439
- self.rack_grp2 = (
440
- Rack.objects.create(name="Rack 2-1", location=self.locations[1]),
441
- Rack.objects.create(name="Rack 2-2", location=self.locations[1]),
452
+ cls.rack_grp2 = (
453
+ Rack.objects.create(name="Rack 2-1", location=cls.locations[1], status=rack_status),
454
+ Rack.objects.create(name="Rack 2-2", location=cls.locations[1], status=rack_status),
442
455
  )
443
456
 
444
- self.api_url = reverse("graphql-api")
457
+ cls.api_url = reverse("graphql-api")
445
458
 
446
- self.get_racks_query = """
459
+ cls.get_racks_query = """
447
460
  query {
448
461
  racks {
449
462
  name
@@ -451,7 +464,7 @@ class GraphQLAPIPermissionTest(TestCase):
451
464
  }
452
465
  """
453
466
 
454
- self.get_racks_params_query = """
467
+ cls.get_racks_params_query = """
455
468
  query {
456
469
  racks(location: "test1") {
457
470
  name
@@ -459,7 +472,7 @@ class GraphQLAPIPermissionTest(TestCase):
459
472
  }
460
473
  """
461
474
 
462
- self.get_racks_var_query = """
475
+ cls.get_racks_var_query = """
463
476
  query ($location: [String]) {
464
477
  racks(location: $location) {
465
478
  name
@@ -467,7 +480,7 @@ class GraphQLAPIPermissionTest(TestCase):
467
480
  }
468
481
  """
469
482
 
470
- self.get_locations_racks_query = """
483
+ cls.get_locations_racks_query = """
471
484
  query {
472
485
  locations {
473
486
  name
@@ -478,7 +491,7 @@ class GraphQLAPIPermissionTest(TestCase):
478
491
  }
479
492
  """
480
493
 
481
- self.get_rack_query = """
494
+ cls.get_rack_query = """
482
495
  query ($id: ID!) {
483
496
  rack (id: $id) {
484
497
  name
@@ -641,13 +654,15 @@ class GraphQLQueryTest(TestCase):
641
654
  cls.location2.status = cls.location_statuses[1]
642
655
  cls.location1.validated_save()
643
656
  cls.location2.validated_save()
644
- cls.rack1 = Rack.objects.create(name="Rack 1", location=cls.location1)
645
- cls.rack2 = Rack.objects.create(name="Rack 2", location=cls.location2)
657
+ rack_statuses = Status.objects.get_for_model(Rack)
658
+ cls.rack1 = Rack.objects.create(name="Rack 1", location=cls.location1, status=rack_statuses[0])
659
+ cls.rack2 = Rack.objects.create(name="Rack 2", location=cls.location2, status=rack_statuses[1])
646
660
  cls.tenant1 = Tenant.objects.create(name="Tenant 1")
647
661
  cls.tenant2 = Tenant.objects.create(name="Tenant 2")
648
662
 
649
- cls.vlan1 = VLAN.objects.create(name="VLAN 1", vid=100, location=cls.location1)
650
- cls.vlan2 = VLAN.objects.create(name="VLAN 2", vid=200, location=cls.location2)
663
+ vlan_statuses = Status.objects.get_for_model(VLAN)
664
+ cls.vlan1 = VLAN.objects.create(name="VLAN 1", vid=100, location=cls.location1, status=vlan_statuses[0])
665
+ cls.vlan2 = VLAN.objects.create(name="VLAN 2", vid=200, location=cls.location2, status=vlan_statuses[1])
651
666
 
652
667
  cls.location1_power_panels = [
653
668
  PowerPanel.objects.create(name="location1-powerpanel1", location=cls.location1),
@@ -758,6 +773,7 @@ class GraphQLQueryTest(TestCase):
758
773
  ),
759
774
  ]
760
775
 
776
+ interface_status = Status.objects.get_for_model(Interface).first()
761
777
  cls.interface11 = Interface.objects.create(
762
778
  name="Int1",
763
779
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
@@ -765,15 +781,20 @@ class GraphQLQueryTest(TestCase):
765
781
  mac_address="00:11:11:11:11:11",
766
782
  mode=InterfaceModeChoices.MODE_ACCESS,
767
783
  untagged_vlan=cls.vlan1,
784
+ status=interface_status,
768
785
  )
769
786
  cls.interface12 = Interface.objects.create(
770
787
  name="Int2",
771
788
  type=InterfaceTypeChoices.TYPE_VIRTUAL,
772
789
  device=cls.device1,
790
+ status=interface_status,
773
791
  )
774
792
  cls.ip_statuses = list(Status.objects.get_for_model(IPAddress))[:2]
793
+ cls.prefix_statuses = list(Status.objects.get_for_model(Prefix))[:2]
775
794
  cls.namespace = Namespace.objects.first()
776
- cls.prefix1 = Prefix.objects.create(prefix="10.0.1.0/24", namespace=cls.namespace)
795
+ cls.prefix1 = Prefix.objects.create(
796
+ prefix="10.0.1.0/24", namespace=cls.namespace, status=cls.prefix_statuses[0]
797
+ )
777
798
  cls.ipaddr1 = IPAddress.objects.create(
778
799
  address="10.0.1.1/24", namespace=cls.namespace, status=cls.ip_statuses[0]
779
800
  )
@@ -796,11 +817,18 @@ class GraphQLQueryTest(TestCase):
796
817
  device=cls.device2,
797
818
  untagged_vlan=cls.vlan2,
798
819
  mode=InterfaceModeChoices.MODE_ACCESS,
820
+ status=interface_status,
799
821
  )
800
822
  cls.interface22 = Interface.objects.create(
801
- name="Int2", type=InterfaceTypeChoices.TYPE_1GE_FIXED, device=cls.device2, mac_address="00:12:12:12:12:12"
823
+ name="Int2",
824
+ type=InterfaceTypeChoices.TYPE_1GE_FIXED,
825
+ device=cls.device2,
826
+ mac_address="00:12:12:12:12:12",
827
+ status=interface_status,
828
+ )
829
+ cls.prefix2 = Prefix.objects.create(
830
+ prefix="10.0.2.0/24", namespace=cls.namespace, status=cls.prefix_statuses[1]
802
831
  )
803
- cls.prefix2 = Prefix.objects.create(prefix="10.0.2.0/24", namespace=cls.namespace)
804
832
  cls.ipaddr2 = IPAddress.objects.create(
805
833
  address="10.0.2.1/30", namespace=cls.namespace, status=cls.ip_statuses[1]
806
834
  )
@@ -815,7 +843,7 @@ class GraphQLQueryTest(TestCase):
815
843
  )
816
844
 
817
845
  cls.interface31 = Interface.objects.create(
818
- name="Int1", type=InterfaceTypeChoices.TYPE_VIRTUAL, device=cls.device3
846
+ name="Int1", type=InterfaceTypeChoices.TYPE_VIRTUAL, device=cls.device3, status=interface_status
819
847
  )
820
848
  cls.interface31 = Interface.objects.create(
821
849
  name="Mgmt1",
@@ -823,6 +851,7 @@ class GraphQLQueryTest(TestCase):
823
851
  device=cls.device3,
824
852
  mgmt_only=True,
825
853
  enabled=False,
854
+ status=interface_status,
826
855
  )
827
856
 
828
857
  cable_statuses = Status.objects.get_for_model(Cable)
@@ -866,59 +895,63 @@ class GraphQLQueryTest(TestCase):
866
895
  cluster=cluster,
867
896
  status=Status.objects.get_for_model(VirtualMachine)[0],
868
897
  )
898
+ vmintf_status = Status.objects.get_for_model(VMInterface).first()
869
899
  cls.vminterface = VMInterface.objects.create(
870
900
  virtual_machine=cls.virtualmachine,
871
901
  name="eth0",
902
+ status=vmintf_status,
903
+ )
904
+ cls.vmprefix = Prefix.objects.create(
905
+ prefix="1.1.1.0/24", namespace=cls.namespace, status=cls.prefix_statuses[0]
872
906
  )
873
- cls.vmprefix = Prefix.objects.create(prefix="1.1.1.0/24", namespace=cls.namespace)
874
907
  cls.vmipaddr = IPAddress.objects.create(
875
908
  address="1.1.1.1/32", namespace=cls.namespace, status=cls.ip_statuses[0]
876
909
  )
877
910
  cls.vminterface.add_ip_addresses(cls.vmipaddr)
878
911
 
879
912
  cls.relationship_o2o_1 = Relationship(
880
- name="Device to VirtualMachine",
881
- slug="device-to-vm",
913
+ label="Device to VirtualMachine",
914
+ key="device_to_vm",
882
915
  source_type=ContentType.objects.get_for_model(Device),
883
916
  destination_type=ContentType.objects.get_for_model(VirtualMachine),
884
917
  type="one-to-one",
885
918
  )
886
- # cls.relationship_o2o_1.validated_save()
919
+ cls.relationship_o2o_1.validated_save()
887
920
 
888
921
  cls.ro2o_assoc_1 = RelationshipAssociation(
889
922
  relationship=cls.relationship_o2o_1,
890
923
  source=cls.device1,
891
924
  destination=cls.virtualmachine,
892
925
  )
893
- # cls.ro2o_assoc_1.validated_save()
926
+ cls.ro2o_assoc_1.validated_save()
894
927
 
895
928
  cls.relationship_m2ms_1 = Relationship(
896
- name="Device Group",
897
- slug="device-group",
929
+ label="Device Group",
930
+ key="device_group",
898
931
  source_type=ContentType.objects.get_for_model(Device),
899
932
  destination_type=ContentType.objects.get_for_model(Device),
900
933
  type="symmetric-many-to-many",
901
934
  )
902
- # cls.relationship_m2ms_1.validated_save()
935
+ cls.relationship_m2ms_1.validated_save()
903
936
 
904
937
  cls.rm2ms_assoc_1 = RelationshipAssociation(
905
938
  relationship=cls.relationship_m2ms_1,
906
939
  source=cls.device1,
907
940
  destination=cls.device2,
908
941
  )
909
- # cls.rm2ms_assoc_1.validated_save()
942
+ cls.rm2ms_assoc_1.validated_save()
910
943
  cls.rm2ms_assoc_2 = RelationshipAssociation(
911
944
  relationship=cls.relationship_m2ms_1,
912
945
  source=cls.device2,
913
946
  destination=cls.device3,
914
947
  )
915
- # cls.rm2ms_assoc_2.validated_save()
948
+ cls.rm2ms_assoc_2.validated_save()
916
949
  cls.rm2ms_assoc_3 = RelationshipAssociation(
917
950
  relationship=cls.relationship_m2ms_1,
918
951
  source=cls.device3,
919
952
  destination=cls.device1,
920
953
  )
921
- # cls.rm2ms_assoc_3.validated_save()
954
+ cls.rm2ms_assoc_3.validated_save()
922
955
 
923
956
  cls.backend = get_default_backend()
924
957
  cls.schema = graphene_settings.SCHEMA
@@ -1352,19 +1385,19 @@ query {
1352
1385
  ),
1353
1386
  (
1354
1387
  "mask_length: 24",
1355
- IPAddress.objects.filter(prefix_length=24).count(),
1388
+ IPAddress.objects.filter(mask_length=24).count(),
1356
1389
  ),
1357
1390
  (
1358
1391
  "mask_length: 30",
1359
- IPAddress.objects.filter(prefix_length=30).count(),
1392
+ IPAddress.objects.filter(mask_length=30).count(),
1360
1393
  ),
1361
1394
  (
1362
1395
  "mask_length: 32",
1363
- IPAddress.objects.filter(prefix_length=32).count(),
1396
+ IPAddress.objects.filter(mask_length=32).count(),
1364
1397
  ),
1365
1398
  (
1366
1399
  "mask_length: 28",
1367
- IPAddress.objects.filter(prefix_length=28).count(),
1400
+ IPAddress.objects.filter(mask_length=28).count(),
1368
1401
  ),
1369
1402
  (
1370
1403
  'parent: "10.0.0.0/16"',
@@ -17,6 +17,10 @@ class LoggingUtilitiesTest(testing.TestCase):
17
17
  "I use username FOO and password BAR to log in as https://FOO:BAR@example.com",
18
18
  "I use username (redacted) and password (redacted) to log in as https://(redacted)@example.com",
19
19
  ),
20
+ ("Password is1234", "Password (redacted)"),
21
+ ("Password: is1234", "Password: (redacted)"),
22
+ ("Password is: is1234", "Password is: (redacted)"),
23
+ ("Password is is1234", "Password is (redacted)"),
20
24
  )
21
25
 
22
26
  def test_sanitize_default_coverage(self):
@@ -1,6 +1,7 @@
1
1
  from django.test import TestCase
2
2
 
3
3
  from nautobot.dcim import models
4
+ from nautobot.extras import models as extras_models
4
5
 
5
6
 
6
7
  class NaturalOrderByManagerTest(TestCase):
@@ -15,7 +16,8 @@ class NaturalOrderByManagerTest(TestCase):
15
16
  # Create the Racks
16
17
  location_type = models.LocationType.objects.get(name="Campus")
17
18
  location = models.Location.objects.filter(location_type=location_type).first()
18
- models.Rack.objects.bulk_create(models.Rack(name=name, location=location) for name in names)
19
+ status = extras_models.Status.objects.get_for_model(models.Rack).first()
20
+ models.Rack.objects.bulk_create(models.Rack(name=name, location=location, status=status) for name in names)
19
21
  # Validate forward ordering
20
22
  self.assertEqual(names, list(models.Rack.objects.filter(name__in=names).values_list("name", flat=True)))
21
23
 
@@ -1,4 +1,5 @@
1
1
  from django.core.exceptions import ValidationError
2
+ from django.test.utils import isolate_apps
2
3
 
3
4
  from nautobot.core.models import BaseModel
4
5
  from nautobot.core.models.utils import construct_natural_key_slug, deconstruct_natural_key_slug
@@ -6,6 +7,7 @@ from nautobot.core.testing import TestCase
6
7
  from nautobot.dcim.models import DeviceType, Manufacturer
7
8
 
8
9
 
10
+ @isolate_apps("nautobot.core.tests")
9
11
  class BaseModelTest(TestCase):
10
12
  class FakeBaseModel(BaseModel):
11
13
  def clean(self):
@@ -9,6 +9,7 @@ from django.urls import reverse
9
9
  from nautobot.core import testing
10
10
  from nautobot.core.views import paginator
11
11
  from nautobot.dcim import models
12
+ from nautobot.extras import models as extras_models
12
13
 
13
14
 
14
15
  class PaginatorTestCase(testing.TestCase):
@@ -52,8 +53,9 @@ class PaginatorTestCase(testing.TestCase):
52
53
  def test_enforce_max_page_size(self):
53
54
  """Request an object list view and assert that the MAX_PAGE_SIZE setting is enforced"""
54
55
  location_type = models.LocationType.objects.get(name="Campus")
56
+ status = extras_models.Status.objects.get_for_model(models.Location).first()
55
57
  models.Location.objects.bulk_create(
56
- [models.Location(name=f"TestLocation{x}", location_type=location_type) for x in range(20)]
58
+ [models.Location(name=f"TestLocation{x}", location_type=location_type, status=status) for x in range(20)]
57
59
  )
58
60
  url = reverse("dcim:location_list")
59
61
  self.add_permissions("dcim.view_location")
@@ -3,8 +3,8 @@ from logging import ERROR
3
3
  from unittest.mock import Mock, patch
4
4
 
5
5
  import requests
6
- from cacheops import CacheMiss, RedisCache
7
6
  from django.conf import settings
7
+ from django.core.cache import cache
8
8
  from django.test import SimpleTestCase, override_settings
9
9
  from packaging import version
10
10
  from requests import Response
@@ -67,10 +67,10 @@ def unsuccessful_github_response(url, *_args, **_kwargs):
67
67
  )
68
68
  class GetReleasesTestCase(SimpleTestCase):
69
69
  @patch.object(requests, "get")
70
- @patch.object(RedisCache, "set")
71
- @patch.object(RedisCache, "get")
70
+ @patch.object(cache, "set")
71
+ @patch.object(cache, "get")
72
72
  def test_pre_releases(self, mock_cache_get: Mock, mock_cache_set: Mock, mock_request_get: Mock):
73
- mock_cache_get.side_effect = CacheMiss()
73
+ mock_cache_get.return_value = None
74
74
  mock_request_get.side_effect = successful_github_response
75
75
 
76
76
  releases = get_releases(pre_releases=True)
@@ -108,10 +108,10 @@ class GetReleasesTestCase(SimpleTestCase):
108
108
  mock_cache_set.assert_called_once_with("latest_release", (expected_version, expected_url), 160876)
109
109
 
110
110
  @patch.object(requests, "get")
111
- @patch.object(RedisCache, "set")
112
- @patch.object(RedisCache, "get")
111
+ @patch.object(cache, "set")
112
+ @patch.object(cache, "get")
113
113
  def test_no_pre_releases(self, mock_cache_get: Mock, mock_cache_set: Mock, mock_request_get: Mock):
114
- mock_cache_get.side_effect = CacheMiss()
114
+ mock_cache_get.return_value = None
115
115
  mock_request_get.side_effect = successful_github_response
116
116
 
117
117
  releases = get_releases(pre_releases=False)
@@ -145,10 +145,10 @@ class GetReleasesTestCase(SimpleTestCase):
145
145
  mock_cache_set.assert_called_once_with("latest_release", (expected_version, expected_url), 160876)
146
146
 
147
147
  @patch.object(requests, "get")
148
- @patch.object(RedisCache, "set")
149
- @patch.object(RedisCache, "get")
148
+ @patch.object(cache, "set")
149
+ @patch.object(cache, "get")
150
150
  def test_failed_request(self, mock_cache_get: Mock, mock_cache_set: Mock, mock_request_get: Mock):
151
- mock_cache_get.side_effect = CacheMiss()
151
+ mock_cache_get.return_value = None
152
152
  mock_request_get.side_effect = unsuccessful_github_response
153
153
 
154
154
  with self.assertLogs(level=ERROR) as cm:
@@ -175,8 +175,8 @@ class GetReleasesTestCase(SimpleTestCase):
175
175
  mock_cache_set.assert_called_once_with("latest_release_no_retry", "https://localhost/unittest/releases", 900)
176
176
 
177
177
  @patch.object(requests, "get")
178
- @patch.object(RedisCache, "set")
179
- @patch.object(RedisCache, "get")
178
+ @patch.object(cache, "set")
179
+ @patch.object(cache, "get")
180
180
  def test_blocked_retry(self, mock_cache_get: Mock, mock_cache_set: Mock, mock_request_get: Mock):
181
181
  mock_cache_get.return_value = "https://localhost/unittest/releases"
182
182
  mock_request_get.side_effect = successful_github_response
@@ -27,24 +27,24 @@ class NautobotTemplatetagsHelperTest(TestCase):
27
27
  location.description = ""
28
28
  location.save()
29
29
  self.assertEqual(
30
- helpers.hyperlinked_object(location), f'<a href="/dcim/locations/{location.slug}/">{location.name}</a>'
30
+ helpers.hyperlinked_object(location), f'<a href="/dcim/locations/{location.pk}/">{location.name}</a>'
31
31
  )
32
32
  # An object with get_absolute_url and a description gives a titled hyperlink
33
33
  location.description = "An important location"
34
34
  location.save()
35
35
  self.assertEqual(
36
36
  helpers.hyperlinked_object(location),
37
- f'<a href="/dcim/locations/{location.slug}/" title="An important location">{location.name}</a>',
37
+ f'<a href="/dcim/locations/{location.pk}/" title="An important location">{location.name}</a>',
38
38
  )
39
39
  # Optionally you can request a field other than the object's display string
40
40
  self.assertEqual(
41
41
  helpers.hyperlinked_object(location, "slug"),
42
- f'<a href="/dcim/locations/{location.slug}/" title="An important location">{location.slug}</a>',
42
+ f'<a href="/dcim/locations/{location.pk}/" title="An important location">{location.slug}</a>',
43
43
  )
44
44
  # If you request a nonexistent field, it defaults to the string representation
45
45
  self.assertEqual(
46
46
  helpers.hyperlinked_object(location, "foo"),
47
- f'<a href="/dcim/locations/{location.slug}/" title="An important location">{location!s}</a>',
47
+ f'<a href="/dcim/locations/{location.pk}/" title="An important location">{location!s}</a>',
48
48
  )
49
49
 
50
50
  def test_placeholder(self):