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
@@ -1,14 +1,13 @@
1
- from nautobot.core.apps import NavMenuAddButton, NavMenuGroup, NavMenuItem, NavMenuImportButton, NavMenuTab
1
+ from nautobot.core.apps import NavMenuGroup, NavMenuItem, NavMenuTab
2
2
 
3
3
 
4
4
  menu_items = (
5
5
  NavMenuTab(
6
- name="Circuits",
7
- weight=500,
6
+ name="Inventory",
8
7
  groups=(
9
8
  NavMenuGroup(
10
9
  name="Circuits",
11
- weight=100,
10
+ weight=400,
12
11
  items=(
13
12
  NavMenuItem(
14
13
  link="circuits:circuit_list",
@@ -17,92 +16,38 @@ menu_items = (
17
16
  permissions=[
18
17
  "circuits.view_circuit",
19
18
  ],
20
- buttons=(
21
- NavMenuAddButton(
22
- link="circuits:circuit_add",
23
- permissions=[
24
- "circuits.add_circuit",
25
- ],
26
- ),
27
- NavMenuImportButton(
28
- link="circuits:circuit_import",
29
- permissions=[
30
- "circuits.add_circuit",
31
- ],
32
- ),
33
- ),
19
+ ),
20
+ NavMenuItem(
21
+ link="circuits:circuittermination_list",
22
+ name="Circuit Terminations",
23
+ weight=200,
24
+ permissions=[
25
+ "circuits.view_circuittermination",
26
+ ],
34
27
  ),
35
28
  NavMenuItem(
36
29
  link="circuits:circuittype_list",
37
30
  name="Circuit Types",
38
- weight=200,
31
+ weight=300,
39
32
  permissions=[
40
33
  "circuits.view_circuittype",
41
34
  ],
42
- buttons=(
43
- NavMenuAddButton(
44
- link="circuits:circuittype_add",
45
- permissions=[
46
- "circuits.add_circuittype",
47
- ],
48
- ),
49
- NavMenuImportButton(
50
- link="circuits:circuittype_import",
51
- permissions=[
52
- "circuits.add_circuittype",
53
- ],
54
- ),
55
- ),
56
35
  ),
57
- ),
58
- ),
59
- NavMenuGroup(
60
- name="Providers",
61
- weight=200,
62
- items=(
63
36
  NavMenuItem(
64
37
  link="circuits:provider_list",
65
38
  name="Providers",
66
- weight=100,
39
+ weight=400,
67
40
  permissions=[
68
41
  "circuits.view_provider",
69
42
  ],
70
- buttons=(
71
- NavMenuAddButton(
72
- link="circuits:provider_add",
73
- permissions=[
74
- "circuits.add_provider",
75
- ],
76
- ),
77
- NavMenuImportButton(
78
- link="circuits:provider_import",
79
- permissions=[
80
- "circuits.add_provider",
81
- ],
82
- ),
83
- ),
84
43
  ),
85
44
  NavMenuItem(
86
45
  link="circuits:providernetwork_list",
87
46
  name="Provider Networks",
88
- weight=200,
47
+ weight=500,
89
48
  permissions=[
90
49
  "circuits.view_providernetwork",
91
50
  ],
92
- buttons=(
93
- NavMenuAddButton(
94
- link="circuits:providernetwork_add",
95
- permissions=[
96
- "circuits.add_providernetwork",
97
- ],
98
- ),
99
- NavMenuImportButton(
100
- link="circuits:providernetwork_import",
101
- permissions=[
102
- "circuits.add_providernetwork",
103
- ],
104
- ),
105
- ),
106
51
  ),
107
52
  ),
108
53
  ),
@@ -1,4 +1,3 @@
1
- from cacheops import invalidate_obj
2
1
  from django.contrib.contenttypes.models import ContentType
3
2
  from django.db import transaction
4
3
  from django.db.models import Q
@@ -29,7 +28,6 @@ def rebuild_paths_circuits(obj):
29
28
 
30
29
  with transaction.atomic():
31
30
  for cp in cable_paths:
32
- invalidate_obj(cp.origin)
33
31
  cp.delete()
34
32
  # Prevent looping back to rebuild_paths during the atomic transaction.
35
33
  create_cablepath(cp.origin, rebuild=False)
@@ -9,7 +9,7 @@ from nautobot.core.tables import (
9
9
  )
10
10
  from nautobot.extras.tables import StatusTableMixin
11
11
  from nautobot.tenancy.tables import TenantColumn
12
- from .models import Circuit, CircuitType, Provider, ProviderNetwork
12
+ from .models import Circuit, CircuitTermination, CircuitType, Provider, ProviderNetwork
13
13
 
14
14
  CIRCUIT_TERMINATION_PARENT = """
15
15
  {% load helpers %}
@@ -141,3 +141,41 @@ class CircuitTable(StatusTableMixin, BaseTable):
141
141
  "circuit_termination_z",
142
142
  "description",
143
143
  )
144
+
145
+
146
+ #
147
+ # Circuit Terminations
148
+ #
149
+
150
+
151
+ class CircuitTerminationTable(BaseTable):
152
+ pk = ToggleColumn()
153
+ circuit = tables.Column(linkify=True)
154
+ term_side = tables.Column(linkify=True)
155
+ location = tables.Column(linkify=True)
156
+ provider_network = tables.Column(linkify=True)
157
+ cable = tables.Column(linkify=True)
158
+
159
+ class Meta(BaseTable.Meta):
160
+ model = CircuitTermination
161
+ fields = (
162
+ "pk",
163
+ "circuit",
164
+ "term_side",
165
+ "location",
166
+ "provider_network",
167
+ "cable",
168
+ "port_speed",
169
+ "upstream_speed",
170
+ "xconnect_id",
171
+ "pp_info",
172
+ "description",
173
+ "tags",
174
+ )
175
+ default_columns = (
176
+ "pk",
177
+ "circuit",
178
+ "term_side",
179
+ "location",
180
+ "provider_network",
181
+ )
@@ -57,8 +57,8 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
57
57
  name="Test Power Panel",
58
58
  )
59
59
  m2m = Relationship.objects.create(
60
- name="Termination 2 Provider m2m",
61
- slug="termination-2-provider-m2m",
60
+ label="Termination 2 Provider m2m",
61
+ key="termination_2_provider_m2m",
62
62
  source_type=circuit_termination_ct,
63
63
  destination_type=provider_ct,
64
64
  type=RelationshipTypeChoices.TYPE_MANY_TO_MANY,
@@ -74,8 +74,8 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
74
74
  destination=provider2,
75
75
  )
76
76
  o2m = Relationship.objects.create(
77
- name="Termination 2 Location o2m",
78
- slug="termination-2-provider-o2m",
77
+ label="Termination 2 Location o2m",
78
+ key="termination_2_provider_o2m",
79
79
  source_type=circuit_termination_ct,
80
80
  destination_type=location_ct,
81
81
  type=RelationshipTypeChoices.TYPE_ONE_TO_MANY,
@@ -86,8 +86,8 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
86
86
  destination=location,
87
87
  )
88
88
  o2o = Relationship.objects.create(
89
- name="Termination 2 Power Panel o2o",
90
- slug="termination-2-power-panel-o2o",
89
+ label="Termination 2 Power Panel o2o",
90
+ key="termination_2_power_panel_o2o",
91
91
  source_type=circuit_termination_ct,
92
92
  destination_type=power_panel_ct,
93
93
  type=RelationshipTypeChoices.TYPE_ONE_TO_ONE,
@@ -100,7 +100,7 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
100
100
  # https://github.com/nautobot/nautobot/issues/2077
101
101
  fake_ct = ContentType.objects.create(app_label="nonexistent", model="nonexistentmodel")
102
102
  bad_relation = Relationship.objects.create(
103
- name="Termination 2 Nonexistent",
103
+ label="Termination 2 Nonexistent",
104
104
  source_type=circuit_termination_ct,
105
105
  destination_type=fake_ct,
106
106
  type=RelationshipTypeChoices.TYPE_MANY_TO_MANY,
@@ -122,8 +122,8 @@ class CircuitRelationshipsTestCase(SeleniumTestCase):
122
122
  """
123
123
  self.browser.visit(self.live_server_url)
124
124
 
125
- # Click Circuits dropdown button
126
- self.browser.links.find_by_partial_text("Circuits")[0].click()
125
+ # Click Inventory dropdown button
126
+ self.browser.links.find_by_partial_text("Inventory")[0].click()
127
127
 
128
128
  # Click Circuits link
129
129
  self.browser.links.find_by_partial_text("Circuits")[1].click()
@@ -17,7 +17,6 @@ class AppTest(APITestCase):
17
17
 
18
18
  class ProviderTest(APIViewTestCases.APIViewTestCase):
19
19
  model = Provider
20
- brief_fields = ["circuit_count", "display", "id", "name", "url"]
21
20
  create_data = [
22
21
  {
23
22
  "name": "Provider 4",
@@ -37,7 +36,6 @@ class ProviderTest(APIViewTestCases.APIViewTestCase):
37
36
 
38
37
  class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
39
38
  model = ProviderNetwork
40
- brief_fields = ["display", "id", "name", "slug", "url"]
41
39
 
42
40
  @classmethod
43
41
  def setUpTestData(cls):
@@ -76,7 +74,6 @@ class ProviderNetworkTest(APIViewTestCases.APIViewTestCase):
76
74
 
77
75
  class CircuitTypeTest(APIViewTestCases.APIViewTestCase):
78
76
  model = CircuitType
79
- brief_fields = ["circuit_count", "display", "id", "name", "url"]
80
77
  create_data = (
81
78
  {
82
79
  "name": "Circuit Type 4",
@@ -103,7 +100,6 @@ class CircuitTypeTest(APIViewTestCases.APIViewTestCase):
103
100
 
104
101
  class CircuitTest(APIViewTestCases.APIViewTestCase):
105
102
  model = Circuit
106
- brief_fields = ["cid", "display", "id", "url"]
107
103
 
108
104
  @classmethod
109
105
  def setUpTestData(cls):
@@ -160,7 +156,6 @@ class CircuitTest(APIViewTestCases.APIViewTestCase):
160
156
 
161
157
  class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
162
158
  model = CircuitTermination
163
- brief_fields = ["cable", "circuit", "display", "id", "term_side", "url"]
164
159
  choices_fields = ["term_side"]
165
160
 
166
161
  @classmethod
@@ -175,11 +170,12 @@ class CircuitTerminationTest(APIViewTestCases.APIViewTestCase):
175
170
 
176
171
  provider = Provider.objects.first()
177
172
  circuit_type = CircuitType.objects.first()
173
+ status = Status.objects.get_for_model(Circuit).first()
178
174
 
179
175
  circuits = (
180
- Circuit.objects.create(cid="Circuit 1", provider=provider, circuit_type=circuit_type),
181
- Circuit.objects.create(cid="Circuit 2", provider=provider, circuit_type=circuit_type),
182
- Circuit.objects.create(cid="Circuit 3", provider=provider, circuit_type=circuit_type),
176
+ Circuit.objects.create(cid="Circuit 1", provider=provider, circuit_type=circuit_type, status=status),
177
+ Circuit.objects.create(cid="Circuit 2", provider=provider, circuit_type=circuit_type, status=status),
178
+ Circuit.objects.create(cid="Circuit 3", provider=provider, circuit_type=circuit_type, status=status),
183
179
  )
184
180
 
185
181
  CircuitTermination.objects.create(circuit=circuits[0], location=locations[0], term_side=SIDE_A)
@@ -39,9 +39,14 @@ class ProviderTestCase(FilterTestCases.NameOnlyFilterTestCase):
39
39
  circuit_types = CircuitType.objects.all()[:2]
40
40
  cls.locations = Location.objects.filter(children__isnull=True)[:2]
41
41
 
42
+ status = Status.objects.get_for_model(Circuit).first()
42
43
  circuits = (
43
- Circuit.objects.create(provider=providers[0], circuit_type=circuit_types[0], cid="Test Circuit 1"),
44
- Circuit.objects.create(provider=providers[1], circuit_type=circuit_types[1], cid="Test Circuit 1"),
44
+ Circuit.objects.create(
45
+ provider=providers[0], circuit_type=circuit_types[0], cid="Test Circuit 1", status=status
46
+ ),
47
+ Circuit.objects.create(
48
+ provider=providers[1], circuit_type=circuit_types[1], cid="Test Circuit 1", status=status
49
+ ),
45
50
  )
46
51
 
47
52
  CircuitTermination.objects.create(circuit=circuits[0], location=cls.locations[0], term_side="A")
@@ -150,8 +155,9 @@ class CircuitTerminationTestCase(FilterTestCases.FilterTestCase):
150
155
  status=device_status,
151
156
  location=location,
152
157
  )
153
- interface1 = Interface.objects.create(device=device1, name="eth0")
154
- interface2 = Interface.objects.create(device=device2, name="eth0")
158
+ interface_status = Status.objects.get_for_model(Interface).first()
159
+ interface1 = Interface.objects.create(device=device1, name="eth0", status=interface_status)
160
+ interface2 = Interface.objects.create(device=device2, name="eth0", status=interface_status)
155
161
 
156
162
  circuit_terminations = CircuitTermination.objects.all()
157
163
  circuit_terminations[0].tags.set(Tag.objects.get_for_model(CircuitTermination))
@@ -5,6 +5,7 @@ from nautobot.circuits.choices import CircuitTerminationSideChoices
5
5
  from nautobot.circuits.models import Circuit, CircuitTermination, CircuitType, Provider, ProviderNetwork
6
6
  from nautobot.core.testing.models import ModelTestCases
7
7
  from nautobot.dcim.models import Location, LocationType
8
+ from nautobot.extras.models import Status
8
9
 
9
10
 
10
11
  class CircuitTerminationModelTestCase(ModelTestCases.BaseModelTestCase):
@@ -19,7 +20,10 @@ class CircuitTerminationModelTestCase(ModelTestCases.BaseModelTestCase):
19
20
  location_type_1.content_types.set([])
20
21
  location_type_2 = LocationType.objects.get(name="Building")
21
22
  location_type_2.content_types.add(ContentType.objects.get_for_model(CircuitTermination))
22
- cls.circuit = Circuit.objects.create(cid="Circuit 1", provider=provider, circuit_type=circuit_type)
23
+ status = Status.objects.get_for_model(Circuit).first()
24
+ cls.circuit = Circuit.objects.create(
25
+ cid="Circuit 1", provider=provider, circuit_type=circuit_type, status=status
26
+ )
23
27
  cls.provider_network = ProviderNetwork.objects.create(name="Provider Network 1", provider=provider)
24
28
  cls.location_1 = Location.objects.filter(location_type=location_type_1)[0]
25
29
  cls.location_2 = Location.objects.filter(location_type=location_type_2)[0]
@@ -10,6 +10,7 @@ from nautobot.circuits.models import (
10
10
  ProviderNetwork,
11
11
  )
12
12
  from nautobot.core.testing import post_data, TestCase as NautobotTestCase, ViewTestCases
13
+ from nautobot.dcim.models import Location
13
14
  from nautobot.extras.models import Status, Tag
14
15
 
15
16
 
@@ -170,17 +171,38 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
170
171
  cls.slug_source = "name"
171
172
 
172
173
 
173
- class CircuitTerminationTestCase(NautobotTestCase):
174
- def setUp(self):
175
- super().setUp()
176
- self.user.is_superuser = True
177
- self.user.save()
174
+ class CircuitTerminationTestCase(
175
+ ViewTestCases.GetObjectViewTestCase,
176
+ ViewTestCases.GetObjectChangelogViewTestCase,
177
+ ViewTestCases.GetObjectNotesViewTestCase,
178
+ # create/edit views are special cases, not currently tested
179
+ ViewTestCases.DeleteObjectViewTestCase,
180
+ ViewTestCases.ListObjectsViewTestCase,
181
+ ViewTestCases.BulkImportObjectsViewTestCase,
182
+ # No bulk-edit support currently
183
+ ViewTestCases.BulkDeleteObjectsViewTestCase,
184
+ ):
185
+ model = CircuitTermination
186
+
187
+ @classmethod
188
+ def setUpTestData(cls):
189
+ circuit = Circuit.objects.filter(circuit_terminations__isnull=True).first()
190
+ provider_network = ProviderNetwork.objects.filter(circuit_terminations__isnull=True).first()
191
+ location = Location.objects.get_for_model(CircuitTermination).first()
192
+
193
+ cls.csv_data = (
194
+ "term_side,circuit,location,provider_network,port_speed",
195
+ f"A,{circuit.natural_key_slug},{location.natural_key_slug}",
196
+ f"Z,{circuit.natural_key_slug},,{provider_network.natural_key_slug},1000",
197
+ )
178
198
 
179
199
  def test_circuit_termination_detail_200(self):
180
200
  """
181
201
  This tests that a circuit termination's detail page (with a provider
182
202
  network instead of a site) returns a 200 response and doesn't contain the connect menu button.
183
203
  """
204
+ self.user.is_superuser = True
205
+ self.user.save()
184
206
 
185
207
  # Set up the required objects:
186
208
  provider = Provider.objects.first()
@@ -2,6 +2,7 @@ from django.contrib import messages
2
2
  from django.db import transaction
3
3
  from django.db.models import Q
4
4
  from django.shortcuts import get_object_or_404, redirect, render
5
+ from django.utils.http import is_safe_url
5
6
  from django_tables2 import RequestConfig
6
7
 
7
8
 
@@ -28,13 +29,11 @@ class CircuitTypeUIViewSet(
28
29
  view_mixins.ObjectChangeLogViewMixin,
29
30
  view_mixins.ObjectNotesViewMixin,
30
31
  ):
31
- bulk_create_form_class = forms.CircuitTypeCSVForm
32
32
  filterset_class = filters.CircuitTypeFilterSet
33
33
  form_class = forms.CircuitTypeForm
34
34
  queryset = CircuitType.objects.annotate(circuit_count=count_related(Circuit, "circuit_type"))
35
35
  serializer_class = serializers.CircuitTypeSerializer
36
36
  table_class = tables.CircuitTypeTable
37
- lookup_field = "pk"
38
37
 
39
38
  def get_extra_context(self, request, instance):
40
39
  # Circuits
@@ -61,15 +60,20 @@ class CircuitTypeUIViewSet(
61
60
 
62
61
  class CircuitTerminationUIViewSet(
63
62
  view_mixins.ObjectDetailViewMixin,
63
+ view_mixins.ObjectListViewMixin,
64
64
  view_mixins.ObjectEditViewMixin,
65
65
  view_mixins.ObjectDestroyViewMixin,
66
+ view_mixins.ObjectBulkDestroyViewMixin,
67
+ view_mixins.ObjectBulkCreateViewMixin,
66
68
  view_mixins.ObjectChangeLogViewMixin,
67
69
  view_mixins.ObjectNotesViewMixin,
68
70
  ):
71
+ action_buttons = ("import", "export")
72
+ filterset_class = filters.CircuitTerminationFilterSet
69
73
  form_class = forms.CircuitTerminationForm
70
- lookup_field = "pk"
71
74
  queryset = CircuitTermination.objects.all()
72
75
  serializer_class = serializers.CircuitTerminationSerializer
76
+ table_class = tables.CircuitTerminationTable
73
77
 
74
78
  def get_object(self):
75
79
  obj = super().get_object()
@@ -77,12 +81,20 @@ class CircuitTerminationUIViewSet(
77
81
  obj.circuit = get_object_or_404(Circuit, pk=self.kwargs["circuit"])
78
82
  return obj
79
83
 
80
- def get_return_url(self, request, obj):
81
- return obj.circuit.get_absolute_url()
84
+ def get_return_url(self, request, obj=None):
85
+ # First, see if `return_url` was specified as a query parameter or form data. Use this URL only if it's
86
+ # considered safe.
87
+ query_param = request.GET.get("return_url") or request.POST.get("return_url")
88
+ if query_param and is_safe_url(url=query_param, allowed_hosts=request.get_host()):
89
+ return query_param
90
+
91
+ if obj is not None and obj.present_in_database and obj.pk:
92
+ return obj.circuit.get_absolute_url()
93
+
94
+ return super().get_return_url(request, obj=obj)
82
95
 
83
96
 
84
97
  class ProviderUIViewSet(NautobotUIViewSet):
85
- bulk_create_form_class = forms.ProviderCSVForm
86
98
  bulk_update_form_class = forms.ProviderBulkEditForm
87
99
  filterset_class = filters.ProviderFilterSet
88
100
  filterset_form_class = forms.ProviderFilterForm
@@ -90,7 +102,6 @@ class ProviderUIViewSet(NautobotUIViewSet):
90
102
  queryset = Provider.objects.annotate(count_circuits=count_related(Circuit, "provider"))
91
103
  serializer_class = serializers.ProviderSerializer
92
104
  table_class = tables.ProviderTable
93
- lookup_field = "pk"
94
105
 
95
106
  def get_extra_context(self, request, instance):
96
107
  context = super().get_extra_context(request, instance)
@@ -115,12 +126,10 @@ class ProviderUIViewSet(NautobotUIViewSet):
115
126
 
116
127
 
117
128
  class CircuitUIViewSet(NautobotUIViewSet):
118
- bulk_create_form_class = forms.CircuitCSVForm
119
129
  bulk_update_form_class = forms.CircuitBulkEditForm
120
130
  filterset_class = filters.CircuitFilterSet
121
131
  filterset_form_class = forms.CircuitFilterForm
122
132
  form_class = forms.CircuitForm
123
- lookup_field = "pk"
124
133
  # v2 TODO(jathan): Replace prefetch_related with select_related
125
134
  prefetch_related = ["provider", "circuit_type", "tenant", "circuit_termination_a", "circuit_termination_z"]
126
135
  queryset = Circuit.objects.all()
@@ -169,7 +178,6 @@ class CircuitUIViewSet(NautobotUIViewSet):
169
178
 
170
179
  class ProviderNetworkUIViewSet(NautobotUIViewSet):
171
180
  model = ProviderNetwork
172
- bulk_create_form_class = forms.ProviderNetworkCSVForm
173
181
  bulk_update_form_class = forms.ProviderNetworkBulkEditForm
174
182
  filterset_class = filters.ProviderNetworkFilterSet
175
183
  filterset_form_class = forms.ProviderNetworkFilterForm
@@ -4,10 +4,13 @@ from .fields import (
4
4
  SerializedPKRelatedField,
5
5
  TimeZoneSerializerField,
6
6
  )
7
- from .routers import OrderedDefaultRouter
8
7
  from .serializers import (
9
8
  BaseModelSerializer,
10
9
  BulkOperationSerializer,
10
+ CustomFieldModelSerializerMixin,
11
+ NautobotModelSerializer,
12
+ NotesSerializerMixin,
13
+ RelationshipModelSerializerMixin,
11
14
  TreeModelSerializerMixin,
12
15
  ValidatedModelSerializer,
13
16
  WritableNestedSerializer,
@@ -19,7 +22,10 @@ __all__ = (
19
22
  "BulkOperationSerializer",
20
23
  "ChoiceField",
21
24
  "ContentTypeField",
22
- "OrderedDefaultRouter",
25
+ "CustomFieldModelSerializerMixin",
26
+ "NautobotModelSerializer",
27
+ "NotesSerializerMixin",
28
+ "RelationshipModelSerializerMixin",
23
29
  "SerializedPKRelatedField",
24
30
  "TimeZoneSerializerField",
25
31
  "TreeModelSerializerMixin",
@@ -1,5 +1,4 @@
1
1
  from collections import OrderedDict
2
-
3
2
  from django.core.exceptions import ObjectDoesNotExist
4
3
  from drf_spectacular.utils import extend_schema_field
5
4
  from rest_framework import serializers
@@ -8,6 +7,7 @@ from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
8
7
  from timezone_field.rest_framework import TimeZoneSerializerField as TimeZoneSerializerField_
9
8
 
10
9
 
10
+ # TODO: why is this not a serializers.ChoiceField subclass??
11
11
  class ChoiceField(serializers.Field):
12
12
  """
13
13
  Represent a ChoiceField as {'value': <DB value>, 'label': <string>}. Accepts a single value on write.
@@ -51,9 +51,18 @@ class ChoiceField(serializers.Field):
51
51
  return data
52
52
  raise ValidationError("This field may not be blank.")
53
53
 
54
+ if isinstance(data, dict):
55
+ if "value" in data:
56
+ data = data["value"]
57
+ else:
58
+ raise ValidationError(
59
+ 'Value must be passed directly (e.g. "foo": 123) '
60
+ 'or as a dict with key "value" (e.g. "foo": {"value": 123}).'
61
+ )
62
+
54
63
  # Provide an explicit error message if the request is trying to write a dict or list
55
- if isinstance(data, (dict, list)):
56
- raise ValidationError('Value must be passed directly (e.g. "foo": 123); do not use a dictionary or list.')
64
+ if isinstance(data, list):
65
+ raise ValidationError('Value must be passed directly (e.g. "foo": 123); do not use a list.')
57
66
 
58
67
  # Check for string representations of boolean/integer values
59
68
  if hasattr(data, "lower"):
@@ -110,9 +119,9 @@ class ObjectTypeField(serializers.CharField):
110
119
  Represent the ContentType of this serializer's model as "<app_label>.<model>".
111
120
  """
112
121
 
113
- def __init__(self, *args, read_only=True, **kwargs): # pylint: disable=useless-parent-delegation
122
+ def __init__(self, *args, read_only=True, source="*", **kwargs): # pylint: disable=useless-parent-delegation
114
123
  """Default read_only to True as this should never be a writable field."""
115
- super().__init__(*args, read_only=read_only, **kwargs)
124
+ super().__init__(*args, read_only=read_only, source=source, **kwargs)
116
125
 
117
126
  def to_representation(self, _value):
118
127
  """
@@ -121,7 +130,7 @@ class ObjectTypeField(serializers.CharField):
121
130
  Implemented this way because `_value` may be None when generating the schema.
122
131
  """
123
132
  model = self.parent.Meta.model
124
- return f"{model._meta.app_label}.{model._meta.model_name}"
133
+ return model._meta.label_lower
125
134
 
126
135
 
127
136
  class SerializedPKRelatedField(PrimaryKeyRelatedField):
@@ -17,11 +17,12 @@ class NautobotFilterBackend(DjangoFilterBackend):
17
17
 
18
18
  for non_filter_param in (
19
19
  "api_version", # used to select the Nautobot API version
20
- "brief", # used to select NestedSerializer rather than Serializer
20
+ "depth", # nested levels of the serializers default to depth=0
21
21
  "format", # "json" or "api", used in the interactive HTML REST API views
22
- "include", # used to include computed fields (excluded by default)
22
+ "include", # used to include computed fields, relationships, config-contexts, etc. (excluded by default)
23
23
  "limit", # pagination
24
24
  "offset", # pagination
25
+ "sort", # sorting of results
25
26
  ):
26
27
  data.pop(non_filter_param, None)
27
28