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
@@ -2,7 +2,7 @@ import re
2
2
 
3
3
  from django.conf import settings
4
4
  from django.core.exceptions import ValidationError
5
- from django.core.validators import BaseValidator, URLValidator, _lazy_re_compile
5
+ from django.core.validators import BaseValidator, RegexValidator, URLValidator, _lazy_re_compile
6
6
 
7
7
 
8
8
  class EnhancedURLValidator(URLValidator):
@@ -41,12 +41,21 @@ class ExclusionValidator(BaseValidator):
41
41
  return a in b
42
42
 
43
43
 
44
- def validate_regex(value):
44
+ class ValidRegexValidator(RegexValidator):
45
45
  """
46
- Checks that the value is a valid regular expression. (Don't confuse this with RegexValidator, which *uses* a regex
47
- to validate a value.)
46
+ Checks that the value is a valid regular expression.
47
+
48
+ Don't confuse this with `RegexValidator`, which *uses* a regex to validate a value.
48
49
  """
49
- try:
50
- re.compile(value)
51
- except re.error:
52
- raise ValidationError(f"{value} is not a valid regular expression.")
50
+
51
+ message = "%(value)r is not a valid regular expression."
52
+ code = "regex_invalid"
53
+
54
+ def __call__(self, value):
55
+ try:
56
+ return re.compile(value)
57
+ except (re.error, TypeError):
58
+ raise ValidationError(self.message, code=self.code, params={"value": value})
59
+
60
+
61
+ validate_regex = ValidRegexValidator()
nautobot/core/releases.py CHANGED
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
 
3
- from cacheops import CacheMiss, cache
3
+ from django.core.cache import cache
4
4
 
5
5
  from nautobot.core.utils.config import get_settings_or_config
6
6
  from nautobot.core.tasks import get_releases
@@ -18,15 +18,13 @@ def get_latest_release(pre_releases=False):
18
18
  """
19
19
  if get_settings_or_config("RELEASE_CHECK_URL"):
20
20
  logger.debug("Checking for most recent release")
21
- try:
22
- latest_release = cache.get("latest_release")
23
- if latest_release:
24
- logger.debug(f"Found cached release: {latest_release}")
25
- return latest_release
26
- except CacheMiss:
27
- # Get the releases in the background worker, it will fill the cache
28
- logger.info("Initiating background task to retrieve updated releases list")
29
- get_releases.delay(pre_releases=pre_releases)
21
+ latest_release = cache.get("latest_release")
22
+ if latest_release is not None:
23
+ logger.debug(f"Found cached release: {latest_release}")
24
+ return latest_release
25
+ # Get the releases in the background worker, it will fill the cache
26
+ logger.info("Initiating background task to retrieve updated releases list")
27
+ get_releases.delay(pre_releases=pre_releases)
30
28
 
31
29
  else:
32
30
  logger.debug("Skipping release check; RELEASE_CHECK_URL not defined")
nautobot/core/settings.py CHANGED
@@ -13,7 +13,7 @@ from nautobot.core.settings_funcs import is_truthy, parse_redis_connection, Cons
13
13
  # Environment setup
14
14
  #
15
15
 
16
- # This is used for display in the UI.
16
+ # This is used for display in the UI. There are also VERSION_MAJOR and VERSION_MINOR derived from this later.
17
17
  VERSION = __version__
18
18
 
19
19
  # Hostname of the system. This is displayed in the web UI footers along with the
@@ -59,6 +59,9 @@ ALLOWED_URL_SCHEMES = (
59
59
  # Base directory wherein all created files (jobs, git repositories, file uploads, static files) will be stored)
60
60
  NAUTOBOT_ROOT = os.getenv("NAUTOBOT_ROOT", os.path.expanduser("~/.nautobot"))
61
61
 
62
+ # The directory where the Nautobot UI packaging is stored.
63
+ NAUTOBOT_UI_DIR = os.path.join(NAUTOBOT_ROOT, "ui")
64
+
62
65
  # Disable linking of Config Context objects via Dynamic Groups by default. This could cause performance impacts
63
66
  # when a large number of dynamic groups are present
64
67
  CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED = is_truthy(os.getenv("NAUTOBOT_CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED", "False"))
@@ -110,7 +113,7 @@ SOCIAL_AUTH_BACKEND_PREFIX = "social_core.backends"
110
113
  SANITIZER_PATTERNS = [
111
114
  # General removal of username-like and password-like tokens
112
115
  (re.compile(r"(https?://)?\S+\s*@", re.IGNORECASE), r"\1{replacement}@"),
113
- (re.compile(r"(username|password|passwd|pwd)(\s*i?s?\s*:?\s*)?\S+", re.IGNORECASE), r"\1\2{replacement}"),
116
+ (re.compile(r"(username|password|passwd|pwd)((?:\s+is.?|:)?\s+)\S+", re.IGNORECASE), r"\1\2{replacement}"),
114
117
  ]
115
118
 
116
119
  # Storage
@@ -161,11 +164,11 @@ STRICT_FILTERING = is_truthy(os.getenv("NAUTOBOT_STRICT_FILTERING", "True"))
161
164
  #
162
165
 
163
166
  REST_FRAMEWORK_VERSION = VERSION.rsplit(".", 1)[0] # Use major.minor as API version
164
- current_major, current_minor = REST_FRAMEWORK_VERSION.split(".")
167
+ VERSION_MAJOR, VERSION_MINOR = [int(v) for v in REST_FRAMEWORK_VERSION.split(".")]
165
168
  # We support all major.minor API versions from 2.0 to the present latest version.
166
169
  # Similar logic exists in tasks.py, please keep them in sync!
167
- assert current_major == "2", f"REST_FRAMEWORK_ALLOWED_VERSIONS needs to be updated to handle version {current_major}"
168
- REST_FRAMEWORK_ALLOWED_VERSIONS = [f"{current_major}.{minor}" for minor in range(0, int(current_minor) + 1)]
170
+ assert VERSION_MAJOR == 2, f"REST_FRAMEWORK_ALLOWED_VERSIONS needs to be updated to handle version {VERSION_MAJOR}"
171
+ REST_FRAMEWORK_ALLOWED_VERSIONS = [f"{VERSION_MAJOR}.{minor}" for minor in range(0, VERSION_MINOR + 1)]
169
172
 
170
173
  REST_FRAMEWORK = {
171
174
  "ALLOWED_VERSIONS": REST_FRAMEWORK_ALLOWED_VERSIONS,
@@ -173,20 +176,27 @@ REST_FRAMEWORK = {
173
176
  "rest_framework.authentication.SessionAuthentication",
174
177
  "nautobot.core.api.authentication.TokenAuthentication",
175
178
  ),
176
- "DEFAULT_FILTER_BACKENDS": ("nautobot.core.api.filter_backends.NautobotFilterBackend",),
179
+ "DEFAULT_FILTER_BACKENDS": (
180
+ "nautobot.core.api.filter_backends.NautobotFilterBackend",
181
+ "rest_framework.filters.OrderingFilter",
182
+ ),
177
183
  "DEFAULT_METADATA_CLASS": "nautobot.core.api.metadata.NautobotMetadata",
178
184
  "DEFAULT_PAGINATION_CLASS": "nautobot.core.api.pagination.OptionalLimitOffsetPagination",
179
185
  "DEFAULT_PERMISSION_CLASSES": ("nautobot.core.api.authentication.TokenPermissions",),
180
186
  "DEFAULT_RENDERER_CLASSES": (
181
- "rest_framework.renderers.JSONRenderer",
187
+ "nautobot.core.api.renderers.NautobotJSONRenderer",
182
188
  "nautobot.core.api.renderers.FormlessBrowsableAPIRenderer",
189
+ "nautobot.core.api.renderers.NautobotCSVRenderer",
190
+ ),
191
+ "DEFAULT_PARSER_CLASSES": (
192
+ "rest_framework.parsers.JSONParser",
193
+ "nautobot.core.api.parsers.NautobotCSVParser",
183
194
  ),
184
- "DEFAULT_PARSER_CLASSES": ("rest_framework.parsers.JSONParser",),
185
195
  "DEFAULT_SCHEMA_CLASS": "nautobot.core.api.schema.NautobotAutoSchema",
186
- # Version to use if the client doesn't request otherwise.
187
- # This should only change (if at all) with Nautobot major (breaking) releases.
188
- "DEFAULT_VERSION": "2.0",
196
+ # Version to use if the client doesn't request otherwise. Default to current (i.e. latest)
197
+ "DEFAULT_VERSION": REST_FRAMEWORK_VERSION,
189
198
  "DEFAULT_VERSIONING_CLASS": "nautobot.core.api.versioning.NautobotAPIVersioning",
199
+ "ORDERING_PARAM": "sort", # This is not meant to be changed by users, but is used internally by the API
190
200
  "PAGE_SIZE": None,
191
201
  "SCHEMA_COERCE_METHOD_NAMES": {
192
202
  # Default mappings
@@ -266,7 +276,10 @@ DATABASES = {
266
276
  "HOST": os.getenv("NAUTOBOT_DB_HOST", "localhost"),
267
277
  "PORT": os.getenv("NAUTOBOT_DB_PORT", ""),
268
278
  "CONN_MAX_AGE": int(os.getenv("NAUTOBOT_DB_TIMEOUT", "300")),
269
- "ENGINE": os.getenv("NAUTOBOT_DB_ENGINE", "django.db.backends.postgresql"),
279
+ "ENGINE": os.getenv(
280
+ "NAUTOBOT_DB_ENGINE",
281
+ "django_prometheus.db.backends.postgresql" if METRICS_ENABLED else "django.db.backends.postgresql",
282
+ ),
270
283
  }
271
284
  }
272
285
 
@@ -287,13 +300,18 @@ DEBUG = is_truthy(os.getenv("NAUTOBOT_DEBUG", "False"))
287
300
  INTERNAL_IPS = ("127.0.0.1", "::1")
288
301
  FORCE_SCRIPT_NAME = None
289
302
 
290
- TESTING = len(sys.argv) > 1 and sys.argv[1] == "test"
303
+ TESTING = "test" in sys.argv
291
304
 
292
305
  LOG_LEVEL = "DEBUG" if DEBUG else "INFO"
293
306
 
294
307
  if TESTING:
295
- # keep log quiet by default when running unit/integration tests
296
- LOGGING = {}
308
+ # Log to null handler instead of stderr during testing
309
+ LOGGING = {
310
+ "version": 1,
311
+ "disable_existing_loggers": False,
312
+ "handlers": {"console": {"level": "INFO", "class": "logging.NullHandler"}},
313
+ "loggers": {"nautobot": {"handlers": ["console"], "level": "INFO"}},
314
+ }
297
315
  else:
298
316
  LOGGING = {
299
317
  "version": 1,
@@ -350,7 +368,6 @@ INSTALLED_APPS = [
350
368
  "django.contrib.messages",
351
369
  "django.contrib.staticfiles",
352
370
  "django.contrib.humanize",
353
- "cacheops", # v2 TODO(jathan); Remove cacheops.
354
371
  "corsheaders",
355
372
  "django_filters",
356
373
  "django_jinja",
@@ -465,7 +482,10 @@ X_FRAME_OPTIONS = "DENY"
465
482
  # Static files (CSS, JavaScript, Images)
466
483
  STATIC_ROOT = os.path.join(NAUTOBOT_ROOT, "static")
467
484
  STATIC_URL = "static/"
468
- STATICFILES_DIRS = (os.path.join(BASE_DIR, "project-static"),)
485
+ STATICFILES_DIRS = (
486
+ os.path.join(BASE_DIR, "project-static"),
487
+ os.path.join(NAUTOBOT_UI_DIR, "build", "static"),
488
+ )
469
489
 
470
490
  # Media
471
491
  MEDIA_URL = "media/"
@@ -629,31 +649,14 @@ GRAPHQL_COMPUTED_FIELD_PREFIX = "cpf"
629
649
  # Caching
630
650
  #
631
651
 
632
- # v2 TODO(jathan): Remove all cacheops settings.
633
- # The django-cacheops plugin is used to cache querysets. The built-in Django
634
- # caching is not used.
635
- CACHEOPS = {
636
- "auth.user": {"ops": "get", "timeout": 60 * 15},
637
- "auth.*": {"ops": ("fetch", "get")},
638
- "auth.permission": {"ops": "all"},
639
- "circuits.*": {"ops": "all"},
640
- "dcim.*": {"ops": "all"},
641
- "ipam.*": {"ops": "all"},
642
- "extras.*": {"ops": "all"},
643
- "users.*": {"ops": "all"},
644
- "tenancy.*": {"ops": "all"},
645
- "virtualization.*": {"ops": "all"},
646
- }
647
- CACHEOPS_DEGRADE_ON_FAILURE = True
648
- CACHEOPS_ENABLED = is_truthy(os.getenv("NAUTOBOT_CACHEOPS_ENABLED", "False"))
649
- CACHEOPS_REDIS = os.getenv("NAUTOBOT_CACHEOPS_REDIS", parse_redis_connection(redis_database=1))
650
- CACHEOPS_DEFAULTS = {"timeout": int(os.getenv("NAUTOBOT_CACHEOPS_TIMEOUT", "900"))}
651
-
652
652
  # The django-redis cache is used to establish concurrent locks using Redis.
653
653
  CACHES = {
654
654
  "default": {
655
- "BACKEND": "django_redis.cache.RedisCache",
656
- "LOCATION": parse_redis_connection(redis_database=0),
655
+ "BACKEND": os.getenv(
656
+ "NAUTOBOT_CACHES_BACKEND",
657
+ "django_prometheus.cache.backends.redis.RedisCache" if METRICS_ENABLED else "django_redis.cache.RedisCache",
658
+ ),
659
+ "LOCATION": parse_redis_connection(redis_database=1),
657
660
  "TIMEOUT": 300,
658
661
  "OPTIONS": {
659
662
  "CLIENT_CLASS": "django_redis.client.DefaultClient",
@@ -678,15 +681,18 @@ CELERY_RESULT_EXTENDED = True
678
681
  # A value of None or 0 means results will never expire (depending on backend specifications).
679
682
  CELERY_RESULT_EXPIRES = None
680
683
 
681
- # If set to True, result messages will be persistent. This means the messages won’t be lost after a broker restart.
682
- CELERY_RESULT_PERSISTENT = True
683
-
684
684
  # Instruct celery to report the started status of a job, instead of just `pending`, `finished`, or `failed`
685
685
  CELERY_TASK_TRACK_STARTED = True
686
686
 
687
687
  # If enabled, a `task-sent` event will be sent for every task so tasks can be tracked before they’re consumed by a worker.
688
688
  CELERY_TASK_SEND_SENT_EVENT = True
689
689
 
690
+ # If enabled stdout and stderr of running jobs will be redirected to the task logger.
691
+ CELERY_WORKER_REDIRECT_STDOUTS = is_truthy(os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS", "True"))
692
+
693
+ # The log level of log messages generated by redirected job stdout and stderr. Can be one of `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL`.
694
+ CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = os.getenv("NAUTOBOT_CELERY_WORKER_REDIRECT_STDOUTS_LEVEL", "WARNING")
695
+
690
696
  # Send task-related events so that tasks can be monitored using tools like flower. Sets the default value for the workers -E argument.
691
697
  CELERY_WORKER_SEND_TASK_EVENTS = True
692
698
 
@@ -783,3 +789,35 @@ def UI_RACK_VIEW_TRUNCATE_FUNCTION(device_display_name):
783
789
  :type: str
784
790
  """
785
791
  return str(device_display_name).split(".")[0]
792
+
793
+
794
+ # Custom JSON schema serializer field type mappingss. These will be added to
795
+ # `NautobotProcessingMixin.TYPE_MAP`.
796
+ # Format: `{serializer_field_class.__name__}` => `{json_schema_type}`
797
+ # See: https://github.com/yoyowallet/drf-react-template-framework#settings
798
+ DRF_REACT_TEMPLATE_TYPE_MAP = {
799
+ "ContentTypeField": {"type": "string", "enum": "choices"},
800
+ "CustomFieldsDataField": {"type": "object", "widget": "textarea"},
801
+ "DateTimeField": {"type": "string", "format": "date-time", "widget": "date-time"},
802
+ "ImageField": {"type": "string", "format": "data-url"},
803
+ "IPFieldSerializer": {"type": "string"},
804
+ "JSONField": {"type": "string", "widget": "textarea"},
805
+ "MultipleChoiceJSONField": {"type": "array", "required": [], "enum": "choices"},
806
+ "ManyRelatedField": {"type": "array", "required": []},
807
+ #
808
+ # Foreign Key fields
809
+ #
810
+ # enum=choices is the one that works in the UI as a related field but it
811
+ # includes ALL related objects in the schema.
812
+ # "NautobotHyperlinkedRelatedField": {"type": "string", "enum": "choices"},
813
+ # readOnly=True disables the fields in the UI; not what we want.
814
+ # "NautobotHyperlinkedRelatedField": {"type": "string", "readOnly": True},
815
+ # type=string results in a free text field; also not what we want. For now,
816
+ # however, this will keep things moving so the unit tests pass.
817
+ "NautobotHyperlinkedRelatedField": {"type": "string", "format": "uuid"},
818
+ "PrimaryKeyRelatedField": {"type": "string", "enum": "choices"},
819
+ "RelationshipsDataField": {"type": "object"},
820
+ "SlugField": {"type": "string"},
821
+ "TimeZoneSerializerField": {"type": "string"},
822
+ "UUIDField": {"type": "string", "format": "uuid"},
823
+ }
nautobot/core/tables.py CHANGED
@@ -37,21 +37,21 @@ class BaseTable(django_tables2.Table):
37
37
  self.base_columns[name] = CustomFieldColumn(cf)
38
38
 
39
39
  for cpf in models.ComputedField.objects.filter(content_type=obj_type):
40
- self.base_columns[f"cpf_{cpf.slug}"] = ComputedFieldColumn(cpf)
40
+ self.base_columns[f"cpf_{cpf.key}"] = ComputedFieldColumn(cpf)
41
41
 
42
42
  for relationship in models.Relationship.objects.filter(source_type=obj_type):
43
43
  if not relationship.symmetric:
44
- self.base_columns[f"cr_{relationship.slug}_src"] = RelationshipColumn(
44
+ self.base_columns[f"cr_{relationship.key}_src"] = RelationshipColumn(
45
45
  relationship, side=choices.RelationshipSideChoices.SIDE_SOURCE
46
46
  )
47
47
  else:
48
- self.base_columns[f"cr_{relationship.slug}_peer"] = RelationshipColumn(
48
+ self.base_columns[f"cr_{relationship.key}_peer"] = RelationshipColumn(
49
49
  relationship, side=choices.RelationshipSideChoices.SIDE_PEER
50
50
  )
51
51
 
52
52
  for relationship in models.Relationship.objects.filter(destination_type=obj_type):
53
53
  if not relationship.symmetric:
54
- self.base_columns[f"cr_{relationship.slug}_dst"] = RelationshipColumn(
54
+ self.base_columns[f"cr_{relationship.key}_dst"] = RelationshipColumn(
55
55
  relationship, side=choices.RelationshipSideChoices.SIDE_DESTINATION
56
56
  )
57
57
  # symmetric relationships are already handled above in the source_type case
@@ -443,7 +443,7 @@ class RelationshipColumn(django_tables2.Column):
443
443
  template += format_html(
444
444
  '<a href="{}?relationship={}&{}_id={}">{} {}</a>',
445
445
  reverse("extras:relationshipassociation_list"),
446
- self.relationship.slug,
446
+ self.relationship.key,
447
447
  self.side,
448
448
  record.id,
449
449
  len(value),
nautobot/core/tasks.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import logging
2
2
 
3
- from cacheops.simple import CacheMiss, cache
4
3
  from django.conf import settings
4
+ from django.core.cache import cache
5
5
  from packaging import version
6
6
  import requests
7
7
 
@@ -21,12 +21,9 @@ def get_releases(pre_releases=False):
21
21
  releases = []
22
22
 
23
23
  # Check whether this URL has failed recently and shouldn't be retried yet
24
- try:
25
- if url == cache.get("latest_release_no_retry"):
26
- logger.info(f"Skipping release check; URL failed recently: {url}")
27
- return []
28
- except CacheMiss:
29
- pass
24
+ if url == cache.get("latest_release_no_retry"):
25
+ logger.info(f"Skipping release check; URL failed recently: {url}")
26
+ return []
30
27
 
31
28
  try:
32
29
  logger.debug(f"Fetching new releases from {url}")
@@ -1,49 +1 @@
1
- {% load static %}
2
- {% load helpers %}
3
- {% load plugins %}
4
-
5
- <!DOCTYPE html>
6
- <html lang="en"{% if request.COOKIES|get_item:"theme" == 'dark' %} data-theme="dark"{% endif %}>
7
- <head>
8
- <title>{% block title %}Home{% endblock %} - {{ settings.BRANDING_TITLE }}</title>
9
- {% include 'inc/media.html' %}
10
- {% block extra_styles %}{% endblock %}
11
- </head>
12
- <body>
13
- {% include 'inc/nav_menu.html' %}
14
- <div class="container-fluid wrapper">
15
- {% if "BANNER_TOP"|settings_or_config %}
16
- <div class="alert alert-info text-center" role="alert">
17
- {{ "BANNER_TOP"|settings_or_config|safe }}
18
- </div>
19
- {% endif %}
20
- {% if settings.MAINTENANCE_MODE %}
21
- <div class="alert alert-warning text-center" role="alert">
22
- <h4><i class="mdi mdi-alert"></i> Maintenance Mode</h4>
23
- <p>Nautobot is currently in maintenance mode. Functionality may be limited.</p>
24
- </div>
25
- {% endif %}
26
- {% plugin_banners %}
27
- {% for message in messages %}
28
- <div class="alert alert-{{ message.tags }} alert-dismissable" role="alert">
29
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
30
- <span>&times;</span>
31
- </button>
32
- {{ message }}
33
- </div>
34
- {% endfor %}
35
- {% block header %}{% endblock header %}
36
- {% block content %}{% endblock content %}
37
- <div class="push"></div>
38
- {% if "BANNER_BOTTOM"|settings_or_config %}
39
- <div class="alert alert-info text-center banner-bottom" role="alert">
40
- {{ "BANNER_BOTTOM"|settings_or_config|safe }}
41
- </div>
42
- {% endif %}
43
- </div>
44
- {% include 'modals/modal_theme.html' with name='theme'%}
45
- {% include 'inc/footer.html' %}
46
- {% include 'inc/javascript.html' %}
47
- {% block javascript %}{% endblock %}
48
- </body>
49
- </html>
1
+ {% extends root_template|default:'base_django.html' %}
@@ -0,0 +1,49 @@
1
+ {% load static %}
2
+ {% load helpers %}
3
+ {% load plugins %}
4
+
5
+ <!DOCTYPE html>
6
+ <html lang="en"{% if request.COOKIES|get_item:"theme" == 'dark' %} data-theme="dark"{% endif %}>
7
+ <head>
8
+ <title>{% block title %}Home{% endblock %} - {{ settings.BRANDING_TITLE }}</title>
9
+ {% include 'inc/media.html' %}
10
+ {% block extra_styles %}{% endblock %}
11
+ </head>
12
+ <body>
13
+ {% include 'inc/nav_menu.html' %}
14
+ <div class="container-fluid wrapper">
15
+ {% if "BANNER_TOP"|settings_or_config %}
16
+ <div class="alert alert-info text-center" role="alert">
17
+ {{ "BANNER_TOP"|settings_or_config|safe }}
18
+ </div>
19
+ {% endif %}
20
+ {% if settings.MAINTENANCE_MODE %}
21
+ <div class="alert alert-warning text-center" role="alert">
22
+ <h4><i class="mdi mdi-alert"></i> Maintenance Mode</h4>
23
+ <p>Nautobot is currently in maintenance mode. Functionality may be limited.</p>
24
+ </div>
25
+ {% endif %}
26
+ {% plugin_banners %}
27
+ {% for message in messages %}
28
+ <div class="alert alert-{{ message.tags }} alert-dismissable" role="alert">
29
+ <button type="button" class="close" data-dismiss="alert" aria-label="Close">
30
+ <span>&times;</span>
31
+ </button>
32
+ {{ message }}
33
+ </div>
34
+ {% endfor %}
35
+ {% block header %}{% endblock header %}
36
+ {% block content %}{% endblock content %}
37
+ <div class="push"></div>
38
+ {% if "BANNER_BOTTOM"|settings_or_config %}
39
+ <div class="alert alert-info text-center banner-bottom" role="alert">
40
+ {{ "BANNER_BOTTOM"|settings_or_config|safe }}
41
+ </div>
42
+ {% endif %}
43
+ </div>
44
+ {% include 'modals/modal_theme.html' with name='theme'%}
45
+ {% include 'inc/footer.html' %}
46
+ {% include 'inc/javascript.html' %}
47
+ {% block javascript %}{% endblock %}
48
+ </body>
49
+ </html>
@@ -0,0 +1,55 @@
1
+ {% load static %}
2
+ {% load helpers %}
3
+ {% load plugins %}
4
+ <!DOCTYPE html>
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="utf-8" />
8
+ <link rel="icon" href="/static/img/favicon.ico" />
9
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
10
+ <meta name="theme-color" content="#000000" />
11
+ <meta
12
+ name="description"
13
+ content="Web site created using create-react-app"
14
+ />
15
+ <link rel="apple-touch-icon" href="/logo192.png" />
16
+ <!--
17
+ manifest.json provides metadata used when your web app is installed on a
18
+ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
19
+ -->
20
+ <link rel="manifest" href="{% static 'asset-manifest.json' %}" />
21
+ <link
22
+ href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap"
23
+ rel="stylesheet"
24
+ />
25
+ <!--
26
+ Notice the use of %PUBLIC_URL% in the tags above.
27
+ It will be replaced with the URL of the `public` folder during the build.
28
+ Only files inside the `public` folder can be referenced from the HTML.
29
+
30
+ Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
31
+ work correctly both with client-side routing and a non-root public URL.
32
+ Learn how to configure a non-root public URL by running `npm run build`.
33
+ -->
34
+ <title>{{ settings.BRANDING_TITLE }}</title>
35
+ <script defer src="{% static 'js/main.js' %}"></script>
36
+ <link href="{% static 'css/main.css' %}" rel="stylesheet">
37
+ </head>
38
+ <body>
39
+ <noscript>You need to enable JavaScript to run this app.</noscript>
40
+ <div id="root"></div>
41
+ <div id="legacy-content" style="display:none">
42
+ {% block content %}{% endblock content %}
43
+ </div>
44
+ <!--
45
+ This HTML file is a template.
46
+ If you open it directly in the browser, you will see an empty page.
47
+
48
+ You can add webfonts, meta tags, or analytics to this file.
49
+ The build step will place the bundled scripts into the <body> tag.
50
+
51
+ To begin the development, run `npm start` or `yarn start`.
52
+ To create a production bundle, use `npm run build` or `yarn build`.
53
+ -->
54
+ </body>
55
+ </html>
@@ -5,15 +5,17 @@
5
5
  Export <span class="caret"></span>
6
6
  </button>
7
7
  <ul class="dropdown-menu dropdown-menu-right">
8
- <li><a href="?{% if url_params %}{{ url_params.urlencode }}&{% endif %}export">Default format</a></li>
8
+ {% if export_url %}
9
+ <li><a href="{{ export_url }}?{% if url_params %}{{ url_params.urlencode }}&{% endif %}format=csv">Default format</a></li>
10
+ {% endif %}
9
11
  <li class="divider"></li>
10
12
  {% for et in export_templates %}
11
13
  <li><a href="?{% if url_params %}{{ url_params.urlencode }}&{% endif %}export={{ et.name }}"{% if et.description %} title="{{ et.description }}"{% endif %}>{{ et.name }}</a></li>
12
14
  {% endfor %}
13
15
  </ul>
14
16
  </div>
15
- {% else %}
16
- <a href="?{% if url_params %}{{ url_params.urlencode }}&{% endif %}export" class="btn btn-success">
17
+ {% elif export_url %}
18
+ <a href="{{ export_url }}?{% if url_params %}{{ url_params.urlencode }}&{% endif %}format=csv" class="btn btn-success">
17
19
  <span class="mdi mdi-database-export" aria-hidden="true"></span> Export
18
20
  </a>
19
- {% endif %}
21
+ {% endif %}
@@ -80,37 +80,29 @@
80
80
  <tr>
81
81
  <th>Field</th>
82
82
  <th>Required</th>
83
- <th>Accessor</th>
84
83
  <th>Description</th>
85
84
  </tr>
86
- {% for name, field in fields.items %}
85
+ {% for field in fields %}
87
86
  <tr>
88
87
  <td>
89
- <code>{{ name }}</code>
88
+ <code>{{ field.name }}</code>
90
89
  </td>
91
90
  <td>{{ field.required | render_boolean }}</td>
92
91
  <td>
93
- {% if field.to_field_name %}
94
- <code>{{ field.to_field_name }}</code>
95
- {% else %}
96
- <span class="text-muted">&mdash;</span>
97
- {% endif %}
98
- </td>
99
- <td>
100
- {% if field.STATIC_CHOICES %}
101
- <button type="button" class="btn btn-link btn-xs pull-right" data-toggle="modal" data-target="#{{ name }}_choices">
92
+ {% if field.choices %}
93
+ <button type="button" class="btn btn-link btn-xs pull-right" data-toggle="modal" data-target="#{{ field.name }}_choices">
102
94
  <i class="mdi mdi-help-circle"></i>
103
95
  </button>
104
- <div class="modal fade" id="{{ name }}_choices" tabindex="-1" role="dialog">
96
+ <div class="modal fade" id="{{ field.name }}_choices" tabindex="-1" role="dialog">
105
97
  <div class="modal-dialog" role="document">
106
98
  <div class="modal-content">
107
99
  <div class="modal-header">
108
100
  <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
109
- <h4 class="modal-title"><code>{{ name }}</code> Choices</h4>
101
+ <h4 class="modal-title"><code>{{ field.name }}</code> Choices</h4>
110
102
  </div>
111
103
  <table class="table table-striped modal-body">
112
104
  <tr><th>Import Value</th><th>Label</th></tr>
113
- {% for value, label in field.choices %}
105
+ {% for value, label in field.choices.items %}
114
106
  {% if value %}<tr><td><samp>{{ value }}</samp></td><td>{{ label }}</td></tr>{% endif %}
115
107
  {% endfor %}
116
108
  </table>
@@ -123,10 +115,8 @@
123
115
  {% elif field.label %}
124
116
  {{ field.label }}<br />
125
117
  {% endif %}
126
- {% if field|widget_type == 'dateinput' %}
127
- <small class="text-muted">Format: YYYY-MM-DD</small>
128
- {% elif field|widget_type == 'checkboxinput' %}
129
- <small class="text-muted">Specify "true" or "false"</small>
118
+ {% if field.format %}
119
+ <small class="text-muted">Format: {{ field.format }}</small>
130
120
  {% endif %}
131
121
  </td>
132
122
  </tr>
@@ -138,8 +128,7 @@
138
128
  objects.
139
129
  </p>
140
130
  <p class="small text-muted">
141
- <i class="mdi mdi-information-outline"></i> Related objects may be referenced by any unique attribute.
142
- For example, <code>vrf.rd</code> would identify a VRF by its route distinguisher.
131
+ <i class="mdi mdi-information-outline"></i> Related objects must be referenced by their natural key slugs. You can find this information in the "Advanced" tab of any object's detail view.
143
132
  </p>
144
133
  {% endif %}
145
134
  </div>
@@ -49,7 +49,9 @@
49
49
  {% import_button content_type.model_class|validated_viewname:"import" %}
50
50
  {% endif %}
51
51
  {% if 'export' in action_buttons %}
52
- {% export_button content_type %}
52
+ {% block export_button %}
53
+ {% export_button content_type %}
54
+ {% endblock export_button %}
53
55
  {% endif %}
54
56
  </div>
55
57
  <h1>{% block title %}{{ title }}{% endblock %}</h1>
@@ -0,0 +1,3 @@
1
+ {% load helpers %}
2
+ {% load plugins %}
3
+ {% plugin_full_width_page object %}
@@ -16,6 +16,7 @@
16
16
  </div>
17
17
  <div class="col-xs-4 text-right noprint">
18
18
  <p class="text-muted">
19
+ <i class="mdi mdi-new-box text-primary"></i> <a href="#" onclick="viewNewUI();">View in New UI</a> &middot;
19
20
  <a href="#theme_modal" data-toggle="modal" data-target="#theme_modal" id="btn-theme-modal"><i class="mdi mdi-theme-light-dark text-primary"></i>Theme</a> &middot;
20
21
  <i class="mdi mdi-book-open-page-variant text-primary"></i>
21
22
  {% if settings.BRANDING_URLS.docs %}
@@ -37,18 +37,4 @@
37
37
  window.addEventListener("resize", setBodyPaddingTop);
38
38
  window.addEventListener("load", setBodyPaddingTop);
39
39
 
40
- /*
41
- Dropdown menu overflow screen view control
42
- */
43
- $(".dropdown .dropdown-toggle").on("click", function(){
44
- var dropdown = $(this).next("ul");
45
- var distanceOfDropDownFromNavStart = $(this).offset().left + dropdown.width();
46
- var navBarWidth = $(".nav.navbar-nav").width();
47
- var isEntirelyVisible = (distanceOfDropDownFromNavStart <= navBarWidth);
48
-
49
- if (!isEntirelyVisible)
50
- dropdown.addClass('edge');
51
- else
52
- dropdown.removeClass('edge');
53
- })
54
40
  </script>