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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. nautobot/apps/choices.py +4 -0
  2. nautobot/apps/ui.py +4 -0
  3. nautobot/apps/utils.py +8 -0
  4. nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
  5. nautobot/circuits/views.py +6 -2
  6. nautobot/core/api/serializers.py +1 -1
  7. nautobot/core/api/urls.py +1 -0
  8. nautobot/core/api/views.py +4 -0
  9. nautobot/core/choices.py +1 -1
  10. nautobot/core/cli/bootstrap_v3_to_v5.py +36 -13
  11. nautobot/core/cli/migrate_deprecated_templates.py +36 -9
  12. nautobot/core/filters.py +4 -0
  13. nautobot/core/forms/__init__.py +2 -0
  14. nautobot/core/forms/widgets.py +21 -2
  15. nautobot/core/jobs/__init__.py +56 -0
  16. nautobot/core/management/commands/generate_test_data.py +3 -3
  17. nautobot/core/models/__init__.py +11 -0
  18. nautobot/core/models/utils.py +1 -1
  19. nautobot/core/settings.py +17 -7
  20. nautobot/core/settings.yaml +4 -26
  21. nautobot/core/templates/admin/base.html +1 -2
  22. nautobot/core/templates/admin/change_list.html +9 -12
  23. nautobot/core/templates/base_django.html +1 -2
  24. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  25. nautobot/core/templates/components/tab/content_wrapper.html +4 -4
  26. nautobot/core/templates/echarts/echarts.html +21 -8
  27. nautobot/core/templates/generic/object_bulk_create.html +2 -2
  28. nautobot/core/templates/generic/object_bulk_delete.html +1 -1
  29. nautobot/core/templates/generic/object_bulk_edit.html +1 -1
  30. nautobot/core/templates/generic/object_bulk_import.html +1 -1
  31. nautobot/core/templates/generic/object_delete.html +1 -1
  32. nautobot/core/templates/generic/object_detail.html +1 -1
  33. nautobot/core/templates/generic/object_edit.html +1 -1
  34. nautobot/core/templates/generic/object_retrieve.html +2 -2
  35. nautobot/core/templates/graphene/graphiql.html +0 -1
  36. nautobot/core/templates/inc/footer.html +3 -1
  37. nautobot/core/templates/inc/header.html +10 -0
  38. nautobot/core/templates/inc/media.html +14 -0
  39. nautobot/core/templates/inc/nav_menu.html +1 -8
  40. nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
  41. nautobot/core/templates/nautobot_config.py.j2 +0 -6
  42. nautobot/core/templates/rest_framework/api.html +103 -2
  43. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +33 -0
  44. nautobot/core/templates/utilities/theme_preview.html +3 -0
  45. nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
  46. nautobot/core/templatetags/helpers.py +24 -12
  47. nautobot/core/testing/integration.py +24 -13
  48. nautobot/core/testing/utils.py +18 -4
  49. nautobot/core/testing/views.py +104 -17
  50. nautobot/core/tests/integration/test_filters.py +48 -11
  51. nautobot/core/tests/integration/test_theme.py +22 -21
  52. nautobot/core/tests/nautobot_config.py +3 -0
  53. nautobot/core/tests/runner.py +1 -2
  54. nautobot/core/tests/test_breadcrumbs.py +21 -21
  55. nautobot/core/tests/test_jobs.py +73 -6
  56. nautobot/core/tests/test_renderers.py +59 -0
  57. nautobot/core/tests/test_settings_schema.py +1 -0
  58. nautobot/core/tests/test_templatetags_helpers.py +9 -0
  59. nautobot/core/tests/test_titles.py +0 -16
  60. nautobot/core/tests/test_ui.py +122 -3
  61. nautobot/core/tests/test_utils.py +41 -1
  62. nautobot/core/ui/breadcrumbs.py +68 -17
  63. nautobot/core/ui/bulk_buttons.py +1 -1
  64. nautobot/core/ui/choices.py +49 -65
  65. nautobot/core/ui/echarts.py +15 -20
  66. nautobot/core/ui/object_detail.py +54 -46
  67. nautobot/core/ui/titles.py +3 -6
  68. nautobot/core/urls.py +8 -8
  69. nautobot/core/utils/filtering.py +11 -1
  70. nautobot/core/utils/lookup.py +46 -0
  71. nautobot/core/views/mixins.py +31 -20
  72. nautobot/core/views/renderers.py +2 -3
  73. nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -2
  74. nautobot/dcim/api/serializers.py +3 -0
  75. nautobot/dcim/choices.py +49 -0
  76. nautobot/dcim/constants.py +7 -0
  77. nautobot/dcim/factory.py +1 -1
  78. nautobot/dcim/filters.py +13 -1
  79. nautobot/dcim/forms.py +89 -3
  80. nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
  81. nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
  82. nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
  83. nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
  84. nautobot/dcim/migrations/{0078_remove_device_location_tenant_name_uniqueness.py → 0079_remove_device_location_tenant_name_uniqueness.py} +1 -1
  85. nautobot/dcim/migrations/{0079_device_name_data_migration.py → 0080_device_name_data_migration.py} +1 -1
  86. nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
  87. nautobot/dcim/models/device_component_templates.py +33 -1
  88. nautobot/dcim/models/device_components.py +22 -1
  89. nautobot/dcim/models/devices.py +17 -4
  90. nautobot/dcim/tables/devices.py +15 -0
  91. nautobot/dcim/tables/devicetypes.py +8 -1
  92. nautobot/dcim/tables/racks.py +0 -2
  93. nautobot/dcim/tables/template_code.py +1 -1
  94. nautobot/dcim/templates/dcim/cable_trace.html +0 -2
  95. nautobot/dcim/templates/dcim/consoleport.html +1 -1
  96. nautobot/dcim/templates/dcim/consoleserverport.html +1 -1
  97. nautobot/dcim/templates/dcim/devicebay.html +1 -1
  98. nautobot/dcim/templates/dcim/frontport.html +1 -1
  99. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  100. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
  101. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  102. nautobot/dcim/templates/dcim/interface.html +9 -1
  103. nautobot/dcim/templates/dcim/interface_edit.html +2 -0
  104. nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
  105. nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
  106. nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
  107. nautobot/dcim/templates/dcim/module_frontports.html +1 -1
  108. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  109. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  110. nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
  111. nautobot/dcim/templates/dcim/module_powerports.html +1 -1
  112. nautobot/dcim/templates/dcim/module_rearports.html +1 -1
  113. nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
  114. nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
  115. nautobot/dcim/templates/dcim/powerport.html +1 -1
  116. nautobot/dcim/templates/dcim/rack_elevation_list.html +1 -1
  117. nautobot/dcim/templates/dcim/rack_retrieve.html +0 -11
  118. nautobot/dcim/templates/dcim/rearport.html +1 -1
  119. nautobot/dcim/templates/dcim/trace/cable.html +1 -1
  120. nautobot/dcim/templates/dcim/virtualchassis_update.html +1 -1
  121. nautobot/dcim/tests/integration/test_controller.py +3 -6
  122. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
  123. nautobot/dcim/tests/integration/test_create_device.py +0 -2
  124. nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
  125. nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
  126. nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
  127. nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
  128. nautobot/dcim/tests/test_api.py +186 -6
  129. nautobot/dcim/tests/test_filters.py +43 -1
  130. nautobot/dcim/tests/test_forms.py +110 -8
  131. nautobot/dcim/tests/test_graphql.py +44 -1
  132. nautobot/dcim/tests/test_models.py +265 -0
  133. nautobot/dcim/tests/test_tables.py +160 -0
  134. nautobot/dcim/tests/test_views.py +69 -7
  135. nautobot/dcim/views.py +232 -126
  136. nautobot/extras/api/views.py +51 -44
  137. nautobot/extras/datasources/git.py +3 -1
  138. nautobot/extras/filters.py +19 -2
  139. nautobot/extras/forms/forms.py +9 -2
  140. nautobot/extras/jobs.py +2 -0
  141. nautobot/extras/jobs_ui.py +4 -3
  142. nautobot/extras/management/__init__.py +2 -0
  143. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
  144. nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
  145. nautobot/extras/models/approvals.py +11 -1
  146. nautobot/extras/models/change_logging.py +4 -0
  147. nautobot/extras/models/jobs.py +1 -3
  148. nautobot/extras/models/models.py +10 -2
  149. nautobot/extras/plugins/marketplace_manifest.yml +49 -1
  150. nautobot/extras/plugins/views.py +0 -5
  151. nautobot/extras/querysets.py +8 -0
  152. nautobot/extras/tables.py +12 -0
  153. nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
  154. nautobot/extras/templates/extras/configcontext_update.html +1 -0
  155. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  156. nautobot/extras/templates/extras/objectchange_retrieve.html +0 -2
  157. nautobot/extras/templates/extras/plugin_detail.html +3 -3
  158. nautobot/extras/templates/extras/secret_create.html +1 -1
  159. nautobot/extras/tests/integration/test_computedfields.py +8 -9
  160. nautobot/extras/tests/integration/test_customfields.py +1 -3
  161. nautobot/extras/tests/integration/test_dynamicgroups.py +7 -8
  162. nautobot/extras/tests/integration/test_relationships.py +0 -2
  163. nautobot/extras/tests/test_api.py +63 -0
  164. nautobot/extras/tests/test_changelog.py +24 -2
  165. nautobot/extras/tests/test_filters.py +36 -3
  166. nautobot/extras/tests/test_models.py +38 -2
  167. nautobot/extras/tests/test_utils.py +3 -4
  168. nautobot/extras/tests/test_views.py +22 -83
  169. nautobot/extras/urls.py +0 -14
  170. nautobot/extras/views.py +83 -52
  171. nautobot/ipam/filters.py +26 -0
  172. nautobot/ipam/tables.py +6 -0
  173. nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
  174. nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
  175. nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
  176. nautobot/ipam/tests/test_filters.py +26 -1
  177. nautobot/ipam/tests/test_models.py +1 -1
  178. nautobot/ipam/views.py +9 -7
  179. nautobot/load_balancers/__init__.py +0 -0
  180. nautobot/load_balancers/api/__init__.py +1 -0
  181. nautobot/load_balancers/api/serializers.py +75 -0
  182. nautobot/load_balancers/api/urls.py +23 -0
  183. nautobot/load_balancers/api/views.py +61 -0
  184. nautobot/load_balancers/apps.py +17 -0
  185. nautobot/load_balancers/choices.py +167 -0
  186. nautobot/load_balancers/filters.py +225 -0
  187. nautobot/load_balancers/forms.py +532 -0
  188. nautobot/load_balancers/management/commands/__init__.py +0 -0
  189. nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
  190. nautobot/load_balancers/migrations/0001_initial.py +465 -0
  191. nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
  192. nautobot/load_balancers/migrations/__init__.py +0 -0
  193. nautobot/load_balancers/models.py +423 -0
  194. nautobot/load_balancers/navigation.py +80 -0
  195. nautobot/load_balancers/tables.py +255 -0
  196. nautobot/load_balancers/tests/__init__.py +474 -0
  197. nautobot/load_balancers/tests/test_api.py +353 -0
  198. nautobot/load_balancers/tests/test_filters.py +134 -0
  199. nautobot/load_balancers/tests/test_forms.py +266 -0
  200. nautobot/load_balancers/tests/test_models.py +195 -0
  201. nautobot/load_balancers/tests/test_views.py +229 -0
  202. nautobot/load_balancers/urls.py +17 -0
  203. nautobot/load_balancers/views.py +248 -0
  204. nautobot/project-static/dist/css/github-dark.min.css +10 -0
  205. nautobot/project-static/dist/css/github.min.css +10 -0
  206. nautobot/project-static/dist/css/nautobot.css +1 -11
  207. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  208. nautobot/project-static/dist/js/libraries.js +1 -1
  209. nautobot/project-static/dist/js/libraries.js.map +1 -1
  210. nautobot/project-static/dist/js/nautobot.js +1 -1
  211. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  212. nautobot/project-static/js/forms.js +13 -0
  213. nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
  214. nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
  215. nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
  216. nautobot/ui/package-lock.json +87 -4
  217. nautobot/ui/package.json +2 -1
  218. nautobot/ui/src/js/nautobot.js +0 -1
  219. nautobot/ui/src/js/select2.js +53 -2
  220. nautobot/ui/src/scss/nautobot.scss +51 -2
  221. nautobot/ui/webpack.config.js +13 -0
  222. nautobot/users/templates/users/preferences.html +11 -2
  223. nautobot/virtualization/filters.py +6 -1
  224. nautobot/virtualization/tests/test_filters.py +10 -1
  225. nautobot/virtualization/tests/test_models.py +1 -0
  226. nautobot/virtualization/views.py +4 -1
  227. nautobot/vpn/factory.py +25 -15
  228. nautobot/vpn/filters.py +1 -0
  229. nautobot/vpn/forms.py +1 -0
  230. nautobot/vpn/migrations/0001_initial.py +1 -1
  231. nautobot/vpn/models.py +16 -8
  232. nautobot/vpn/tables.py +5 -2
  233. nautobot/vpn/tests/test_api.py +0 -5
  234. nautobot/vpn/tests/test_forms.py +1 -2
  235. nautobot/vpn/tests/test_models.py +57 -7
  236. nautobot/vpn/tests/test_views.py +22 -3
  237. nautobot/vpn/views.py +78 -20
  238. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +4 -4
  239. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +243 -352
  240. nautobot/circuits/templates/circuits/circuit.html +0 -2
  241. nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
  242. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
  243. nautobot/circuits/templates/circuits/circuit_update.html +0 -1
  244. nautobot/circuits/templates/circuits/circuittermination.html +0 -2
  245. nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
  246. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
  247. nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
  248. nautobot/circuits/templates/circuits/circuittype.html +0 -2
  249. nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
  250. nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
  251. nautobot/circuits/templates/circuits/provider.html +0 -2
  252. nautobot/circuits/templates/circuits/provider_edit.html +0 -2
  253. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
  254. nautobot/circuits/templates/circuits/provider_update.html +0 -1
  255. nautobot/circuits/templates/circuits/providernetwork.html +0 -2
  256. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
  257. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
  258. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
  259. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
  260. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
  261. nautobot/core/templates/buttons/import.html +0 -9
  262. nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
  263. nautobot/dcim/templates/dcim/cable.html +0 -2
  264. nautobot/dcim/templates/dcim/cable_edit.html +0 -2
  265. nautobot/dcim/templates/dcim/controller/base.html +0 -2
  266. nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
  267. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
  268. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
  269. nautobot/dcim/templates/dcim/device/base.html +0 -2
  270. nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
  271. nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
  272. nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
  273. nautobot/dcim/templates/dcim/device/frontports.html +0 -2
  274. nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
  275. nautobot/dcim/templates/dcim/device/inventory.html +0 -2
  276. nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
  277. nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
  278. nautobot/dcim/templates/dcim/device/powerports.html +0 -2
  279. nautobot/dcim/templates/dcim/device/rearports.html +0 -2
  280. nautobot/dcim/templates/dcim/device/wireless.html +0 -2
  281. nautobot/dcim/templates/dcim/device_component.html +0 -2
  282. nautobot/dcim/templates/dcim/device_edit.html +0 -2
  283. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
  284. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
  285. nautobot/dcim/templates/dcim/devicetype.html +0 -2
  286. nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
  287. nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
  288. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
  289. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
  290. nautobot/dcim/templates/dcim/location.html +0 -2
  291. nautobot/dcim/templates/dcim/location_edit.html +0 -2
  292. nautobot/dcim/templates/dcim/location_retrieve.html +0 -2
  293. nautobot/dcim/templates/dcim/locationtype.html +0 -2
  294. nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
  295. nautobot/dcim/templates/dcim/manufacturer.html +0 -2
  296. nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
  297. nautobot/dcim/templates/dcim/platform.html +0 -2
  298. nautobot/dcim/templates/dcim/powerfeed.html +0 -2
  299. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
  300. nautobot/dcim/templates/dcim/powerpanel.html +0 -2
  301. nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
  302. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
  303. nautobot/dcim/templates/dcim/rack.html +0 -2
  304. nautobot/dcim/templates/dcim/rack_edit.html +0 -2
  305. nautobot/dcim/templates/dcim/rackgroup.html +0 -2
  306. nautobot/dcim/templates/dcim/rackreservation.html +0 -2
  307. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
  308. nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
  309. nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
  310. nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
  311. nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
  312. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
  313. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
  314. nautobot/dcim/ui.py +0 -29
  315. nautobot/extras/templates/extras/computedfield.html +0 -2
  316. nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
  317. nautobot/extras/templates/extras/configcontext.html +0 -2
  318. nautobot/extras/templates/extras/configcontext_edit.html +0 -2
  319. nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
  320. nautobot/extras/templates/extras/configcontextschema.html +0 -2
  321. nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
  322. nautobot/extras/templates/extras/contact_retrieve.html +0 -2
  323. nautobot/extras/templates/extras/customfield.html +0 -2
  324. nautobot/extras/templates/extras/customfield_edit.html +0 -2
  325. nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
  326. nautobot/extras/templates/extras/customlink.html +0 -2
  327. nautobot/extras/templates/extras/dynamicgroup.html +0 -2
  328. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
  329. nautobot/extras/templates/extras/exporttemplate.html +0 -2
  330. nautobot/extras/templates/extras/gitrepository.html +0 -2
  331. nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
  332. nautobot/extras/templates/extras/graphqlquery.html +0 -2
  333. nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
  334. nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -2
  335. nautobot/extras/templates/extras/job_detail.html +0 -2
  336. nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
  337. nautobot/extras/templates/extras/jobhook.html +0 -2
  338. nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
  339. nautobot/extras/templates/extras/jobresult.html +0 -2
  340. nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
  341. nautobot/extras/templates/extras/note.html +0 -2
  342. nautobot/extras/templates/extras/note_retrieve.html +0 -1
  343. nautobot/extras/templates/extras/object_changelog.html +0 -2
  344. nautobot/extras/templates/extras/object_notes.html +0 -2
  345. nautobot/extras/templates/extras/objectchange.html +0 -2
  346. nautobot/extras/templates/extras/objectchange_list.html +0 -3
  347. nautobot/extras/templates/extras/relationship.html +0 -1
  348. nautobot/extras/templates/extras/secret.html +0 -1
  349. nautobot/extras/templates/extras/secret_edit.html +0 -1
  350. nautobot/extras/templates/extras/secretsgroup.html +0 -2
  351. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
  352. nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
  353. nautobot/extras/templates/extras/status.html +0 -2
  354. nautobot/extras/templates/extras/tag.html +0 -2
  355. nautobot/extras/templates/extras/tag_edit.html +0 -2
  356. nautobot/extras/templates/extras/tag_retrieve.html +0 -2
  357. nautobot/extras/templates/extras/team_retrieve.html +0 -2
  358. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
  359. nautobot/ipam/templates/ipam/prefix.html +0 -2
  360. nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
  361. nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
  362. nautobot/ipam/templates/ipam/rir.html +0 -2
  363. nautobot/ipam/templates/ipam/routetarget.html +0 -1
  364. nautobot/ipam/templates/ipam/service.html +0 -2
  365. nautobot/ipam/templates/ipam/service_edit.html +0 -2
  366. nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
  367. nautobot/ipam/templates/ipam/vlan.html +0 -2
  368. nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
  369. nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
  370. nautobot/ipam/templates/ipam/vlangroup.html +0 -2
  371. nautobot/ipam/templates/ipam/vrf.html +0 -1
  372. nautobot/tenancy/templates/tenancy/tenant.html +0 -2
  373. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
  374. nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
  375. nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
  376. nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
  377. nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
  378. nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
  379. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
  380. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
  381. nautobot/vpn/templates/vpn/vpnprofile.html +0 -2
  382. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
  383. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
  384. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
  385. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
  386. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
  387. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
  388. {nautobot-3.0.0a3.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +0 -0
nautobot/core/settings.py CHANGED
@@ -413,6 +413,7 @@ SPECTACULAR_SETTINGS = {
413
413
  # enum naming encountered a non-optimally resolvable collision for fields named "protocol".
414
414
  "InterfaceRedundancyGroupProtocolChoices": "nautobot.dcim.choices.InterfaceRedundancyGroupProtocolChoices",
415
415
  "ServiceProtocolChoices": "nautobot.ipam.choices.ServiceProtocolChoices",
416
+ "VirtualServerProtocolChoices": "nautobot.load_balancers.choices.ProtocolChoices",
416
417
  # These choice enums need to be overridden because they get assigned to the `mode` field and
417
418
  # result in this error:
418
419
  # enum naming encountered a non-optimally resolvable collision for fields named "mode".
@@ -566,8 +567,9 @@ INSTALLED_APPS = [
566
567
  "nautobot.cloud",
567
568
  "nautobot.data_validation",
568
569
  "nautobot.dcim",
569
- "nautobot.ipam",
570
570
  "nautobot.extras",
571
+ "nautobot.ipam",
572
+ "nautobot.load_balancers",
571
573
  "nautobot.tenancy",
572
574
  "nautobot.users",
573
575
  "nautobot.virtualization",
@@ -836,6 +838,11 @@ CONSTANCE_CONFIG = {
836
838
  help_text="Whether to prefer IPv4 primary addresses over IPv6 primary addresses for devices.",
837
839
  field_type=bool,
838
840
  ),
841
+ "RACK_DEFAULT_U_HEIGHT": ConstanceConfigItem(
842
+ default=42,
843
+ help_text="Default height in rack units (U) for newly created racks. Must be between 1 and 500.",
844
+ field_type=int,
845
+ ),
839
846
  "RACK_ELEVATION_DEFAULT_UNIT_HEIGHT": ConstanceConfigItem(
840
847
  default=22, help_text="Default height (in pixels) of a rack unit in a rack elevation diagram", field_type=int
841
848
  ),
@@ -879,6 +886,7 @@ CONSTANCE_CONFIG_FIELDSETS = {
879
886
  "Pagination": ["PAGINATE_COUNT", "MAX_PAGE_SIZE", "PER_PAGE_DEFAULTS"],
880
887
  "Performance": ["JOB_CREATE_FILE_MAX_SIZE"],
881
888
  "Rack Elevation Rendering": [
889
+ "RACK_DEFAULT_U_HEIGHT",
882
890
  "RACK_ELEVATION_DEFAULT_UNIT_HEIGHT",
883
891
  "RACK_ELEVATION_DEFAULT_UNIT_WIDTH",
884
892
  "RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT",
@@ -1041,12 +1049,8 @@ BRANDING_FILEPATHS = {
1041
1049
  "icon_mask": os.getenv(
1042
1050
  "NAUTOBOT_BRANDING_FILEPATHS_ICON_MASK", None
1043
1051
  ), # mono-chrome icon used for the mask-icon header
1044
- "header_bullet": os.getenv(
1045
- "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
1046
- ), # bullet image used for various view headers
1047
- "nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
1048
- "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
1049
- "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
1052
+ # "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
1053
+ # "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
1050
1054
  }
1051
1055
 
1052
1056
  # Title to use in place of "Nautobot"
@@ -1153,6 +1157,12 @@ def silk_request_logging_intercept_logic(request):
1153
1157
 
1154
1158
  SILKY_INTERCEPT_FUNC = silk_request_logging_intercept_logic
1155
1159
 
1160
+ #
1161
+ # django-tables2
1162
+ #
1163
+
1164
+ DJANGO_TABLES2_TEMPLATE = "utilities/obj_table.html"
1165
+
1156
1166
  #
1157
1167
  # Kubernetes settings variables
1158
1168
  #
@@ -162,22 +162,17 @@ properties:
162
162
  type: "string"
163
163
  BRANDING_FILEPATHS:
164
164
  default:
165
- css: null
166
165
  favicon: null
167
- header_bullet: null
168
166
  icon_16: null
169
167
  icon_32: null
170
168
  icon_180: null
171
169
  icon_192: null
172
170
  icon_mask: null
173
- javascript: null
174
171
  logo: null
175
- nav_bullet: null
176
172
  description: >-
177
173
  A set of filepaths relative to the [`MEDIA_ROOT`](#media_root) which locate assets used for
178
174
  custom branding of your Nautobot instance.
179
- With the exception of `css` and `javascript`, which provide the option to add an _additional_ file to Nautobot
180
- page content, each of the other assets takes the place of the corresponding stock Nautobot asset.
175
+ Each of the assets takes the place of the corresponding stock Nautobot asset.
181
176
  This allows for, for instance, providing your own navbar logo and favicon.
182
177
  If a custom asset is not provided for any of the above options, the stock Nautobot asset is used.
183
178
  details: |-
@@ -186,22 +181,15 @@ properties:
186
181
 
187
182
  +++ 2.2.4
188
183
  The `css` and `javascript` assets were added as options.
184
+
185
+ --- 3.0.0
186
+ The `header_bullet`, `nav_bullet`, `javascript`, and `css` assets were removed.
189
187
  properties:
190
- css:
191
- "$ref": "#/definitions/relative_path"
192
- default: null
193
- description: "Custom global CSS file"
194
- environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_CSS"
195
188
  favicon:
196
189
  "$ref": "#/definitions/relative_path"
197
190
  default: null
198
191
  description: "Browser favicon"
199
192
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_FAVICON"
200
- header_bullet:
201
- "$ref": "#/definitions/relative_path"
202
- default: null
203
- description: "Bullet image used for various view headers"
204
- environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET"
205
193
  icon_16:
206
194
  "$ref": "#/definitions/relative_path"
207
195
  default: null
@@ -227,21 +215,11 @@ properties:
227
215
  default: null
228
216
  description: "Mono-chrome icon used for the mask-icon header"
229
217
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_ICON_MASK"
230
- javascript:
231
- "$ref": "#/definitions/relative_path"
232
- default: null
233
- description: "Custom global JavaScript file"
234
- environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT"
235
218
  logo:
236
219
  "$ref": "#/definitions/relative_path"
237
220
  default: null
238
221
  description: "Navbar logo"
239
222
  environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_LOGO"
240
- nav_bullet:
241
- "$ref": "#/definitions/relative_path"
242
- default: null
243
- description: "Bullet image used for nav menu headers"
244
- environment_variable: "NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET"
245
223
  type: "object"
246
224
  version_added: "1.2.0"
247
225
  BRANDING_PREPENDED_FILENAME:
@@ -92,7 +92,7 @@
92
92
  </header>
93
93
 
94
94
  <main class="container-fluid wrapper{% if is_popup %} pb-0{% endif %}" id="main-content" tabindex="-1">
95
- <div class="align-items-center d-flex gap-8 justify-content-end mb-16 d-print-none">
95
+ <div class="align-items-center d-flex gap-8 justify-content-end mb-16 d-print-none flex-wrap">
96
96
  {% block object-tools %}{% endblock %}
97
97
  </div>
98
98
  <!-- Content -->
@@ -107,7 +107,6 @@
107
107
  {% endif %}
108
108
  {% include 'inc/footer.html' %}
109
109
  {% endif %}
110
- {% include 'modals/modal_theme.html' with name='theme'%}
111
110
 
112
111
  {% block javascript %}
113
112
  {% include 'inc/javascript.html' %}
@@ -1,5 +1,5 @@
1
1
  {% extends "admin/base_site.html" %}
2
- {% load i18n admin_urls static admin_list bootstrapped_goodies_tags %}
2
+ {% load i18n admin_urls static admin_list bootstrapped_goodies_tags helpers %}
3
3
 
4
4
  {% block extrastyle %}
5
5
  {{ block.super }}
@@ -41,17 +41,14 @@
41
41
 
42
42
  {% block object-tools %}
43
43
  {% block search %}{% search_form cl %}{% endblock %}
44
- <div id="content-navbar-collapse" class="navbar-collapse collapse">
45
- {% block object-tools-items %}
46
- {% if has_add_permission %}
47
- {% url cl.opts|admin_urlname:'add' as add_url %}
48
- <a role="button" href="{% add_preserved_filters add_url is_popup %}" class="btn btn-primary">
49
- <span class="glyphicon glyphicon-plus"></span> {% blocktrans with cl.opts.verbose_name as name %}Add{% endblocktrans %}
50
- </a>
51
- </li>
52
- {% endif %}
53
- {% endblock %}
54
- </div>
44
+ {% block object-tools-items %}
45
+ {% if has_add_permission %}
46
+ {% url cl.opts|admin_urlname:'add' as add_url %}
47
+ <a role="button" href="{% add_preserved_filters add_url is_popup %}" class="btn btn-primary">
48
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> {% blocktrans with cl.opts.verbose_name|bettertitle as name %}Add {{ name }}{% endblocktrans %}
49
+ </a>
50
+ {% endif %}
51
+ {% endblock %}
55
52
  {% endblock %}
56
53
 
57
54
  {% block content %}
@@ -26,7 +26,7 @@
26
26
  </div>
27
27
  <div class="container-fluid mb-12 mt-16">
28
28
  <div class="row">
29
- <div class="col-4">
29
+ <div id="page-title" class="col-4">
30
30
  {% with copy_title=False %}
31
31
  {% block page_title %}{% include "inc/page_title.html" with title=title_block_content copy_title=copy_title %}{% endblock %}
32
32
  {% endwith %}
@@ -51,7 +51,6 @@
51
51
  </div>
52
52
  {% endif %}
53
53
  {% endif %}
54
- {% include 'modals/modal_theme.html' with name='theme'%}
55
54
  {% include 'inc/footer.html' %}
56
55
  {% include 'inc/javascript.html' %}
57
56
  {% block javascript %}{% endblock %}
@@ -4,7 +4,7 @@
4
4
  {% if body_content_table_list_url %}
5
5
  <a href="{{ body_content_table_list_url }}" class="badge bg-primary">{% if badge_count_override %}{{ badge_count_override }}{% else %}{{ body_content_table.rows|length }}{% endif %}</a>
6
6
  {% elif body_content_table or badge_count_override %}
7
- <span class="badge bg-primary">
7
+ <span class="badge bg-secondary">
8
8
  {% if badge_count_override %}
9
9
  {{ badge_count_override }}
10
10
  {% else %}
@@ -6,9 +6,9 @@
6
6
 
7
7
  <div id="{{ tab_id }}" role="tabpanel" class="tab-pane fade{% if active_tab == tab_id or request.GET.tab == tab_id %} show active{% endif %}">
8
8
  {% if include_timestamps_and_buttons %}
9
- <div class="align-items-center d-flex flex-wrap mb-16">
9
+ <div class="align-items-center d-flex flex-wrap mb-16 gap-8">
10
10
  {% include 'inc/created_updated.html' %}
11
- <div class="flex-grow-0 flex-shrink-0 d-print-none">
11
+ <div class="d-flex align-items-center gap-8 flex-grow-0 flex-wrap d-print-none ms-auto">
12
12
  {% custom_links object %}
13
13
  {% job_buttons object %}
14
14
  {% block buttons %}
@@ -20,9 +20,9 @@
20
20
  </div>
21
21
  </div>
22
22
  {% else %}
23
- <div class="align-items-center d-flex flex-wrap mb-16">
23
+ <div class="align-items-center d-flex flex-wrap mb-16 gap-8">
24
24
  <div class="flex-grow-1 m-0"></div>
25
- <div class="flex-grow-0 flex-shrink-0 d-print-none">
25
+ <div class="d-flex align-items-center gap-8 flex-grow-0 flex-wrap d-print-none ms-auto">
26
26
  {% render_detail_view_extra_buttons %}
27
27
  </div>
28
28
  </div>
@@ -6,15 +6,28 @@
6
6
 
7
7
  <script type="text/javascript">
8
8
  document.addEventListener('DOMContentLoaded', () => {
9
- // Initialize the echarts instance based on the prepared dom
10
- var myChart = window.echarts.init(document.getElementById("{{ chart_container_id }}"), null, { renderer: "{{ chart.renderer }}" });
9
+ setTimeout(() => {
10
+ // Initialize the echarts instance based on the prepared dom
11
+ var myChart = window.echarts.init(document.getElementById("{{ chart_container_id }}"), null, { renderer: "{{ chart.renderer }}" });
11
12
 
12
- // Get config from JSON script
13
- var options = JSON.parse(
14
- document.getElementById("echarts-config-{{ chart_container_id }}").textContent
15
- );
13
+ // Get config from JSON script
14
+ var options = JSON.parse(
15
+ document.getElementById("echarts-config-{{ chart_container_id }}").textContent
16
+ );
16
17
 
17
- // Display the chart using the configuration items and data just specified.
18
- myChart.setOption(options);
18
+ // Get current theme
19
+ var currentTheme = document.documentElement.dataset.bsTheme || 'light';
20
+
21
+ // Display the chart using the configuration items and data just specified.
22
+ myChart.setOption({
23
+ ...options,
24
+ // Enable dark mode if the current theme is dark
25
+ darkMode: currentTheme === 'dark',
26
+ // Update colors based on theme
27
+ color: Array.isArray(options.color)
28
+ ? options.color.map((colorObj) => colorObj?.[currentTheme] || colorObj?.light || colorObj)
29
+ : options.color,
30
+ });
31
+ });
19
32
  });
20
33
  </script>
@@ -1,7 +1,7 @@
1
1
  {% extends 'base.html' %}
2
2
  {% comment %}
3
- 3.0 TODO: This file is not used in Nautobot any more as it's replaced by the 'system_jobs/import_objects.html' template.
4
- Leaving it here for now in case apps are making use of it.
3
+ 4.0 TODO: This file should be replaced by the 'system_jobs/import_objects.html' template eventually,
4
+ but for now many CSV import views still exist which use this template.
5
5
  {% endcomment %}
6
6
  {% load helpers %}
7
7
  {% load form_helpers %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_bulk_destroy.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_bulk_update.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_bulk_create.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_destroy.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
1
  {% extends 'generic/object_create.html' %}
2
- {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
2
+ {% comment %}4.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -129,9 +129,9 @@
129
129
  {% render_components object_detail_content.tabs %}
130
130
  {% else %}
131
131
  <div id="main" role="tabpanel" class="tab-pane {% if active_tab == "main" or request.GET.tab == "main" %}active{% else %}fade{% endif %}">
132
- <div class="align-items-center d-flex flex-wrap mb-16">
132
+ <div class="align-items-center d-flex flex-wrap mb-16 gap-8">
133
133
  {% include 'inc/created_updated.html' %}
134
- <div class="flex-grow-0 flex-shrink-0 d-print-none">
134
+ <div class="d-flex align-items-center gap-8 flex-grow-0 flex-wrap d-print-none ms-auto">
135
135
  {% custom_links object %}
136
136
  {% job_buttons object %}
137
137
  {% block buttons %}
@@ -108,7 +108,6 @@ add "&raw" to the end of the URL within a browser.
108
108
  </div>
109
109
  {% block header %}{% endblock header %}
110
110
  </header>
111
- {% include 'modals/modal_theme.html' with name='theme'%}
112
111
  {% include 'inc/javascript.html' %}
113
112
  <main class="container-fluid wrapper" id="main-content" tabindex="-1">
114
113
  <!-- GraphiQL page contents -->
@@ -9,7 +9,7 @@
9
9
  {% if request.user.is_authenticated %}
10
10
  {% if settings.BRANDING_FILEPATHS.logo and settings.BRANDING_POWERED_BY_URL %}
11
11
  <a
12
- class="align-items-center d-inline-flex gap-4 my-n4 text-decoration-none"
12
+ class="align-items-center d-inline-flex fs-5 gap-4 my-n4 text-decoration-none"
13
13
  href="{{ settings.BRANDING_POWERED_BY_URL }}"
14
14
  target="_blank"
15
15
  >
@@ -102,3 +102,5 @@
102
102
  </div>
103
103
  </div>
104
104
  </footer>
105
+
106
+ {% include 'modals/modal_theme.html' with name='theme'%}
@@ -1,4 +1,5 @@
1
1
  {% load helpers %}
2
+ {% load static %}
2
3
 
3
4
  {% if request.user.is_authenticated %}
4
5
  {% with is_apple_os=request.META.HTTP_USER_AGENT|split:'Mac OS X'|length|divisibleby:'2' %}
@@ -72,4 +73,13 @@
72
73
  </ul>
73
74
  </div>
74
75
  </div>
76
+ {% else %}
77
+ {% url settings.LOGIN_URL as login_url %}
78
+ {% if request.path != login_url %}
79
+ <div class="col-4 offset-4 text-end">
80
+ <a class="btn btn-primary" href="{{ login_url }}?next={{ request.get_full_path | urlencode }}">
81
+ <span aria-hidden="true" class="mdi mdi-login me-4"></span>Log in
82
+ </a>
83
+ </div>
84
+ {% endif %}
75
85
  {% endif %}
@@ -9,6 +9,20 @@
9
9
  <link rel="stylesheet"
10
10
  href="{% static 'dist/css/materialdesignicons.css' %}"
11
11
  onerror="window.location='{% url 'media_failure' %}?filename=dist/css/materialdesignicons.css'">
12
+ {% with cookie_theme=request.COOKIES|get_item:'theme' %}
13
+ {% if not cookie_theme or cookie_theme == 'light' %}
14
+ <link rel="stylesheet"
15
+ href="{% static 'dist/css/github.min.css' %}"
16
+ onerror="window.location='{% url 'media_failure' %}?filename=dist/css/github.min.css'"
17
+ {% if not cookie_theme %}media="not (prefers-color-scheme: dark)"{% endif %}>
18
+ {% endif %}
19
+ {% if not cookie_theme or cookie_theme == 'dark' %}
20
+ <link rel="stylesheet"
21
+ href="{% static 'dist/css/github-dark.min.css' %}"
22
+ onerror="window.location='{% url 'media_failure' %}?filename=dist/css/github-dark.min.css'"
23
+ {% if not cookie_theme %}media="(prefers-color-scheme: dark)"{% endif %}>
24
+ {% endif %}
25
+ {% endwith %}
12
26
  {% if settings.BRANDING_FILEPATHS.css %}
13
27
  <link rel="stylesheet" id="custom-css" href="{% custom_branding_or_static 'css' None %}">
14
28
  {% endif %}
@@ -15,7 +15,7 @@
15
15
  ></button>
16
16
 
17
17
  <a class="nb-sidenav-brand" href="{% url 'home' %}">
18
- <img src="{% custom_branding_or_static 'icon' 'img/nautobot_icon.svg' %}"/>
18
+ <img src="{% custom_branding_or_static 'icon_32' 'img/nautobot_icon.svg' %}"/>
19
19
  </a>
20
20
  <a class="position-absolute nb-sidenav-brand" href="{% url 'home' %}">
21
21
  <img src="{% custom_branding_or_static 'logo' 'img/nautobot_logo.svg' %}"/>
@@ -149,13 +149,6 @@
149
149
  </li>
150
150
  {% endfor %}
151
151
  {% endwith %}
152
- {% else %}
153
- <li class="nb-sidenav-link-wrapper">
154
- <a class="nb-sidenav-link flat" href="{% url settings.LOGIN_URL %}?next={{ request.get_full_path | urlencode }}">
155
- <span class="mdi mdi-login"></span>
156
- <span class="ms-10">Log in</span>
157
- </a>
158
- </li>
159
152
  {% endif %}
160
153
  </ul>
161
154
  </nav>
@@ -68,13 +68,13 @@
68
68
  {% if object.created %}
69
69
  <tr>
70
70
  <td>Created</td>
71
- <td>{{ object.created }}</td>
71
+ <td><span data-bs-toggle="tooltip" title="Created at">{{ object.created }}</span></td>
72
72
  </tr>
73
73
  {% endif %}
74
74
  {% if object.last_updated %}
75
75
  <tr>
76
76
  <td>Updated</td>
77
- <td>{{ object.last_updated }}</td>
77
+ <td><span data-bs-toggle="tooltip" title="Last updated">{{ object.last_updated }}</span></td>
78
78
  </tr>
79
79
  {% endif %}
80
80
  <tr>
@@ -261,12 +261,6 @@ SECRET_KEY = os.getenv("NAUTOBOT_SECRET_KEY", "{{ secret_key }}")
261
261
  # "icon_mask": os.getenv(
262
262
  # "NAUTOBOT_BRANDING_FILEPATHS_ICON_MASK", None
263
263
  # ), # mono-chrome icon used for the mask-icon header
264
- # "header_bullet": os.getenv(
265
- # "NAUTOBOT_BRANDING_FILEPATHS_HEADER_BULLET", None
266
- # ), # bullet image used for various view headers
267
- # "nav_bullet": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_NAV_BULLET", None), # bullet image used for nav menu headers
268
- # "css": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_CSS", None), # Custom global CSS
269
- # "javascript": os.getenv("NAUTOBOT_BRANDING_FILEPATHS_JAVASCRIPT", None), # Custom global JavaScript
270
264
  # }
271
265
 
272
266
  # Prepended to CSV, YAML and export template filenames (i.e. `nautobot_device.yml`)
@@ -2,6 +2,8 @@
2
2
  {% load helpers %}
3
3
  {% load plugins %}
4
4
  {% load static %}
5
+ {% load i18n %}
6
+ {% load rest_framework %}
5
7
  {% load ui_framework %}
6
8
 
7
9
  {% block bootstrap_theme %}
@@ -37,7 +39,83 @@
37
39
  </header>
38
40
  <main class="container-fluid wrapper" id="main-content" tabindex="-1">
39
41
  {% block content %}
40
- {{ block.super }}
42
+ <div class="region" aria-label="{% trans "request form" %}">
43
+ {% block request_forms %}
44
+
45
+ {% if 'GET' in allowed_methods %}
46
+ <form id="get-form" class="button-form">
47
+ <fieldset>
48
+ {% if api_settings.URL_FORMAT_OVERRIDE %}
49
+ <div class="btn-group format-selection">
50
+ <a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
51
+
52
+ <button class="btn btn-primary dropdown-toggle js-tooltip" data-bs-toggle="dropdown" title="Specify a format for the GET request">
53
+ <span class="mdi mdi-chevron-down"></span>
54
+ </button>
55
+ <ul class="dropdown-menu">
56
+ {% for format in available_formats %}
57
+ <li>
58
+ <a class="js-tooltip format-option dropdown-item" href="{% add_query_param request api_settings.URL_FORMAT_OVERRIDE format %}" rel="nofollow" title="Make a GET request on the {{ name }} resource with the format set to `{{ format }}`">{{ format }}</a>
59
+ </li>
60
+ {% endfor %}
61
+ </ul>
62
+ </div>
63
+ {% else %}
64
+ <a class="btn btn-primary js-tooltip" href="{{ request.get_full_path }}" rel="nofollow" title="Make a GET request on the {{ name }} resource">GET</a>
65
+ {% endif %}
66
+ </fieldset>
67
+ </form>
68
+ {% endif %}
69
+
70
+ {% if options_form %}
71
+ {# djlint:off H029 OPTIONS is an HTTP method #}
72
+ <form class="button-form" action="{{ request.get_full_path }}" data-method="OPTIONS">
73
+ <button class="btn btn-primary js-tooltip" title="Make an OPTIONS request on the {{ name }} resource">OPTIONS</button>
74
+ </form>
75
+ {# djlint:on H029 #}
76
+ {% endif %}
77
+
78
+ {% if extra_actions %}
79
+ <div class="dropdown" style="float: right; margin-right: 10px">
80
+ <button class="btn btn-secondary" id="extra-actions-menu" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
81
+ {% trans "Extra Actions" %}
82
+ <span class="mdi mdi-chevron-down"></span>
83
+ </button>
84
+ <ul class="dropdown-menu" aria-labelledby="extra-actions-menu">
85
+ {% for action_name, url in extra_actions|items %}
86
+ <li><a href="{{ url }}" class="dropdown-item">{{ action_name }}</a></li>
87
+ {% endfor %}
88
+ </ul>
89
+ </div>
90
+ {% endif %}
91
+
92
+ {% endblock request_forms %}
93
+ </div>
94
+
95
+ <div class="content-main" role="main" aria-label="{% trans "main content" %}">
96
+ <div class="float-start">
97
+ {% block description %}
98
+ {{ description }}
99
+ {% endblock %}
100
+ </div>
101
+
102
+ {% if paginator %}
103
+ <nav class="float-end">
104
+ {% get_pagination_html paginator %}
105
+ </nav>
106
+ {% endif %}
107
+
108
+ <div class="request-info pt-4" aria-label="{% trans "request info" %}">
109
+ <pre class="language-json"><b>{{ request.method }}</b> {{ request.get_full_path }}</pre>
110
+ </div>
111
+
112
+ <div class="response-info" aria-label="{% trans "response info" %}">
113
+ <pre class="language-json"><span class="meta nocode"><b>HTTP {{ response.status_code }} {{ response.status_text }}</b>{% for key, val in response_headers|items %}
114
+ <b>{{ key }}:</b> <span class="lit">{{ val|urlize }}</span>{% endfor %}
115
+
116
+ </span>{{ content|urlize }}</pre>
117
+ </div>
118
+ </div>
41
119
  {% endblock %}
42
120
  </main>
43
121
  {% include 'inc/footer.html' %}
@@ -49,12 +127,35 @@
49
127
 
50
128
  {% block script %}
51
129
  {% include 'inc/javascript.html' %}
52
- <script src="{% static "rest_framework/js/prettify-min.js" %}"></script>
53
130
  <script src="{% static "rest_framework/js/ajax-form.js" %}"></script>
54
131
  <script src="{% static "rest_framework/js/default.js" %}"></script>
55
132
  <script>
133
+ function linkifyHighlightedUrls() {
134
+ // Find all hljs-string spans
135
+ const stringSpans = document.querySelectorAll('span.hljs-string');
136
+
137
+ stringSpans.forEach(span => {
138
+ const text = span.textContent;
139
+
140
+ // Check if the string starts with "http
141
+ if (text.match(/^["']https?:\/\/.*["']$/)) {
142
+ // Extract the URL (remove quotes)
143
+ const url = text.slice(1, -1); // Remove opening and closing quotes
144
+
145
+ // Create a clickable link while preserving the syntax highlighting
146
+ const link = document.createElement('a');
147
+ link.href = url;
148
+ link.className = 'hljs-string'; // Maintain the syntax highlighting class
149
+ link.textContent = text; // Keep the original text with quotes
150
+
151
+ // Replace the span with the link
152
+ span.parentNode.replaceChild(link, span);
153
+ }
154
+ });
155
+ }
56
156
  $(document).ready(function() {
57
157
  $('form').ajaxForm();
158
+ linkifyHighlightedUrls();
58
159
  });
59
160
  </script>
60
161
  {% endblock script %}
@@ -124,6 +124,31 @@
124
124
  dynamicFilterForm: document.querySelector('#dynamic-filter-form'),
125
125
  });
126
126
 
127
+ const prepopulateFilterSelectsFromURL = (() => {
128
+ const { defaultFilterForm } = getFilterForms();
129
+ const urlParams = new URLSearchParams(window.location.search);
130
+ // Only target Select2 controls inside the default filter form.
131
+ [...defaultFilterForm.querySelectorAll('select.nautobot-select2-multi-value-char')].forEach((el) => {
132
+ const name = el.getAttribute('name');
133
+ if (!name) { return; }
134
+ const values = urlParams.getAll(name);
135
+ if (!values.length) { return; }
136
+ values.forEach((val) => {
137
+ let found = Array.prototype.find.call(el.options, (opt) => {
138
+ return String(opt.value) === String(val);
139
+ });
140
+ if (found) {
141
+ found.selected = true;
142
+ } else {
143
+ el.add(new Option(val, val, true, true));
144
+ }
145
+ });
146
+ if (window.jQuery && $(el).data('select2')) {
147
+ $(el).trigger('change');
148
+ }
149
+ });
150
+ })();
151
+
127
152
  /**
128
153
  * Synchronize given `filter` value from default to dynamic filter form.
129
154
  * @param {string} name - Filter name.
@@ -435,6 +460,14 @@
435
460
 
436
461
  const { defaultFilterForm, dynamicFilterForm } = getFilterForms();
437
462
 
463
+ /*
464
+ * Just before the form submission automatically add filter selected in "Advanced" tab (if any)
465
+ * which hasn't been manually applied for whatever reason (usually forgetfulness, speed, etc.).
466
+ * This is a requested UX flavor.
467
+ */
468
+ const add = dynamicFilterForm.querySelector('button.nb-dynamic-filter-add');
469
+ add.click();
470
+
438
471
  // Remove all field names which are not applied filters container descendants.
439
472
  [...dynamicFilterForm.querySelectorAll('input, select, textarea')].forEach((field) =>
440
473
  field.closest('.nb-dynamic-filter-items') ? undefined : field.removeAttribute('name'),