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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (659) hide show
  1. nautobot/apps/choices.py +4 -2
  2. nautobot/apps/filters.py +7 -9
  3. nautobot/apps/models.py +2 -2
  4. nautobot/apps/ui.py +13 -1
  5. nautobot/apps/utils.py +8 -0
  6. nautobot/circuits/filters.py +3 -2
  7. nautobot/circuits/navigation.py +3 -2
  8. nautobot/circuits/templates/circuits/circuit_create.html +3 -3
  9. nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
  10. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
  11. nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
  12. nautobot/circuits/tests/integration/test_circuit.py +10 -13
  13. nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
  14. nautobot/circuits/views.py +6 -2
  15. nautobot/cloud/filters.py +1 -1
  16. nautobot/cloud/navigation.py +3 -2
  17. nautobot/core/api/schema.py +1 -1
  18. nautobot/core/api/serializers.py +6 -1
  19. nautobot/core/api/urls.py +2 -0
  20. nautobot/core/api/views.py +12 -0
  21. nautobot/core/apps/__init__.py +11 -10
  22. nautobot/core/celery/__init__.py +3 -5
  23. nautobot/core/checks.py +46 -0
  24. nautobot/core/choices.py +1 -1
  25. nautobot/core/cli/bootstrap_v3_to_v5.py +105 -13
  26. nautobot/core/cli/migrate_deprecated_templates.py +227 -0
  27. nautobot/core/constants.py +3 -0
  28. nautobot/core/context_processors.py +9 -1
  29. nautobot/core/filters.py +4 -0
  30. nautobot/core/forms/__init__.py +2 -0
  31. nautobot/core/forms/forms.py +1 -1
  32. nautobot/core/forms/widgets.py +21 -2
  33. nautobot/core/jobs/__init__.py +62 -3
  34. nautobot/core/jobs/groups.py +31 -1
  35. nautobot/core/management/commands/generate_test_data.py +28 -9
  36. nautobot/core/models/__init__.py +11 -0
  37. nautobot/core/models/generics.py +9 -1
  38. nautobot/core/models/tree_queries.py +10 -5
  39. nautobot/core/models/utils.py +1 -1
  40. nautobot/core/settings.py +35 -19
  41. nautobot/core/settings.yaml +17 -33
  42. nautobot/core/signals.py +12 -1
  43. nautobot/core/tables.py +13 -6
  44. nautobot/core/templates/40x.html +1 -1
  45. nautobot/core/templates/500.html +2 -2
  46. nautobot/core/templates/admin/base.html +1 -2
  47. nautobot/core/templates/admin/change_list.html +9 -12
  48. nautobot/core/templates/admin/config/config.html +12 -12
  49. nautobot/core/templates/admin/index.html +3 -3
  50. nautobot/core/templates/base_django.html +1 -2
  51. nautobot/core/templates/buttons/export.html +1 -1
  52. nautobot/core/templates/components/button/dropdown.html +5 -3
  53. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
  54. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  55. nautobot/core/templates/components/panel/panel.html +3 -3
  56. nautobot/core/templates/components/tab/content_wrapper.html +6 -7
  57. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
  58. nautobot/core/templates/echarts/echarts.html +22 -9
  59. nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
  60. nautobot/core/templates/generic/object_bulk_create.html +6 -5
  61. nautobot/core/templates/generic/object_bulk_delete.html +1 -1
  62. nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
  63. nautobot/core/templates/generic/object_bulk_edit.html +1 -1
  64. nautobot/core/templates/generic/object_bulk_import.html +1 -1
  65. nautobot/core/templates/generic/object_bulk_remove.html +2 -2
  66. nautobot/core/templates/generic/object_bulk_update.html +5 -4
  67. nautobot/core/templates/generic/object_create.html +5 -4
  68. nautobot/core/templates/generic/object_delete.html +1 -1
  69. nautobot/core/templates/generic/object_detail.html +1 -1
  70. nautobot/core/templates/generic/object_edit.html +1 -1
  71. nautobot/core/templates/generic/object_import.html +2 -1
  72. nautobot/core/templates/generic/object_list.html +12 -4
  73. nautobot/core/templates/generic/object_notes.html +5 -3
  74. nautobot/core/templates/generic/object_retrieve.html +4 -5
  75. nautobot/core/templates/graphene/graphiql.html +7 -8
  76. nautobot/core/templates/home.html +1 -1
  77. nautobot/core/templates/import_success.html +2 -1
  78. nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
  79. nautobot/core/templates/inc/created_updated.html +7 -3
  80. nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
  81. nautobot/core/templates/inc/footer.html +3 -1
  82. nautobot/core/templates/inc/form_static_field.html +6 -0
  83. nautobot/core/templates/inc/header.html +11 -1
  84. nautobot/core/templates/inc/image_attachments.html +2 -1
  85. nautobot/core/templates/inc/media.html +14 -0
  86. nautobot/core/templates/inc/nav_menu.html +3 -9
  87. nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
  88. nautobot/core/templates/inc/search_panel.html +4 -4
  89. nautobot/core/templates/login.html +4 -2
  90. nautobot/core/templates/nautobot_config.py.j2 +6 -11
  91. nautobot/core/templates/redoc_ui.html +7 -0
  92. nautobot/core/templates/rest_framework/api.html +103 -2
  93. nautobot/core/templates/search.html +1 -1
  94. nautobot/core/templates/swagger_ui.html +17 -3
  95. nautobot/core/templates/system_jobs/import_objects.html +1 -2
  96. nautobot/core/templates/utilities/confirmation_form.html +2 -2
  97. nautobot/core/templates/utilities/obj_table.html +10 -2
  98. nautobot/core/templates/utilities/render_field.html +7 -7
  99. nautobot/core/templates/utilities/render_jinja2.html +2 -2
  100. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +37 -4
  101. nautobot/core/templates/utilities/theme_preview.html +19 -3
  102. nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
  103. nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
  104. nautobot/core/templatetags/helpers.py +76 -18
  105. nautobot/core/testing/api.py +68 -9
  106. nautobot/core/testing/filters.py +0 -23
  107. nautobot/core/testing/integration.py +41 -17
  108. nautobot/core/testing/mixins.py +2 -0
  109. nautobot/core/testing/utils.py +18 -4
  110. nautobot/core/testing/views.py +104 -13
  111. nautobot/core/tests/integration/test_app_home.py +34 -30
  112. nautobot/core/tests/integration/test_app_navbar.py +3 -0
  113. nautobot/core/tests/integration/test_filters.py +48 -11
  114. nautobot/core/tests/integration/test_theme.py +22 -21
  115. nautobot/core/tests/nautobot_config.py +3 -0
  116. nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
  117. nautobot/core/tests/runner.py +8 -1
  118. nautobot/core/tests/test_api.py +5 -3
  119. nautobot/core/tests/test_breadcrumbs.py +27 -28
  120. nautobot/core/tests/test_checks.py +28 -0
  121. nautobot/core/tests/test_cli.py +40 -0
  122. nautobot/core/tests/test_config.py +2 -1
  123. nautobot/core/tests/test_forms.py +55 -13
  124. nautobot/core/tests/test_jobs.py +144 -3
  125. nautobot/core/tests/test_nautobot_server.py +2 -0
  126. nautobot/core/tests/test_navigations.py +76 -1
  127. nautobot/core/tests/test_patch_social_django.py +42 -0
  128. nautobot/core/tests/test_renderers.py +59 -0
  129. nautobot/core/tests/test_settings_schema.py +1 -0
  130. nautobot/core/tests/test_tables.py +3 -1
  131. nautobot/core/tests/test_templatetags_helpers.py +62 -13
  132. nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
  133. nautobot/core/tests/test_titles.py +0 -16
  134. nautobot/core/tests/test_tree_queries.py +14 -1
  135. nautobot/core/tests/test_ui.py +123 -4
  136. nautobot/core/tests/test_utils.py +72 -5
  137. nautobot/core/tests/test_views.py +159 -31
  138. nautobot/core/ui/breadcrumbs.py +70 -29
  139. nautobot/core/ui/bulk_buttons.py +1 -1
  140. nautobot/core/ui/choices.py +143 -27
  141. nautobot/core/ui/constants.py +76 -12
  142. nautobot/core/ui/echarts.py +15 -20
  143. nautobot/core/ui/object_detail.py +143 -55
  144. nautobot/core/ui/titles.py +3 -6
  145. nautobot/core/urls.py +20 -9
  146. nautobot/core/utils/cache.py +2 -1
  147. nautobot/core/utils/filtering.py +28 -18
  148. nautobot/core/utils/lookup.py +49 -8
  149. nautobot/core/utils/module_loading.py +21 -0
  150. nautobot/core/utils/patch_social_django.py +128 -0
  151. nautobot/core/views/__init__.py +38 -1
  152. nautobot/core/views/generic.py +3 -3
  153. nautobot/core/views/mixins.py +45 -22
  154. nautobot/core/views/renderers.py +4 -3
  155. nautobot/core/views/viewsets.py +2 -1
  156. nautobot/data_validation/apps.py +1 -5
  157. nautobot/data_validation/custom_validators.py +4 -4
  158. nautobot/data_validation/filters.py +1 -1
  159. nautobot/data_validation/forms.py +40 -0
  160. nautobot/data_validation/migrations/0001_initial.py +0 -7
  161. nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -14
  162. nautobot/data_validation/models.py +16 -7
  163. nautobot/data_validation/navigation.py +8 -1
  164. nautobot/data_validation/tables.py +12 -5
  165. nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
  166. nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
  167. nautobot/data_validation/tests/__init__.py +2 -2
  168. nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
  169. nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
  170. nautobot/data_validation/tests/test_filters.py +8 -6
  171. nautobot/data_validation/tests/test_models.py +15 -0
  172. nautobot/data_validation/tests/test_views.py +190 -32
  173. nautobot/data_validation/urls.py +2 -5
  174. nautobot/data_validation/views.py +73 -40
  175. nautobot/dcim/api/serializers.py +3 -13
  176. nautobot/dcim/apps.py +4 -0
  177. nautobot/dcim/choices.py +65 -0
  178. nautobot/dcim/constants.py +7 -0
  179. nautobot/dcim/custom_validators.py +84 -0
  180. nautobot/dcim/factory.py +1 -1
  181. nautobot/dcim/filter_mixins.py +353 -4
  182. nautobot/dcim/{filters/__init__.py → filters.py} +15 -36
  183. nautobot/dcim/forms.py +90 -4
  184. nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
  185. nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
  186. nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
  187. nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
  188. nautobot/dcim/migrations/0079_remove_device_location_tenant_name_uniqueness.py +16 -0
  189. nautobot/dcim/migrations/0080_device_name_data_migration.py +59 -0
  190. nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
  191. nautobot/dcim/models/device_component_templates.py +33 -1
  192. nautobot/dcim/models/device_components.py +98 -64
  193. nautobot/dcim/models/devices.py +30 -20
  194. nautobot/dcim/navigation.py +7 -6
  195. nautobot/dcim/tables/devices.py +18 -0
  196. nautobot/dcim/tables/devicetypes.py +8 -1
  197. nautobot/dcim/tables/racks.py +0 -2
  198. nautobot/dcim/tables/template_code.py +15 -15
  199. nautobot/dcim/templates/dcim/cable_connect.html +28 -112
  200. nautobot/dcim/templates/dcim/cable_trace.html +0 -4
  201. nautobot/dcim/templates/dcim/{cable_edit.html → cable_update.html} +1 -1
  202. nautobot/dcim/templates/dcim/consoleport.html +7 -6
  203. nautobot/dcim/templates/dcim/consoleserverport.html +7 -6
  204. nautobot/dcim/templates/dcim/device/config.html +2 -2
  205. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
  206. nautobot/dcim/templates/dcim/device/status.html +8 -8
  207. nautobot/dcim/templates/dcim/device.html +1 -1
  208. nautobot/dcim/templates/dcim/device_component_add.html +2 -2
  209. nautobot/dcim/templates/dcim/device_create.html +5 -3
  210. nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
  211. nautobot/dcim/templates/dcim/device_list.html +73 -10
  212. nautobot/dcim/templates/dcim/devicebay.html +1 -1
  213. nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
  214. nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
  215. nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
  216. nautobot/dcim/templates/dcim/frontport.html +10 -9
  217. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  218. nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
  219. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
  220. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  221. nautobot/dcim/templates/dcim/interface.html +35 -7
  222. nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
  223. nautobot/dcim/templates/dcim/interface_edit.html +2 -0
  224. nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
  225. nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
  226. nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
  227. nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
  228. nautobot/dcim/templates/dcim/module/base.html +49 -9
  229. nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
  230. nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
  231. nautobot/dcim/templates/dcim/module_frontports.html +1 -1
  232. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  233. nautobot/dcim/templates/dcim/module_list.html +57 -8
  234. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  235. nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
  236. nautobot/dcim/templates/dcim/module_powerports.html +1 -1
  237. nautobot/dcim/templates/dcim/module_rearports.html +1 -1
  238. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  239. nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
  240. nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
  241. nautobot/dcim/templates/dcim/platform_create.html +1 -1
  242. nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
  243. nautobot/dcim/templates/dcim/powerport.html +6 -5
  244. nautobot/dcim/templates/dcim/rack_elevation_list.html +17 -5
  245. nautobot/dcim/templates/dcim/rack_retrieve.html +22 -15
  246. nautobot/dcim/templates/dcim/rearport.html +8 -7
  247. nautobot/dcim/templates/dcim/trace/cable.html +1 -1
  248. nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
  249. nautobot/dcim/templates/dcim/virtualchassis_update.html +15 -7
  250. nautobot/dcim/tests/integration/test_controller.py +4 -6
  251. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
  252. nautobot/dcim/tests/integration/test_create_device.py +0 -2
  253. nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
  254. nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
  255. nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
  256. nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
  257. nautobot/dcim/tests/test_api.py +194 -6
  258. nautobot/dcim/tests/test_custom_validators.py +229 -0
  259. nautobot/dcim/tests/test_filters.py +55 -7
  260. nautobot/dcim/tests/test_forms.py +110 -8
  261. nautobot/dcim/tests/test_graphql.py +44 -1
  262. nautobot/dcim/tests/test_models.py +328 -4
  263. nautobot/dcim/tests/test_tables.py +160 -0
  264. nautobot/dcim/tests/test_views.py +132 -29
  265. nautobot/dcim/urls.py +64 -21
  266. nautobot/dcim/utils.py +3 -3
  267. nautobot/dcim/views.py +777 -397
  268. nautobot/extras/api/views.py +60 -45
  269. nautobot/extras/choices.py +2 -13
  270. nautobot/extras/datasources/git.py +3 -1
  271. nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
  272. nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
  273. nautobot/extras/{filters/__init__.py → filters.py} +33 -48
  274. nautobot/extras/forms/forms.py +14 -15
  275. nautobot/extras/forms/mixins.py +0 -41
  276. nautobot/extras/jobs.py +2 -0
  277. nautobot/extras/jobs_ui.py +4 -3
  278. nautobot/extras/management/__init__.py +11 -0
  279. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
  280. nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
  281. nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
  282. nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
  283. nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
  284. nautobot/extras/models/__init__.py +1 -2
  285. nautobot/extras/models/approvals.py +33 -14
  286. nautobot/extras/models/change_logging.py +4 -0
  287. nautobot/extras/models/contacts.py +2 -0
  288. nautobot/extras/models/groups.py +44 -5
  289. nautobot/extras/models/jobs.py +60 -4
  290. nautobot/extras/models/mixins.py +28 -0
  291. nautobot/extras/models/models.py +23 -2
  292. nautobot/extras/models/secrets.py +1 -0
  293. nautobot/extras/models/statuses.py +0 -15
  294. nautobot/extras/navigation.py +13 -9
  295. nautobot/extras/plugins/__init__.py +33 -55
  296. nautobot/extras/plugins/marketplace_manifest.yml +49 -1
  297. nautobot/extras/plugins/tables.py +3 -3
  298. nautobot/extras/plugins/urls.py +2 -21
  299. nautobot/extras/plugins/utils.py +1 -33
  300. nautobot/extras/plugins/views.py +0 -9
  301. nautobot/extras/querysets.py +8 -0
  302. nautobot/extras/signals.py +20 -19
  303. nautobot/extras/tables.py +64 -68
  304. nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
  305. nautobot/extras/templates/extras/approval_dashboard.html +7 -5
  306. nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
  307. nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
  308. nautobot/extras/templates/extras/configcontext_update.html +1 -0
  309. nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
  310. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
  311. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  312. nautobot/extras/templates/extras/gitrepository_result.html +0 -2
  313. nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
  314. nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
  315. nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
  316. nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
  317. nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
  318. nautobot/extras/templates/extras/inc/json_format.html +10 -3
  319. nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
  320. nautobot/extras/templates/extras/job.html +29 -12
  321. nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
  322. nautobot/extras/templates/extras/job_edit.html +52 -46
  323. nautobot/extras/templates/extras/job_list.html +29 -25
  324. nautobot/extras/templates/extras/marketplace.html +5 -9
  325. nautobot/extras/templates/extras/object_configcontext.html +1 -1
  326. nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
  327. nautobot/extras/templates/extras/objectchange_retrieve.html +19 -39
  328. nautobot/extras/templates/extras/plugin_detail.html +29 -24
  329. nautobot/extras/templates/extras/plugins_list.html +16 -26
  330. nautobot/extras/templates/extras/role_retrieve.html +64 -0
  331. nautobot/extras/templates/extras/scheduledjob.html +4 -2
  332. nautobot/extras/templates/extras/secret_create.html +1 -1
  333. nautobot/extras/templatetags/custom_links.py +12 -12
  334. nautobot/extras/templatetags/job_buttons.py +14 -12
  335. nautobot/extras/test_jobs/invalid_import.py +9 -0
  336. nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
  337. nautobot/extras/test_jobs/missing_import.py +11 -0
  338. nautobot/extras/tests/integration/test_computedfields.py +8 -9
  339. nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
  340. nautobot/extras/tests/integration/test_customfields.py +9 -10
  341. nautobot/extras/tests/integration/test_dynamicgroups.py +12 -9
  342. nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
  343. nautobot/extras/tests/integration/test_plugins.py +18 -6
  344. nautobot/extras/tests/integration/test_relationships.py +0 -2
  345. nautobot/extras/tests/test_api.py +90 -18
  346. nautobot/extras/tests/test_approvals.py +38 -38
  347. nautobot/extras/tests/test_changelog.py +59 -5
  348. nautobot/extras/tests/test_customfields.py +22 -13
  349. nautobot/extras/tests/test_customfields_filters.py +479 -0
  350. nautobot/extras/tests/test_dynamicgroups.py +39 -1
  351. nautobot/extras/tests/test_filters.py +57 -22
  352. nautobot/extras/tests/test_forms.py +18 -21
  353. nautobot/extras/tests/test_jobs.py +25 -4
  354. nautobot/extras/tests/test_migrations.py +1 -0
  355. nautobot/extras/tests/test_models.py +51 -33
  356. nautobot/extras/tests/test_plugins.py +36 -10
  357. nautobot/extras/tests/test_utils.py +3 -4
  358. nautobot/extras/tests/test_views.py +52 -112
  359. nautobot/extras/urls.py +0 -14
  360. nautobot/extras/views.py +164 -71
  361. nautobot/ipam/factory.py +7 -0
  362. nautobot/ipam/filter_mixins.py +38 -0
  363. nautobot/ipam/filters.py +53 -38
  364. nautobot/ipam/formfields.py +1 -1
  365. nautobot/ipam/forms.py +6 -3
  366. nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
  367. nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
  368. nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
  369. nautobot/ipam/models.py +29 -2
  370. nautobot/ipam/navigation.py +3 -2
  371. nautobot/ipam/signals.py +71 -0
  372. nautobot/ipam/tables.py +19 -6
  373. nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
  374. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
  375. nautobot/ipam/templates/ipam/ipaddress.html +14 -0
  376. nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
  377. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
  378. nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
  379. nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
  380. nautobot/ipam/templates/ipam/namespace_update.html +15 -0
  381. nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
  382. nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
  383. nautobot/ipam/templates/ipam/prefix_list.html +14 -13
  384. nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
  385. nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
  386. nautobot/ipam/tests/migration/test_migrations.py +89 -0
  387. nautobot/ipam/tests/test_api.py +13 -6
  388. nautobot/ipam/tests/test_filters.py +36 -1
  389. nautobot/ipam/tests/test_forms.py +1 -1
  390. nautobot/ipam/tests/test_models.py +44 -2
  391. nautobot/ipam/tests/test_tables.py +1 -2
  392. nautobot/ipam/tests/test_utils.py +1 -1
  393. nautobot/ipam/tests/test_views.py +13 -14
  394. nautobot/ipam/ui.py +0 -17
  395. nautobot/ipam/utils/migrations.py +16 -2
  396. nautobot/ipam/utils/testing.py +9 -3
  397. nautobot/ipam/views.py +53 -11
  398. nautobot/load_balancers/__init__.py +0 -0
  399. nautobot/load_balancers/api/__init__.py +1 -0
  400. nautobot/load_balancers/api/serializers.py +75 -0
  401. nautobot/load_balancers/api/urls.py +23 -0
  402. nautobot/load_balancers/api/views.py +61 -0
  403. nautobot/load_balancers/apps.py +17 -0
  404. nautobot/load_balancers/choices.py +167 -0
  405. nautobot/load_balancers/filters.py +225 -0
  406. nautobot/load_balancers/forms.py +532 -0
  407. nautobot/load_balancers/management/commands/__init__.py +0 -0
  408. nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
  409. nautobot/load_balancers/migrations/0001_initial.py +465 -0
  410. nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
  411. nautobot/load_balancers/migrations/__init__.py +0 -0
  412. nautobot/load_balancers/models.py +423 -0
  413. nautobot/load_balancers/navigation.py +80 -0
  414. nautobot/load_balancers/tables.py +255 -0
  415. nautobot/load_balancers/tests/__init__.py +474 -0
  416. nautobot/load_balancers/tests/test_api.py +353 -0
  417. nautobot/load_balancers/tests/test_filters.py +134 -0
  418. nautobot/load_balancers/tests/test_forms.py +266 -0
  419. nautobot/load_balancers/tests/test_models.py +195 -0
  420. nautobot/load_balancers/tests/test_views.py +229 -0
  421. nautobot/load_balancers/urls.py +17 -0
  422. nautobot/load_balancers/views.py +248 -0
  423. nautobot/project-static/dist/css/github-dark.min.css +10 -0
  424. nautobot/project-static/dist/css/github.min.css +10 -0
  425. nautobot/project-static/dist/css/nautobot.css +1 -11
  426. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  427. nautobot/project-static/dist/js/libraries.js +1 -1
  428. nautobot/project-static/dist/js/libraries.js.map +1 -1
  429. nautobot/project-static/dist/js/nautobot.js +1 -1
  430. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  431. nautobot/project-static/js/cabletrace.js +1 -1
  432. nautobot/project-static/js/forms.js +13 -0
  433. nautobot/project-static/js/interface_filtering.js +20 -16
  434. nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
  435. nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
  436. nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
  437. nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
  438. nautobot/project-static/nautobot-icons/cloud.svg +1 -1
  439. nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
  440. nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
  441. nautobot/project-static/nautobot-icons/elements.svg +1 -1
  442. nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
  443. nautobot/project-static/nautobot-icons/hammer.svg +1 -1
  444. nautobot/project-static/nautobot-icons/organization.svg +3 -0
  445. nautobot/project-static/nautobot-icons/secrets.svg +1 -1
  446. nautobot/project-static/nautobot-icons/security.svg +3 -0
  447. nautobot/project-static/nautobot-icons/server.svg +1 -1
  448. nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
  449. nautobot/project-static/nautobot-icons/star.svg +1 -1
  450. nautobot/tenancy/api/serializers.py +1 -0
  451. nautobot/tenancy/api/views.py +2 -1
  452. nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
  453. nautobot/tenancy/navigation.py +3 -1
  454. nautobot/tenancy/tests/test_filters.py +0 -2
  455. nautobot/tenancy/views.py +2 -1
  456. nautobot/ui/package-lock.json +87 -4
  457. nautobot/ui/package.json +2 -1
  458. nautobot/ui/src/js/collapse.js +3 -3
  459. nautobot/ui/src/js/nautobot.js +16 -1
  460. nautobot/ui/src/js/select2.js +53 -2
  461. nautobot/ui/src/scss/colors.scss +1 -1
  462. nautobot/ui/src/scss/nautobot.scss +112 -30
  463. nautobot/ui/webpack.config.js +13 -0
  464. nautobot/users/templates/users/preferences.html +11 -2
  465. nautobot/users/templates/users/profile.html +45 -12
  466. nautobot/users/templates/users/sessionkey_delete.html +1 -1
  467. nautobot/users/tests/test_api.py +4 -0
  468. nautobot/users/views.py +4 -2
  469. nautobot/virtualization/filters.py +6 -1
  470. nautobot/virtualization/models.py +1 -68
  471. nautobot/virtualization/navigation.py +3 -2
  472. nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
  473. nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
  474. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
  475. nautobot/virtualization/tests/test_api.py +3 -0
  476. nautobot/virtualization/tests/test_filters.py +10 -1
  477. nautobot/virtualization/tests/test_models.py +45 -4
  478. nautobot/virtualization/views.py +4 -1
  479. nautobot/vpn/__init__.py +0 -0
  480. nautobot/vpn/api/serializers.py +113 -0
  481. nautobot/vpn/api/urls.py +19 -0
  482. nautobot/vpn/api/views.py +70 -0
  483. nautobot/vpn/apps.py +8 -0
  484. nautobot/vpn/choices.py +171 -0
  485. nautobot/vpn/factory.py +219 -0
  486. nautobot/vpn/filters.py +234 -0
  487. nautobot/vpn/forms.py +487 -0
  488. nautobot/vpn/homepage.py +19 -0
  489. nautobot/vpn/migrations/0001_initial.py +541 -0
  490. nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
  491. nautobot/vpn/migrations/__init__.py +0 -0
  492. nautobot/vpn/models.py +535 -0
  493. nautobot/vpn/navigation.py +98 -0
  494. nautobot/vpn/tables.py +383 -0
  495. nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
  496. nautobot/vpn/tests/__init__.py +0 -0
  497. nautobot/vpn/tests/test_api.py +336 -0
  498. nautobot/vpn/tests/test_filters.py +139 -0
  499. nautobot/vpn/tests/test_forms.py +293 -0
  500. nautobot/vpn/tests/test_models.py +147 -0
  501. nautobot/vpn/tests/test_views.py +300 -0
  502. nautobot/vpn/urls.py +16 -0
  503. nautobot/vpn/views.py +495 -0
  504. nautobot/wireless/navigation.py +3 -2
  505. nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
  506. nautobot/wireless/tests/test_api.py +1 -1
  507. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +15 -15
  508. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +514 -572
  509. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +1 -0
  510. nautobot/circuits/templates/circuits/circuit.html +0 -2
  511. nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
  512. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
  513. nautobot/circuits/templates/circuits/circuit_update.html +0 -1
  514. nautobot/circuits/templates/circuits/circuittermination.html +0 -2
  515. nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
  516. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
  517. nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
  518. nautobot/circuits/templates/circuits/circuittype.html +0 -2
  519. nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
  520. nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
  521. nautobot/circuits/templates/circuits/provider.html +0 -2
  522. nautobot/circuits/templates/circuits/provider_edit.html +0 -2
  523. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
  524. nautobot/circuits/templates/circuits/provider_update.html +0 -1
  525. nautobot/circuits/templates/circuits/providernetwork.html +0 -2
  526. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
  527. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
  528. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
  529. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
  530. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
  531. nautobot/core/templates/buttons/import.html +0 -9
  532. nautobot/data_validation/template_content.py +0 -42
  533. nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
  534. nautobot/dcim/filters/mixins.py +0 -354
  535. nautobot/dcim/templates/dcim/controller/base.html +0 -2
  536. nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
  537. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
  538. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
  539. nautobot/dcim/templates/dcim/device/base.html +0 -2
  540. nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
  541. nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
  542. nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
  543. nautobot/dcim/templates/dcim/device/frontports.html +0 -2
  544. nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
  545. nautobot/dcim/templates/dcim/device/inventory.html +0 -2
  546. nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
  547. nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
  548. nautobot/dcim/templates/dcim/device/powerports.html +0 -2
  549. nautobot/dcim/templates/dcim/device/rearports.html +0 -2
  550. nautobot/dcim/templates/dcim/device/wireless.html +0 -2
  551. nautobot/dcim/templates/dcim/device_component.html +0 -2
  552. nautobot/dcim/templates/dcim/device_edit.html +0 -2
  553. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
  554. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
  555. nautobot/dcim/templates/dcim/devicetype.html +0 -2
  556. nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
  557. nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
  558. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
  559. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
  560. nautobot/dcim/templates/dcim/location.html +0 -2
  561. nautobot/dcim/templates/dcim/location_edit.html +0 -2
  562. nautobot/dcim/templates/dcim/location_retrieve.html +0 -243
  563. nautobot/dcim/templates/dcim/locationtype.html +0 -2
  564. nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
  565. nautobot/dcim/templates/dcim/manufacturer.html +0 -2
  566. nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
  567. nautobot/dcim/templates/dcim/platform.html +0 -2
  568. nautobot/dcim/templates/dcim/powerfeed.html +0 -2
  569. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
  570. nautobot/dcim/templates/dcim/powerpanel.html +0 -2
  571. nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
  572. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
  573. nautobot/dcim/templates/dcim/rack.html +0 -2
  574. nautobot/dcim/templates/dcim/rack_edit.html +0 -2
  575. nautobot/dcim/templates/dcim/rackgroup.html +0 -2
  576. nautobot/dcim/templates/dcim/rackreservation.html +0 -2
  577. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
  578. nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
  579. nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
  580. nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
  581. nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
  582. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
  583. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
  584. nautobot/dcim/ui.py +0 -29
  585. nautobot/extras/templates/extras/computedfield.html +0 -2
  586. nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
  587. nautobot/extras/templates/extras/configcontext.html +0 -2
  588. nautobot/extras/templates/extras/configcontext_edit.html +0 -2
  589. nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
  590. nautobot/extras/templates/extras/configcontextschema.html +0 -2
  591. nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
  592. nautobot/extras/templates/extras/contact_retrieve.html +0 -2
  593. nautobot/extras/templates/extras/customfield.html +0 -2
  594. nautobot/extras/templates/extras/customfield_edit.html +0 -2
  595. nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
  596. nautobot/extras/templates/extras/customlink.html +0 -2
  597. nautobot/extras/templates/extras/dynamicgroup.html +0 -2
  598. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
  599. nautobot/extras/templates/extras/exporttemplate.html +0 -2
  600. nautobot/extras/templates/extras/gitrepository.html +0 -2
  601. nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
  602. nautobot/extras/templates/extras/graphqlquery.html +0 -2
  603. nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
  604. nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -97
  605. nautobot/extras/templates/extras/job_detail.html +0 -2
  606. nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
  607. nautobot/extras/templates/extras/jobhook.html +0 -2
  608. nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
  609. nautobot/extras/templates/extras/jobresult.html +0 -2
  610. nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
  611. nautobot/extras/templates/extras/note.html +0 -2
  612. nautobot/extras/templates/extras/note_retrieve.html +0 -1
  613. nautobot/extras/templates/extras/object_changelog.html +0 -2
  614. nautobot/extras/templates/extras/object_notes.html +0 -2
  615. nautobot/extras/templates/extras/objectchange.html +0 -2
  616. nautobot/extras/templates/extras/objectchange_list.html +0 -3
  617. nautobot/extras/templates/extras/relationship.html +0 -1
  618. nautobot/extras/templates/extras/secret.html +0 -1
  619. nautobot/extras/templates/extras/secret_edit.html +0 -1
  620. nautobot/extras/templates/extras/secretsgroup.html +0 -2
  621. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
  622. nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
  623. nautobot/extras/templates/extras/status.html +0 -2
  624. nautobot/extras/templates/extras/tag.html +0 -2
  625. nautobot/extras/templates/extras/tag_edit.html +0 -2
  626. nautobot/extras/templates/extras/tag_retrieve.html +0 -2
  627. nautobot/extras/templates/extras/team_retrieve.html +0 -2
  628. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
  629. nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
  630. nautobot/ipam/templates/ipam/prefix.html +0 -2
  631. nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
  632. nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
  633. nautobot/ipam/templates/ipam/rir.html +0 -2
  634. nautobot/ipam/templates/ipam/routetarget.html +0 -1
  635. nautobot/ipam/templates/ipam/service.html +0 -2
  636. nautobot/ipam/templates/ipam/service_edit.html +0 -2
  637. nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
  638. nautobot/ipam/templates/ipam/vlan.html +0 -2
  639. nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
  640. nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
  641. nautobot/ipam/templates/ipam/vlangroup.html +0 -2
  642. nautobot/ipam/templates/ipam/vrf.html +0 -1
  643. nautobot/tenancy/templates/tenancy/tenant.html +0 -2
  644. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
  645. nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
  646. nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
  647. nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
  648. nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
  649. nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
  650. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
  651. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
  652. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
  653. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
  654. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
  655. /nautobot/dcim/templates/dcim/{cable.html → cable_retrieve.html} +0 -0
  656. /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
  657. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
  658. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
  659. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
@@ -1,7 +1,8 @@
1
1
  {% load form_helpers %}
2
2
 
3
- <hr>
4
- <div class="mb-10 d-flex justify-content-center{% if field.errors %} has-error{% endif %}">
3
+
4
+ <hr class="border-top">
5
+ <div class="mb-10 d-lg-flex justify-content-center{% if field.errors %} has-error{% endif %}">
5
6
  <label class="col-lg-3 col-form-label{% if field.field.required %} nb-required{% endif %}" for="{{ field.id_for_label }}">
6
7
  {{ field.label }}
7
8
  </label>
@@ -19,17 +20,17 @@
19
20
  {% endif %}
20
21
  </div>
21
22
  </div>
22
- <div class="mb-10 d-flex justify-content-center">
23
+ <div class="mb-10 d-lg-flex justify-content-center">
23
24
  <span class="col-lg-3 col-form-label">
24
25
  </span>
25
26
  <div class="col-lg-9">
26
- <div>
27
- <label for="{{ override_field.id_for_label }}">
28
- {{ override_field }}
27
+ <div class="form-check flex-wrap">
28
+ {{ override_field }}
29
+ <label class="form-check-label" for="{{ override_field.id_for_label }}">
29
30
  <i>Clear override</i>
30
31
  </label>
31
32
  {% if override_field.help_text %}
32
- <span class="form-text">{{ override_field.help_text|safe }}</span>
33
+ <span class="form-text w-100">{{ override_field.help_text|safe }}</span>
33
34
  {% endif %}
34
35
  </div>
35
36
  </div>
@@ -1,6 +1,13 @@
1
+ {% load helpers %}
1
2
  <div class="float-end">
2
- <div class="btn-group btn-group-xs" role="group">
3
- <a href="?data_format=json" class="btn {% if format == 'json' %}btn-primary{% else %}btn-secondary{% endif %}">JSON</a>
4
- <a href="?data_format=yaml" class="btn {% if format == 'yaml' %}btn-primary{% else %}btn-secondary{% endif %}">YAML</a>
3
+ <div class="btn-group btn-group-sm" role="group">
4
+ <a href="{% django_querystring data_format='json' %}"
5
+ class="btn btn-primary {% if data_format == 'json' %}bg-primary nb-text-body-bg{% endif %}">
6
+ <span class="mdi mdi-code-json" aria-hidden="true"></span> JSON
7
+ </a>
8
+ <a href="{% django_querystring data_format='yaml' %}"
9
+ class="btn btn-primary {% if data_format == 'yaml' %}bg-primary nb-text-body-bg{% endif %}">
10
+ <span class="mdi mdi-format-list-group" aria-hidden="true"></span> YAML
11
+ </a>
5
12
  </div>
6
13
  </div>
@@ -0,0 +1,71 @@
1
+ {% load helpers %}
2
+
3
+ <div class="card">
4
+ <div class="card-header">
5
+ <strong>Response</strong>
6
+ <button class="btn btn-primary btn-sm float-end" onclick="test_query()">Execute</button>
7
+ </div>
8
+ {% if object.variables %}
9
+ <table class="table table-hover card-body attr-table">
10
+ <tr>
11
+ <td>Variables:</td>
12
+ <td><textarea id="query_variables" class="form-control">{{ object.variables|render_json:False }}</textarea></td>
13
+ </tr>
14
+ </table>
15
+ {% endif %}
16
+ <div class="card-footer">
17
+ <pre id="query_output" class="p-5">
18
+
19
+ </pre>
20
+ </div>
21
+ </div>
22
+
23
+ <script>
24
+ function fillQueryOutput(data) {
25
+ const queryOutput = document.querySelector('#query_output');
26
+
27
+ [...queryOutput.childNodes].forEach(childNode => childNode.remove());
28
+
29
+ const code = document.createElement('code');
30
+ code.classList.add('language-json');
31
+ code.textContent = JSON.stringify(data, undefined, 2);
32
+
33
+ queryOutput.appendChild(code);
34
+
35
+ hljs.highlightElement(code);
36
+ }
37
+
38
+ function test_query() {
39
+ const variables = document.querySelector('#query_variables')?.value;
40
+
41
+ $.ajax({
42
+ url: "{% url 'graphql' %}",
43
+ method: "POST",
44
+ headers: {"X-CSRFTOKEN": "{{ csrf_token }}"},
45
+ dataType: "json",
46
+ data: {
47
+ "query": `{{ object.query | escapejs }}`,
48
+ "variables": variables,
49
+ },
50
+ success: function(data) {
51
+ fillQueryOutput(data);
52
+ },
53
+ error: function(error) {
54
+ console.log(error);
55
+ fillQueryOutput(error.responseJSON);
56
+ }
57
+ });
58
+ };
59
+
60
+ window.addEventListener("load", () => {
61
+ textarea = document.querySelector("#query_variables");
62
+ textarea.addEventListener('input', autoResize, false);
63
+ textarea.style.height = 'auto';
64
+ textarea.style.height = textarea.scrollHeight + 'px';
65
+ });
66
+
67
+ function autoResize() {
68
+ this.style.height = 'auto';
69
+ this.style.height = this.scrollHeight + 'px';
70
+ }
71
+ </script>
@@ -19,9 +19,21 @@
19
19
  <header class="nb-tile-header">
20
20
  <h3>{{ row.record.grouping|bettertitle }}</h3>
21
21
 
22
- <a href="{% url 'extras:job_run' pk=row.record.pk %}" class="btn btn-primary btn-sm" data-bs-toggle="tooltip" data-bs-title="Run/Schedule" {% if not perms.extras.run_job or not row.record.runnable %}disabled="disabled"{% endif %}>
23
- <span class="mdi mdi-play" aria-hidden="true"><span class="visually-hidden">Run/Schedule</span></span>
24
- </a>
22
+ {% if perms.extras.run_job and row.record.runnable %}
23
+ <a href="{% url 'extras:job_run' pk=row.record.pk %}"
24
+ class="btn btn-primary btn-sm"
25
+ data-bs-toggle="tooltip"
26
+ data-bs-title="Run/Schedule">
27
+ <span class="mdi mdi-play" aria-hidden="true"><span class="visually-hidden">Run/Schedule</span></span>
28
+ </a>
29
+ {% else %}
30
+ <a aria-disabled="true"
31
+ class="btn btn-primary btn-sm disabled"
32
+ data-bs-toggle="tooltip"
33
+ data-bs-title="Run/Schedule">
34
+ <span class="mdi mdi-play" aria-hidden="true"><span class="visually-hidden">Run/Schedule</span></span>
35
+ </a>
36
+ {% endif %}
25
37
 
26
38
  {% comment "TODO(norbert-mieczkowski-codilime): use the same buttons (actions) in tables and tiles when tables support dropdown menus" %}
27
39
  {% for item in row.items %}
@@ -1,6 +1,13 @@
1
+ {% load helpers %}
1
2
  <div class="float-end">
2
- <div class="btn-group btn-group-xs" role="group">
3
- <a href="?format=json" class="btn btn-secondary{% if format == 'json' %} active{% endif %}">JSON</a>
4
- <a href="?format=yaml" class="btn btn-secondary{% if format == 'yaml' %} active{% endif %}">YAML</a>
3
+ <div class="btn-group btn-group-sm" role="group">
4
+ <a href="{% django_querystring format='json' %}"
5
+ class="btn btn-primary{% if format == 'json' %} bg-primary nb-text-body-bg{% endif %}">
6
+ <span class="mdi mdi-code-json" aria-hidden="true"></span> JSON
7
+ </a>
8
+ <a href="{% django_querystring format='yaml' %}"
9
+ class="btn btn-primary{% if format == 'yaml' %} bg-primary nb-text-body-bg{% endif %}">
10
+ <span class="mdi mdi-format-list-group" aria-hidden="true"></span> YAML
11
+ </a>
5
12
  </div>
6
13
  </div>
@@ -1,27 +1,28 @@
1
1
  {% load form_helpers %}
2
2
 
3
- <div class="mb-10 d-flex justify-content-center{% if field.errors %} has-error{% endif %}">
3
+ <div class="mb-10 d-lg-flex justify-content-center{% if field.errors %} has-error{% endif %}">
4
4
  <label class="col-lg-3 col-form-label{% if field.field.required %} nb-required{% endif %}" for="{{ field.id_for_label }}">
5
5
  {{ field.label }}
6
6
  </label>
7
- <div class="col-lg-3">
8
- <div class="form-check{% if override_field.errors %} has-error{% endif %}">
9
- <label for="{{ override_field.id_for_label }}">
10
- {{ override_field }}
7
+ <div class="col-lg-3 pe-lg-10">
8
+ <div class="form-check my-6{% if override_field.errors %} has-error{% endif %}">
9
+ {{ override_field }}
10
+ <label class="form-check-label" for="{{ override_field.id_for_label }}">
11
11
  <i>Override default value</i>
12
+ {% if override_field.help_text %}
13
+ <span class="form-text">{{ override_field.help_text|safe }}</span>
14
+ {% endif %}
12
15
  </label>
13
- {% if override_field.help_text %}
14
- <span class="form-text">{{ override_field.help_text|safe }}</span>
15
- {% endif %}
16
16
  </div>
17
17
  </div>
18
18
  <div class="col-lg-6">
19
19
  {% if field|widget_type == 'checkboxinput' %}
20
- <div class="form-check{% if field.errors %} has-error{% endif %}">
21
- <label for="{{ field.id_for_label }}">
22
- {{ field }} {{ field.label }}
20
+ <div class="form-check my-6{% if field.errors %} has-error{% endif %}">
21
+ {{ field }}
22
+ <label class="form-check-label" for="{{ field.id_for_label }}">
23
+ {{ field.label }}
24
+ {% if field.help_text %}<span class="form-text">{{ field.help_text|safe }}</span>{% endif %}
23
25
  </label>
24
- {% if field.help_text %}<span class="form-text">{{ field.help_text|safe }}</span>{% endif %}
25
26
  </div>
26
27
  {% else %}
27
28
  {{ field }}
@@ -14,17 +14,10 @@
14
14
  <li class="breadcrumb-item">Submission and Scheduling</li>
15
15
  </ol>
16
16
  </div>
17
- <div>
18
- <h1 class="mb-16">{{ job_model }}</h1>
19
- {% if job_model.read_only %}
20
- <span class="badge bg-body-secondary border">Read-only</span>
21
- {% endif %}
22
- <p>{{ job_model.description | render_markdown }}</p>
23
- </div>
24
17
  <form action="" method="post" enctype="multipart/form-data" class="h-100 vstack">
25
18
  {% csrf_token %}
26
- <div class="row align-content-start flex-fill">
27
- <div class="col-xl-8 offset-lg-2 col-lg-10 offset-md-1">
19
+ <div class="row justify-content-center flex-fill">
20
+ <div class="col-xl-8 col-lg-10">
28
21
  {% if not perms.extras.run_job %}
29
22
  <div class="alert alert-warning">
30
23
  <span aria-hidden="true" class="mdi mdi-alert"></span>
@@ -40,6 +33,11 @@
40
33
  <span aria-hidden="true" class="mdi mdi-alert"></span> This job is not enabled to be run.
41
34
  </div>
42
35
  {% endif %}
36
+ {% if job_model.read_only %}
37
+ <div class="alert alert-info">
38
+ <span aria-hidden="true" class="mdi mdi-info"></span>This job is read-only in its operation.
39
+ </div>
40
+ {% endif %}
43
41
  {% if job_form.non_field_errors or schedule_form.non_field_errors %}
44
42
  <div class="card border-danger">
45
43
  <div class="card-header bg-danger-subtle border-danger text-body">
@@ -88,7 +86,7 @@
88
86
  id="id__run"
89
87
  name="_run"
90
88
  type="submit"
91
- {% if not perms.extras.run_job or not job_model.runnable %}disabled="disabled"{% endif %}
89
+ {% if not perms.extras.run_job or not job_model.runnable %}disabled{% endif %}
92
90
  >
93
91
  <span aria-hidden="true" class="mdi mdi-play me-4"></span><!--
94
92
  -->Run Job Now
@@ -147,13 +145,32 @@
147
145
 
148
146
  // Toggle schedule name and schedule time field rows.
149
147
  ['#id__schedule_name', '#id__schedule_start_time'].forEach((selector) => {
150
- const row = document.querySelector(selector).parentElement.parentElement;
148
+ const input = document.querySelector(selector);
149
+ const row = input?.parentElement.parentElement;
151
150
  row.classList.toggle('d-none', immediately);
151
+ const label = row.querySelector('label');
152
+
153
+ label?.classList.toggle('nb-required', !immediately);
154
+ if (immediately) {
155
+ input.removeAttribute('required');
156
+ } else {
157
+ input.setAttribute('required', '');
158
+ }
152
159
  });
153
160
 
154
161
  // Toggle custom crontab field row.
155
- const row = document.querySelector('#id__recurrence_custom_time').parentElement.parentElement;
162
+ input = document.querySelector('#id__recurrence_custom_time')
163
+ const row = input.parentElement.parentElement;
156
164
  row.classList.toggle('d-none', !custom);
165
+ const label = row.querySelector('label');
166
+
167
+ label?.classList.toggle('nb-required', custom);
168
+ if (!custom) {
169
+ input.removeAttribute('required');
170
+ } else {
171
+ input.setAttribute('required', '');
172
+ }
173
+
157
174
  };
158
175
 
159
176
  {% if job_model.has_sensitive_variables %}
@@ -1,6 +1,24 @@
1
1
  {% extends 'generic/object_bulk_update.html' %}
2
2
  {% load form_helpers %}
3
3
 
4
+ {% block extra_styles %}
5
+ <style>
6
+ tr a.job_run {
7
+ display: inline-flex;
8
+ gap: 0.625rem; /* 10px */
9
+ }
10
+
11
+ tr a.job_run .btn {
12
+ align-self: flex-start;
13
+ margin-block: -0.09375rem; /* -1.5px */
14
+ }
15
+
16
+ tr :last-child {
17
+ margin-bottom: 0;
18
+ }
19
+ </style>
20
+ {% endblock %}
21
+
4
22
  {% block form_fields %}
5
23
  {% render_field form.enabled %}
6
24
  {% include "extras/inc/bulk_edit_overridable_field.html" with field=form.grouping override_field=form.clear_grouping_override %}
@@ -6,69 +6,69 @@
6
6
  <div class="card">
7
7
  <div class="card-header"><strong>Job Source</strong></div>
8
8
  <div class="card-body">
9
- <div class="mb-10 d-flex justify-content-center">
9
+ <div class="mb-10 d-lg-flex justify-content-center">
10
10
  <label class="col-lg-3 col-form-label">Module</label>
11
- <div class="col-lg-9" style="padding-top: 7px">
11
+ <div class="col-lg-9 pt-6">
12
12
  <code>{{ obj.module_name }}</code>
13
13
  <span class="form-text">Dotted name of the Python module providing this job</span>
14
14
  </div>
15
15
  </div>
16
- <div class="mb-10 d-flex justify-content-center">
16
+ <div class="mb-10 d-lg-flex justify-content-center">
17
17
  <label class="col-lg-3 col-form-label">Job Class</label>
18
- <div class="col-lg-9" style="padding-top: 7px">
18
+ <div class="col-lg-9 pt-6">
19
19
  <code>{{ obj.job_class_name }}</code>
20
20
  <span class="form-text">Name of the Python class providing this job</span>
21
21
  </div>
22
22
  </div>
23
- <div class="mb-10 d-flex justify-content-center">
23
+ <div class="mb-10 d-lg-flex justify-content-center">
24
24
  <div class="col-lg-9 offset-lg-3">
25
- <div class="form-check">
26
- <label>
27
- <input type="checkbox" disabled="true" {% if obj.installed %}checked="checked"{% endif %}>
25
+ <div class="form-check mt-6">
26
+ <input class="form-check-input" id="id_installed" name="installed" type="checkbox" disabled {% if obj.installed %}checked{% endif %}>
27
+ <label class="form-check-label" for="id_installed">
28
28
  Installed
29
+ <span class="form-text">
30
+ Whether the Python class providing this job is presently installed and loadable
31
+ </span>
29
32
  </label>
30
- <span class="form-text">
31
- Whether the Python class providing this job is presently installed and loadable
32
- </span>
33
33
  </div>
34
34
  </div>
35
35
  </div>
36
- <div class="mb-10 d-flex justify-content-center">
36
+ <div class="mb-10 d-lg-flex justify-content-center">
37
37
  <div class="col-lg-9 offset-lg-3">
38
- <div class="form-check">
39
- <label>
40
- <input type="checkbox" disabled="true" {% if obj.supports_dryrun %}checked="checked"{% endif %}>
38
+ <div class="form-check mt-6">
39
+ <input class="form-check-input" id="id_supports_dryrun" name="supports_dryrun" type="checkbox" disabled {% if obj.supports_dryrun %}checked{% endif %}>
40
+ <label class="form-check-label" for="id_supports_dryrun">
41
41
  Supports dryrun
42
+ <span class="form-text">
43
+ Whether this job supports bypassing approval when running with dryrun argument set to true
44
+ </span>
42
45
  </label>
43
- <span class="form-text">
44
- Whether this job supports bypassing approval when running with dryrun argument set to true
45
- </span>
46
46
  </div>
47
47
  </div>
48
48
  </div>
49
- <div class="mb-10 d-flex justify-content-center">
49
+ <div class="mb-10 d-lg-flex justify-content-center">
50
50
  <div class="col-lg-9 offset-lg-3">
51
- <div class="form-check">
52
- <label>
53
- <input type="checkbox" disabled="true" {% if obj.is_job_hook_receiver %}checked="checked"{% endif %}>
51
+ <div class="form-check mt-6">
52
+ <input class="form-check-input" id="id_is_job_hook_receiver" name="is_job_hook_receiver" type="checkbox" disabled {% if obj.is_job_hook_receiver %}checked{% endif %}>
53
+ <label class="form-check-label" for="id_is_job_hook_receiver">
54
54
  Is job hook receiver
55
+ <span class="form-text">
56
+ Whether this job is a job hook receiver
57
+ </span>
55
58
  </label>
56
- <span class="form-text">
57
- Whether this job is a job hook receiver
58
- </span>
59
59
  </div>
60
60
  </div>
61
61
  </div>
62
- <div class="mb-10 d-flex justify-content-center">
62
+ <div class="mb-10 d-lg-flex justify-content-center">
63
63
  <div class="col-lg-9 offset-lg-3">
64
- <div class="form-check">
65
- <label>
66
- <input type="checkbox" disabled="true" {% if obj.is_job_button_receiver %}checked="checked"{% endif %}>
64
+ <div class="form-check mt-6">
65
+ <input class="form-check-input" id="id_is_job_button_receiver" name="is_job_button_receiver" type="checkbox" disabled {% if obj.is_job_button_receiver %}checked{% endif %}>
66
+ <label class="form-check-label" for="id_is_job_button_receiver">
67
67
  Is job button receiver
68
+ <span class="form-text">
69
+ Whether this job is a job button receiver
70
+ </span>
68
71
  </label>
69
- <span class="form-text">
70
- Whether this job is a job button receiver
71
- </span>
72
72
  </div>
73
73
  </div>
74
74
  </div>
@@ -103,12 +103,15 @@
103
103
  {{ block.super }}
104
104
  {{ obj.job_class.properties_dict | json_script:"job_class_properties" }}
105
105
  <script>
106
+ /*
107
+ * Because some of the form fields are Select2 widgets, we need to stick with jQuery here for now
108
+ */
106
109
  const job_class_properties = JSON.parse(document.getElementById("job_class_properties").textContent);
107
110
  const description_default = $("#id_description").val();
108
- /* All id_*_override fields */
111
+ /* All id_*_override fields */
109
112
  $("[id^=id_][id$=_override]").change(function() {
110
113
  const override_id = $(this).attr("id");
111
- /* What's the form field this is an override for? */
114
+ /* What's the form field this is an override for? */
112
115
  const field_id = override_id.slice(0, -9);
113
116
  const field = $("#" + field_id);
114
117
  const field_name = field_id.slice(3);
@@ -116,32 +119,32 @@
116
119
  field.attr("readonly", null);
117
120
  field.prop("disabled", false);
118
121
  } else {
119
- /* Revert the field to its default value */
122
+ /* Revert the field to its default value */
120
123
  if (field.attr("type") == "checkbox") {
121
- /* Do we have a job class object to derive properties from? */
124
+ /* Do we have a job class object to derive properties from? */
122
125
  if (job_class_properties != "") {
123
126
  field.prop("checked", job_class_properties[field_name]);
124
127
  } else {
125
- /* No, we don't - it's probably not installed */
128
+ /* No, we don't - it's probably not installed */
126
129
  field.prop("checked", field.attr("checked"));
127
130
  }
128
- /*
129
- * Checkboxes can't be "readonly" in HTML :-(
130
- * Note that "disabled" fields aren't included in form submission, so we have to be sure to
131
- * re-enable them at form submission time.
132
- */
131
+ /*
132
+ * Checkboxes can't be "readonly" in HTML :-(
133
+ * Note that "disabled" fields aren't included in form submission, so we have to be sure to
134
+ * re-enable them at form submission time.
135
+ */
133
136
  field.prop("disabled", true);
134
137
  } else {
135
- /* Do we have a job class object to derive properties from? */
138
+ /* Do we have a job class object to derive properties from? */
136
139
  if (job_class_properties != "") {
137
140
  if (field_name != "job_queues" && field_name != "default_job_queue") {
138
141
  field.val(job_class_properties[field_name]);
139
142
  }
140
143
  } else if (field_name != "description") {
141
- /* No, we don't - it's probably not installed */
144
+ /* No, we don't - it's probably not installed */
142
145
  field.val(field.attr("value"));
143
146
  } else {
144
- /* Textarea fields don't have a "value" attribute */
147
+ /* Textarea fields don't have a "value" attribute */
145
148
  field.val(description_default);
146
149
  }
147
150
  if (field_name == "job_queues" || field_name == "default_job_queue") {
@@ -154,7 +157,10 @@
154
157
  });
155
158
  $("[id^=id_][id$=_override]").change();
156
159
 
157
- /* As mentioned above, we need to re-enable all checkboxes, job_queues and default_job_queue fields on form submission so they get included */
160
+ /*
161
+ * As mentioned above, we need to re-enable all checkboxes, job_queues and default_job_queue fields
162
+ * on form submission so they get included
163
+ */
158
164
  $("form").submit(function() {
159
165
  $('input[type="checkbox"]:disabled').each(function() {
160
166
  $(this).prop("disabled", false);
@@ -3,12 +3,22 @@
3
3
 
4
4
  {% block extra_styles %}
5
5
  <style>
6
+ tr a.job_run {
7
+ display: inline-flex;
8
+ gap: 0.625rem; /* 10px */
9
+ }
10
+
6
11
  tr a.job_run .btn {
7
- margin: -4px 10px 0 0;
12
+ align-self: flex-start;
13
+ margin-block: -0.09375rem; /* -1.5px */
8
14
  }
9
15
 
10
- tr.disabled {
11
- color: #7d7f7c;
16
+ tr :last-child {
17
+ margin-bottom: 0;
18
+ }
19
+
20
+ tr.disabled td {
21
+ color: var(--bs-secondary-color);
12
22
  }
13
23
 
14
24
  tr.disabled a.job_run {
@@ -17,19 +27,27 @@
17
27
  }
18
28
 
19
29
  tr.disabled a.job_run .btn {
20
- cursor: not-allowed;
30
+ cursor: inherit;
31
+ }
32
+
33
+ tr.disabled p {
34
+ color: inherit;
21
35
  }
22
36
  </style>
23
37
  {% endblock %}
24
38
 
25
39
  {% block buttons %}
26
- <div class="btn-group">
27
- <a class="btn btn-secondary set-job_list-display" data-display="tiles" href="" title="Tiles">
28
- <span class="mdi mdi-view-grid{% if display == "list" %}-outline{% endif %}"></span>
40
+ <div class="btn-group" role="group">
41
+ <a href="{% django_querystring display='list' %}"
42
+ class="btn btn-primary{% if display == 'list' %} bg-primary nb-text-body-bg{% endif %}">
43
+ <span class="mdi mdi-view-sequential" aria-hidden="true"></span> List
29
44
  </a>
30
- <a class="btn btn-secondary set-job_list-display" data-display="list" href="" title="List">
31
- <span class="mdi mdi-view-sequential{% if display == "tiles" %}-outline{% endif %}"></span>
45
+ {# djlint:off B123 #}
46
+ <a href="{% django_querystring display='tiles' %}"
47
+ class="btn btn-primary{% if display == 'tiles' %} bg-primary nb-text-body-bg{% endif %}">
48
+ <span class="mdi mdi-view-grid" aria-hidden="true"></span> Tiles
32
49
  </a>
50
+ {# djlint:on B123 #}
33
51
  </div>
34
52
 
35
53
  <button
@@ -38,22 +56,8 @@
38
56
  data-nb-toggle="collapse-all"
39
57
  data-nb-target="#job_accordion .collapse"
40
58
  type="button"
41
- {% if display == "tiles" %}disabled="disabled"{% endif %}
59
+ {% if display == "tiles" %}disabled{% endif %}
42
60
  >
43
- Collapse All
61
+ Collapse All Groups
44
62
  </button>
45
63
  {% endblock %}
46
-
47
- {% block javascript %}
48
- {{ block.super }}
49
- <script>
50
- document.addEventListener('DOMContentLoaded', () => {
51
- // Set display anchor links without losing other potentially active query params such as applied filters.
52
- [...document.querySelectorAll('.set-job_list-display')].forEach((button) => {
53
- const queryParams = new URLSearchParams(window.location.search);
54
- queryParams.set('display', button.dataset.display);
55
- button.setAttribute('href', `?${queryParams.toString()}`);
56
- });
57
- });
58
- </script>
59
- {% endblock %}
@@ -60,18 +60,14 @@
60
60
  {% block document_title %}{% render_title "plain" %}{% endblock %}
61
61
 
62
62
  {% block content %}
63
- <div class="row d-print-none">
63
+ <div class="row d-print-none mb-16">
64
64
  <div class="col-lg-12">
65
- {% render_breadcrumbs %}
65
+ <div class="float-end">
66
+ <a class="btn btn-primary" href="{% url 'apps:apps_list' %}">See Installed Apps</a>
67
+ </div>
66
68
  </div>
67
69
  </div>
68
70
 
69
- <div class="float-end d-print-none">
70
- <a class="btn btn-primary" href="{% url 'apps:apps_list' %}">See Installed Apps</a>
71
- </div>
72
-
73
- <h1>{% block page_heading %}{% render_title %}{% endblock page_heading %}</h1>
74
-
75
71
  <div class="row">
76
72
  <div class="col-lg-12">
77
73
  <section class="nb-tiles">
@@ -119,7 +115,7 @@
119
115
  {% if app.docs|default:None != None %}
120
116
  <a href="{{ app.docs }}" class="btn btn-info btn-sm" target="_blank" data-bs-title="Docs">
121
117
  {% else %}
122
- <a href="" class="btn btn-info btn-sm disabled" target="_blank" data-bs-title="No docs provided">
118
+ <a aria-disabled="true" class="btn btn-info btn-sm disabled" data-bs-title="No docs provided">
123
119
  {% endif %}
124
120
  <span class="mdi mdi-book-open-page-variant"></span>
125
121
  </a>
@@ -8,7 +8,7 @@
8
8
  <div class="card">
9
9
  <div class="card-header">
10
10
  <strong>Rendered Context</strong>
11
- {% include 'extras/inc/configcontext_format.html' %}
11
+ {% include 'extras/inc/configcontext_format.html' with data_format=format %}
12
12
  </div>
13
13
  <div class="card-body">
14
14
  {% include 'extras/inc/json_data.html' with data=rendered_context format=format %}
@@ -7,8 +7,8 @@
7
7
  {% block content %}
8
8
  <div class="alert alert-warning">
9
9
  Dynamic group membership is cached for performance reasons, therefore this page may not always be up-to-date.
10
- <br>You can refresh the membership of any specific group by viewing it from the list below or from the
11
- <a href="{% url 'extras:dynamicgroup_list' %}">Dynamic Groups list view</a>.
10
+ <br>You can refresh the membership of any specific group by accessing it from the list below or from the
11
+ <a href="{% url 'extras:dynamicgroup_list' %}">Dynamic Groups list view</a> and clicking the "Refresh Members" button.
12
12
  <br>You can also refresh the membership of all groups by running the
13
13
  <a href="{% url 'extras:job_run_by_class_path' class_path='nautobot.core.jobs.groups.RefreshDynamicGroupCaches' %}">Refresh Dynamic Group Caches job</a>.
14
14
  </div>