nautobot 3.0.0a2__py3-none-any.whl → 3.0.0a3__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.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (420) hide show
  1. nautobot/apps/choices.py +0 -2
  2. nautobot/apps/filters.py +7 -9
  3. nautobot/apps/models.py +2 -2
  4. nautobot/apps/ui.py +9 -1
  5. nautobot/circuits/filters.py +3 -2
  6. nautobot/circuits/navigation.py +3 -2
  7. nautobot/circuits/templates/circuits/circuit.html +1 -1
  8. nautobot/circuits/templates/circuits/circuit_create.html +3 -3
  9. nautobot/circuits/templates/circuits/circuittermination.html +1 -1
  10. nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
  11. nautobot/circuits/templates/circuits/circuittype.html +1 -1
  12. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
  13. nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
  14. nautobot/circuits/templates/circuits/providernetwork.html +1 -1
  15. nautobot/circuits/tests/integration/test_circuit.py +10 -13
  16. nautobot/cloud/filters.py +1 -1
  17. nautobot/cloud/navigation.py +3 -2
  18. nautobot/core/api/schema.py +1 -1
  19. nautobot/core/api/serializers.py +6 -1
  20. nautobot/core/api/urls.py +1 -0
  21. nautobot/core/api/views.py +8 -0
  22. nautobot/core/apps/__init__.py +11 -10
  23. nautobot/core/celery/__init__.py +3 -5
  24. nautobot/core/checks.py +46 -0
  25. nautobot/core/cli/bootstrap_v3_to_v5.py +70 -1
  26. nautobot/core/cli/migrate_deprecated_templates.py +200 -0
  27. nautobot/core/constants.py +3 -0
  28. nautobot/core/context_processors.py +9 -1
  29. nautobot/core/forms/forms.py +1 -1
  30. nautobot/core/jobs/__init__.py +6 -3
  31. nautobot/core/jobs/groups.py +31 -1
  32. nautobot/core/management/commands/generate_test_data.py +28 -9
  33. nautobot/core/models/generics.py +9 -1
  34. nautobot/core/models/tree_queries.py +10 -5
  35. nautobot/core/settings.py +18 -12
  36. nautobot/core/settings.yaml +13 -7
  37. nautobot/core/signals.py +12 -1
  38. nautobot/core/tables.py +13 -6
  39. nautobot/core/templates/40x.html +1 -1
  40. nautobot/core/templates/500.html +2 -2
  41. nautobot/core/templates/admin/config/config.html +12 -12
  42. nautobot/core/templates/admin/index.html +3 -3
  43. nautobot/core/templates/buttons/export.html +1 -1
  44. nautobot/core/templates/components/button/dropdown.html +5 -3
  45. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
  46. nautobot/core/templates/components/panel/panel.html +3 -3
  47. nautobot/core/templates/components/tab/content_wrapper.html +2 -3
  48. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
  49. nautobot/core/templates/echarts/echarts.html +1 -1
  50. nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
  51. nautobot/core/templates/generic/object_bulk_create.html +4 -3
  52. nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
  53. nautobot/core/templates/generic/object_bulk_remove.html +2 -2
  54. nautobot/core/templates/generic/object_bulk_update.html +5 -4
  55. nautobot/core/templates/generic/object_create.html +5 -4
  56. nautobot/core/templates/generic/object_import.html +2 -1
  57. nautobot/core/templates/generic/object_list.html +12 -4
  58. nautobot/core/templates/generic/object_notes.html +5 -3
  59. nautobot/core/templates/generic/object_retrieve.html +2 -3
  60. nautobot/core/templates/graphene/graphiql.html +7 -7
  61. nautobot/core/templates/home.html +1 -1
  62. nautobot/core/templates/import_success.html +2 -1
  63. nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
  64. nautobot/core/templates/inc/created_updated.html +7 -3
  65. nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
  66. nautobot/core/templates/inc/form_static_field.html +6 -0
  67. nautobot/core/templates/inc/header.html +1 -1
  68. nautobot/core/templates/inc/image_attachments.html +2 -1
  69. nautobot/core/templates/inc/nav_menu.html +2 -1
  70. nautobot/core/templates/inc/search_panel.html +4 -4
  71. nautobot/core/templates/login.html +4 -2
  72. nautobot/core/templates/nautobot_config.py.j2 +6 -5
  73. nautobot/core/templates/redoc_ui.html +7 -0
  74. nautobot/core/templates/search.html +1 -1
  75. nautobot/core/templates/swagger_ui.html +17 -3
  76. nautobot/core/templates/system_jobs/import_objects.html +1 -2
  77. nautobot/core/templates/utilities/confirmation_form.html +2 -2
  78. nautobot/core/templates/utilities/obj_table.html +10 -2
  79. nautobot/core/templates/utilities/render_field.html +7 -7
  80. nautobot/core/templates/utilities/render_jinja2.html +2 -2
  81. nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +4 -4
  82. nautobot/core/templates/utilities/theme_preview.html +16 -3
  83. nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
  84. nautobot/core/templatetags/helpers.py +52 -6
  85. nautobot/core/testing/api.py +68 -9
  86. nautobot/core/testing/filters.py +0 -23
  87. nautobot/core/testing/integration.py +23 -10
  88. nautobot/core/testing/mixins.py +2 -0
  89. nautobot/core/testing/views.py +4 -0
  90. nautobot/core/tests/integration/test_app_home.py +34 -30
  91. nautobot/core/tests/integration/test_app_navbar.py +3 -0
  92. nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
  93. nautobot/core/tests/runner.py +9 -1
  94. nautobot/core/tests/test_api.py +5 -3
  95. nautobot/core/tests/test_breadcrumbs.py +6 -7
  96. nautobot/core/tests/test_checks.py +28 -0
  97. nautobot/core/tests/test_cli.py +40 -0
  98. nautobot/core/tests/test_config.py +2 -1
  99. nautobot/core/tests/test_forms.py +55 -13
  100. nautobot/core/tests/test_jobs.py +75 -1
  101. nautobot/core/tests/test_nautobot_server.py +2 -0
  102. nautobot/core/tests/test_navigations.py +76 -1
  103. nautobot/core/tests/test_patch_social_django.py +42 -0
  104. nautobot/core/tests/test_tables.py +3 -1
  105. nautobot/core/tests/test_templatetags_helpers.py +53 -13
  106. nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
  107. nautobot/core/tests/test_tree_queries.py +14 -1
  108. nautobot/core/tests/test_ui.py +1 -1
  109. nautobot/core/tests/test_utils.py +31 -4
  110. nautobot/core/tests/test_views.py +159 -31
  111. nautobot/core/ui/breadcrumbs.py +2 -12
  112. nautobot/core/ui/choices.py +142 -10
  113. nautobot/core/ui/constants.py +76 -12
  114. nautobot/core/ui/object_detail.py +92 -12
  115. nautobot/core/urls.py +12 -1
  116. nautobot/core/utils/cache.py +2 -1
  117. nautobot/core/utils/filtering.py +17 -17
  118. nautobot/core/utils/lookup.py +3 -8
  119. nautobot/core/utils/module_loading.py +21 -0
  120. nautobot/core/utils/patch_social_django.py +128 -0
  121. nautobot/core/views/__init__.py +38 -1
  122. nautobot/core/views/generic.py +3 -3
  123. nautobot/core/views/mixins.py +15 -3
  124. nautobot/core/views/renderers.py +2 -0
  125. nautobot/core/views/viewsets.py +2 -1
  126. nautobot/data_validation/apps.py +1 -5
  127. nautobot/data_validation/custom_validators.py +4 -4
  128. nautobot/data_validation/filters.py +1 -1
  129. nautobot/data_validation/forms.py +40 -0
  130. nautobot/data_validation/migrations/0001_initial.py +0 -7
  131. nautobot/data_validation/migrations/0002_data_migration_from_app.py +0 -12
  132. nautobot/data_validation/models.py +16 -7
  133. nautobot/data_validation/navigation.py +8 -1
  134. nautobot/data_validation/tables.py +12 -5
  135. nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
  136. nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
  137. nautobot/data_validation/tests/__init__.py +2 -2
  138. nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
  139. nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
  140. nautobot/data_validation/tests/test_filters.py +8 -6
  141. nautobot/data_validation/tests/test_models.py +15 -0
  142. nautobot/data_validation/tests/test_views.py +190 -32
  143. nautobot/data_validation/urls.py +2 -5
  144. nautobot/data_validation/views.py +73 -40
  145. nautobot/dcim/api/serializers.py +0 -13
  146. nautobot/dcim/apps.py +4 -0
  147. nautobot/dcim/choices.py +16 -0
  148. nautobot/dcim/custom_validators.py +84 -0
  149. nautobot/dcim/filter_mixins.py +353 -4
  150. nautobot/dcim/{filters/__init__.py → filters.py} +2 -35
  151. nautobot/dcim/forms.py +1 -1
  152. nautobot/dcim/migrations/0078_remove_device_location_tenant_name_uniqueness.py +16 -0
  153. nautobot/dcim/migrations/0079_device_name_data_migration.py +59 -0
  154. nautobot/dcim/models/device_components.py +81 -68
  155. nautobot/dcim/models/devices.py +13 -16
  156. nautobot/dcim/navigation.py +7 -6
  157. nautobot/dcim/tables/devices.py +3 -0
  158. nautobot/dcim/tables/template_code.py +14 -14
  159. nautobot/dcim/templates/dcim/cable.html +2 -61
  160. nautobot/dcim/templates/dcim/cable_connect.html +28 -112
  161. nautobot/dcim/templates/dcim/cable_edit.html +2 -5
  162. nautobot/dcim/templates/dcim/cable_retrieve.html +61 -0
  163. nautobot/dcim/templates/dcim/cable_trace.html +1 -3
  164. nautobot/dcim/templates/dcim/cable_update.html +5 -0
  165. nautobot/dcim/templates/dcim/consoleport.html +6 -5
  166. nautobot/dcim/templates/dcim/consoleserverport.html +6 -5
  167. nautobot/dcim/templates/dcim/device/config.html +2 -2
  168. nautobot/dcim/templates/dcim/device/consoleports.html +1 -1
  169. nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -1
  170. nautobot/dcim/templates/dcim/device/devicebays.html +1 -1
  171. nautobot/dcim/templates/dcim/device/frontports.html +1 -1
  172. nautobot/dcim/templates/dcim/device/interfaces.html +1 -1
  173. nautobot/dcim/templates/dcim/device/inventory.html +1 -1
  174. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
  175. nautobot/dcim/templates/dcim/device/modulebays.html +1 -1
  176. nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -1
  177. nautobot/dcim/templates/dcim/device/powerports.html +1 -1
  178. nautobot/dcim/templates/dcim/device/rearports.html +1 -1
  179. nautobot/dcim/templates/dcim/device/status.html +8 -8
  180. nautobot/dcim/templates/dcim/device/wireless.html +1 -1
  181. nautobot/dcim/templates/dcim/device.html +1 -1
  182. nautobot/dcim/templates/dcim/device_component_add.html +2 -2
  183. nautobot/dcim/templates/dcim/device_create.html +5 -3
  184. nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
  185. nautobot/dcim/templates/dcim/device_list.html +73 -10
  186. nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
  187. nautobot/dcim/templates/dcim/devicetype.html +1 -1
  188. nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
  189. nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
  190. nautobot/dcim/templates/dcim/frontport.html +9 -8
  191. nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
  192. nautobot/dcim/templates/dcim/interface.html +26 -6
  193. nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
  194. nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
  195. nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
  196. nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
  197. nautobot/dcim/templates/dcim/location_retrieve.html +1 -242
  198. nautobot/dcim/templates/dcim/module/base.html +49 -9
  199. nautobot/dcim/templates/dcim/module_list.html +57 -8
  200. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  201. nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
  202. nautobot/dcim/templates/dcim/platform_create.html +1 -1
  203. nautobot/dcim/templates/dcim/powerfeed.html +1 -1
  204. nautobot/dcim/templates/dcim/powerpanel.html +1 -1
  205. nautobot/dcim/templates/dcim/powerport.html +5 -4
  206. nautobot/dcim/templates/dcim/rack_elevation_list.html +16 -4
  207. nautobot/dcim/templates/dcim/rack_retrieve.html +33 -15
  208. nautobot/dcim/templates/dcim/rearport.html +7 -6
  209. nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
  210. nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
  211. nautobot/dcim/templates/dcim/virtualchassis_update.html +14 -6
  212. nautobot/dcim/tests/integration/test_controller.py +1 -0
  213. nautobot/dcim/tests/test_api.py +8 -0
  214. nautobot/dcim/tests/test_custom_validators.py +229 -0
  215. nautobot/dcim/tests/test_filters.py +12 -6
  216. nautobot/dcim/tests/test_models.py +63 -4
  217. nautobot/dcim/tests/test_views.py +63 -22
  218. nautobot/dcim/urls.py +64 -21
  219. nautobot/dcim/utils.py +3 -3
  220. nautobot/dcim/views.py +547 -273
  221. nautobot/extras/api/views.py +9 -1
  222. nautobot/extras/choices.py +2 -13
  223. nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
  224. nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
  225. nautobot/extras/{filters/__init__.py → filters.py} +14 -46
  226. nautobot/extras/forms/forms.py +5 -13
  227. nautobot/extras/forms/mixins.py +0 -41
  228. nautobot/extras/management/__init__.py +9 -0
  229. nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
  230. nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
  231. nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
  232. nautobot/extras/models/__init__.py +1 -2
  233. nautobot/extras/models/approvals.py +22 -13
  234. nautobot/extras/models/contacts.py +2 -0
  235. nautobot/extras/models/groups.py +44 -5
  236. nautobot/extras/models/jobs.py +59 -1
  237. nautobot/extras/models/mixins.py +28 -0
  238. nautobot/extras/models/models.py +13 -0
  239. nautobot/extras/models/secrets.py +1 -0
  240. nautobot/extras/models/statuses.py +0 -15
  241. nautobot/extras/navigation.py +13 -9
  242. nautobot/extras/plugins/__init__.py +33 -55
  243. nautobot/extras/plugins/tables.py +3 -3
  244. nautobot/extras/plugins/urls.py +2 -21
  245. nautobot/extras/plugins/utils.py +1 -33
  246. nautobot/extras/plugins/views.py +0 -4
  247. nautobot/extras/signals.py +20 -19
  248. nautobot/extras/tables.py +52 -68
  249. nautobot/extras/templates/extras/approval_dashboard.html +7 -5
  250. nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
  251. nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
  252. nautobot/extras/templates/extras/computedfield.html +1 -1
  253. nautobot/extras/templates/extras/configcontext.html +1 -1
  254. nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
  255. nautobot/extras/templates/extras/customfield.html +1 -1
  256. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
  257. nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
  258. nautobot/extras/templates/extras/gitrepository_result.html +0 -2
  259. nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -96
  260. nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
  261. nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
  262. nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
  263. nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
  264. nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
  265. nautobot/extras/templates/extras/inc/json_format.html +10 -3
  266. nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
  267. nautobot/extras/templates/extras/job.html +29 -12
  268. nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
  269. nautobot/extras/templates/extras/job_edit.html +52 -46
  270. nautobot/extras/templates/extras/job_list.html +29 -25
  271. nautobot/extras/templates/extras/marketplace.html +5 -9
  272. nautobot/extras/templates/extras/object_configcontext.html +1 -1
  273. nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
  274. nautobot/extras/templates/extras/objectchange_retrieve.html +19 -37
  275. nautobot/extras/templates/extras/plugin_detail.html +26 -21
  276. nautobot/extras/templates/extras/plugins_list.html +16 -26
  277. nautobot/extras/templates/extras/role_retrieve.html +64 -0
  278. nautobot/extras/templates/extras/scheduledjob.html +4 -2
  279. nautobot/extras/templates/extras/secretsgroup.html +1 -1
  280. nautobot/extras/templates/extras/tag.html +1 -1
  281. nautobot/extras/templatetags/custom_links.py +12 -12
  282. nautobot/extras/templatetags/job_buttons.py +14 -12
  283. nautobot/extras/test_jobs/invalid_import.py +9 -0
  284. nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
  285. nautobot/extras/test_jobs/missing_import.py +11 -0
  286. nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
  287. nautobot/extras/tests/integration/test_customfields.py +8 -7
  288. nautobot/extras/tests/integration/test_dynamicgroups.py +5 -1
  289. nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
  290. nautobot/extras/tests/integration/test_plugins.py +18 -6
  291. nautobot/extras/tests/test_api.py +27 -18
  292. nautobot/extras/tests/test_approvals.py +38 -38
  293. nautobot/extras/tests/test_changelog.py +35 -3
  294. nautobot/extras/tests/test_customfields.py +22 -13
  295. nautobot/extras/tests/test_customfields_filters.py +479 -0
  296. nautobot/extras/tests/test_dynamicgroups.py +39 -1
  297. nautobot/extras/tests/test_filters.py +21 -19
  298. nautobot/extras/tests/test_forms.py +18 -21
  299. nautobot/extras/tests/test_jobs.py +25 -4
  300. nautobot/extras/tests/test_migrations.py +1 -0
  301. nautobot/extras/tests/test_models.py +13 -31
  302. nautobot/extras/tests/test_plugins.py +36 -10
  303. nautobot/extras/tests/test_views.py +31 -30
  304. nautobot/extras/views.py +81 -19
  305. nautobot/ipam/factory.py +7 -0
  306. nautobot/ipam/filter_mixins.py +38 -0
  307. nautobot/ipam/filters.py +27 -38
  308. nautobot/ipam/formfields.py +1 -1
  309. nautobot/ipam/forms.py +6 -3
  310. nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
  311. nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
  312. nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
  313. nautobot/ipam/models.py +29 -2
  314. nautobot/ipam/navigation.py +3 -2
  315. nautobot/ipam/signals.py +71 -0
  316. nautobot/ipam/tables.py +13 -6
  317. nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
  318. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
  319. nautobot/ipam/templates/ipam/ipaddress.html +14 -0
  320. nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
  321. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
  322. nautobot/ipam/templates/ipam/namespace_update.html +15 -0
  323. nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
  324. nautobot/ipam/templates/ipam/prefix_list.html +14 -13
  325. nautobot/ipam/templates/ipam/service.html +1 -1
  326. nautobot/ipam/templates/ipam/vlan.html +1 -1
  327. nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
  328. nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
  329. nautobot/ipam/tests/migration/test_migrations.py +89 -0
  330. nautobot/ipam/tests/test_api.py +13 -6
  331. nautobot/ipam/tests/test_filters.py +10 -0
  332. nautobot/ipam/tests/test_forms.py +1 -1
  333. nautobot/ipam/tests/test_models.py +43 -1
  334. nautobot/ipam/tests/test_tables.py +1 -2
  335. nautobot/ipam/tests/test_utils.py +1 -1
  336. nautobot/ipam/tests/test_views.py +13 -14
  337. nautobot/ipam/ui.py +0 -17
  338. nautobot/ipam/utils/migrations.py +16 -2
  339. nautobot/ipam/utils/testing.py +9 -3
  340. nautobot/ipam/views.py +46 -6
  341. nautobot/project-static/dist/css/nautobot.css +1 -1
  342. nautobot/project-static/dist/css/nautobot.css.map +1 -1
  343. nautobot/project-static/dist/js/nautobot.js +1 -1
  344. nautobot/project-static/dist/js/nautobot.js.map +1 -1
  345. nautobot/project-static/js/cabletrace.js +1 -1
  346. nautobot/project-static/js/interface_filtering.js +20 -16
  347. nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
  348. nautobot/project-static/nautobot-icons/cloud.svg +1 -1
  349. nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
  350. nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
  351. nautobot/project-static/nautobot-icons/elements.svg +1 -1
  352. nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
  353. nautobot/project-static/nautobot-icons/hammer.svg +1 -1
  354. nautobot/project-static/nautobot-icons/organization.svg +3 -0
  355. nautobot/project-static/nautobot-icons/secrets.svg +1 -1
  356. nautobot/project-static/nautobot-icons/security.svg +3 -0
  357. nautobot/project-static/nautobot-icons/server.svg +1 -1
  358. nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
  359. nautobot/project-static/nautobot-icons/star.svg +1 -1
  360. nautobot/tenancy/api/serializers.py +1 -0
  361. nautobot/tenancy/api/views.py +2 -1
  362. nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
  363. nautobot/tenancy/navigation.py +3 -1
  364. nautobot/tenancy/tests/test_filters.py +0 -2
  365. nautobot/tenancy/views.py +2 -1
  366. nautobot/ui/src/js/collapse.js +3 -3
  367. nautobot/ui/src/js/nautobot.js +16 -0
  368. nautobot/ui/src/scss/colors.scss +1 -1
  369. nautobot/ui/src/scss/nautobot.scss +61 -28
  370. nautobot/users/templates/users/profile.html +45 -12
  371. nautobot/users/templates/users/sessionkey_delete.html +1 -1
  372. nautobot/users/tests/test_api.py +4 -0
  373. nautobot/users/views.py +4 -2
  374. nautobot/virtualization/models.py +1 -68
  375. nautobot/virtualization/navigation.py +3 -2
  376. nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
  377. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  378. nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
  379. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
  380. nautobot/virtualization/tests/test_api.py +3 -0
  381. nautobot/virtualization/tests/test_models.py +44 -4
  382. nautobot/vpn/__init__.py +0 -0
  383. nautobot/vpn/api/serializers.py +113 -0
  384. nautobot/vpn/api/urls.py +19 -0
  385. nautobot/vpn/api/views.py +70 -0
  386. nautobot/vpn/apps.py +8 -0
  387. nautobot/vpn/choices.py +171 -0
  388. nautobot/vpn/factory.py +209 -0
  389. nautobot/vpn/filters.py +233 -0
  390. nautobot/vpn/forms.py +486 -0
  391. nautobot/vpn/homepage.py +19 -0
  392. nautobot/vpn/migrations/0001_initial.py +541 -0
  393. nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
  394. nautobot/vpn/migrations/__init__.py +0 -0
  395. nautobot/vpn/models.py +527 -0
  396. nautobot/vpn/navigation.py +98 -0
  397. nautobot/vpn/tables.py +380 -0
  398. nautobot/vpn/templates/vpn/vpnprofile.html +2 -0
  399. nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
  400. nautobot/vpn/tests/__init__.py +0 -0
  401. nautobot/vpn/tests/test_api.py +341 -0
  402. nautobot/vpn/tests/test_filters.py +139 -0
  403. nautobot/vpn/tests/test_forms.py +294 -0
  404. nautobot/vpn/tests/test_models.py +97 -0
  405. nautobot/vpn/tests/test_views.py +281 -0
  406. nautobot/vpn/urls.py +16 -0
  407. nautobot/vpn/views.py +437 -0
  408. nautobot/wireless/navigation.py +3 -2
  409. nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
  410. nautobot/wireless/tests/test_api.py +1 -1
  411. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +14 -14
  412. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +417 -366
  413. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
  414. nautobot/data_validation/template_content.py +0 -42
  415. nautobot/dcim/filters/mixins.py +0 -354
  416. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
  417. /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
  418. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
  419. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
  420. {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
@@ -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>
@@ -4,36 +4,6 @@
4
4
 
5
5
  {% block title %}{{ object }} - Change Log{% endblock %}
6
6
 
7
- {% block header %}
8
- <div class="row d-print-none">
9
- <div class="col-md-8 col-lg-9">
10
- <ol class="breadcrumb">
11
- <li class="breadcrumb-item"><a href="{% url 'extras:objectchange_list' %}">Change Log</a></li>
12
- {% if object.related_object.get_absolute_url %}
13
- <li class="breadcrumb-item"><a href="{{ object.related_object.get_absolute_url }}changelog/">{{ object.related_object }}</a></li>
14
- {% elif object.changed_object and object.changed_object.get_absolute_url %}
15
- <li class="breadcrumb-item"><a href="{{ object.changed_object.get_absolute_url }}changelog/">{{ object.changed_object }}</a></li>
16
- {% elif object.changed_object is not None %}
17
- <li class="breadcrumb-item">{{ object.changed_object }}</li>
18
- {% endif %}
19
- <li class="breadcrumb-item">{{ object }}</li>
20
- </ol>
21
- </div>
22
- <div class="col-md-4 col-lg-3">
23
- <form action="{% url 'extras:objectchange_list' %}" method="get">
24
- <div class="input-group">
25
- <input type="text" name="q" class="form-control" placeholder="Search change logs" />
26
- <span class="input-group-btn">
27
- <button type="submit" class="btn btn-primary">
28
- <span class="mdi mdi-magnify" aria-hidden="true"></span>
29
- </button>
30
- </span>
31
- </div>
32
- </form>
33
- </div>
34
- </div>
35
- {% endblock %}
36
-
37
7
  {% block content %}
38
8
  <div class="row">
39
9
  <div class="col-lg-5">
@@ -113,13 +83,25 @@
113
83
  <div class="card">
114
84
  <div class="card-header">
115
85
  <strong>Difference</strong>
116
- <div class="btn-group btn-group-xs float-end d-print-none">
117
- <a {% if prev_change %}href="{% url 'extras:objectchange' pk=prev_change.pk %}"{% else %}disabled{% endif %} class="btn btn-secondary">
118
- <span class="mdi mdi-chevron-left" aria-hidden="true"></span> Previous
119
- </a>
120
- <a {% if next_change %}href="{% url 'extras:objectchange' pk=next_change.pk %}"{% else %}disabled{% endif %} class="btn btn-secondary">
121
- Next <span class="mdi mdi-chevron-right" aria-hidden="true"></span>
122
- </a>
86
+ <div class="btn-group btn-group-sm float-end d-print-none" role="group">
87
+ {% if prev_change %}
88
+ <a href="{% url 'extras:objectchange' pk=prev_change.pk %}" class="btn btn-secondary">
89
+ <span class="mdi mdi-chevron-left" aria-hidden="true"></span> Previous
90
+ </a>
91
+ {% else %}
92
+ <a aria-disabled="true" class="btn btn-secondary disabled">
93
+ <span class="mdi mdi-chevron-left" aria-hidden="true"></span> Previous
94
+ </a>
95
+ {% endif %}
96
+ {% if next_change %}
97
+ <a href="{% url 'extras:objectchange' pk=next_change.pk %}" class="btn btn-secondary">
98
+ Next <span class="mdi mdi-chevron-right" aria-hidden="true"></span>
99
+ </a>
100
+ {% else %}
101
+ <a aria-disabled="true" class="btn btn-secondary disabled">
102
+ Next <span class="mdi mdi-chevron-right" aria-hidden="true"></span>
103
+ </a>
104
+ {% endif %}
123
105
  </div>
124
106
  </div>
125
107
  <div class="card-body">
@@ -4,29 +4,34 @@
4
4
 
5
5
  {% block breadcrumbs_wrapper %}{% render_breadcrumbs %}{% endblock breadcrumbs_wrapper %}
6
6
 
7
- {% block header %}
8
- <div class="float-end d-print-none">
9
- {% block buttons %}
10
- {% if app_data.home_url %}
11
- <a href="{% url app_data.home_url %}" class="btn btn-primary">
12
- <span class="mdi mdi-home"></span> App Home
13
- </a>
14
- {% endif %}
15
- {% if app_data.config_url %}
16
- <a href="{% url app_data.config_url %}" class="btn btn-warning">
17
- <span class="mdi mdi-cog"></span> App Configuration
18
- </a>
19
- {% endif %}
20
- {% if app_data.docs_url %}
21
- <a href="{% url app_data.docs_url %}" class="btn btn-info">
22
- <span class="mdi mdi-cog"></span> App Documentation
23
- </a>
24
- {% endif %}
25
- {% endblock buttons %}
26
- </div>
27
- {% endblock header %}
7
+ {% block header %}{% endblock header %}
28
8
 
29
9
  {% block content %}
10
+
11
+ <div class="row d-print-none mb-16">
12
+ <div class="col-lg-12">
13
+ <div class="float-end d-print-none">
14
+ {% block buttons %}
15
+ {% if app_data.home_url %}
16
+ <a href="{% url app_data.home_url %}" class="btn btn-primary">
17
+ <span class="mdi mdi-home"></span> App Home
18
+ </a>
19
+ {% endif %}
20
+ {% if app_data.config_url %}
21
+ <a href="{% url app_data.config_url %}" class="btn btn-warning">
22
+ <span class="mdi mdi-cog"></span> App Configuration
23
+ </a>
24
+ {% endif %}
25
+ {% if app_data.docs_url %}
26
+ <a href="{% url app_data.docs_url %}" class="btn btn-info">
27
+ <span class="mdi mdi-cog"></span> App Documentation
28
+ </a>
29
+ {% endif %}
30
+ {% endblock buttons %}
31
+ </div>
32
+ </div>
33
+ </div>
34
+
30
35
  <div class="row">
31
36
  <div class="col-lg-6">
32
37
  {% block content_left_page %}
@@ -8,27 +8,26 @@
8
8
  {% endblock %}
9
9
 
10
10
  {% block content %}
11
- <div class="row d-print-none">
11
+ <div class="row d-print-none mb-16">
12
12
  <div class="col-lg-12">
13
- {% render_breadcrumbs %}
14
- </div>
15
- </div>
13
+ <div class="float-end d-print-none">
14
+ <div class="btn-group" role="group">
15
+ <a href="{% django_querystring display='list' %}"
16
+ class="btn btn-primary{% if display == 'list' %} bg-primary nb-text-body-bg{% endif %}">
17
+ <span class="mdi mdi-view-sequential" aria-hidden="true"></span> List
18
+ </a>
19
+ {# djlint:off B123 #}
20
+ <a href="{% django_querystring display='tiles' %}"
21
+ class="btn btn-primary{% if display == 'tiles' %} bg-primary nb-text-body-bg{% endif %}">
22
+ <span class="mdi mdi-view-grid" aria-hidden="true"></span> Tiles
23
+ </a>
24
+ {# djlint:on B123 #}
25
+ </div>
16
26
 
17
- <div class="float-end d-print-none">
18
- <div class="btn-group">
19
- <a class="btn btn-secondary set-apps-display" data-display="tiles" href="" title="Tiles">
20
- <span class="mdi mdi-view-grid{% if display == "list" %}-outline{% endif %}"></span>
21
- </a>
22
- <a class="btn btn-secondary set-apps-display" data-display="list" href="" title="List">
23
- <span class="mdi mdi-view-sequential{% if display == "tiles" %}-outline{% endif %}"></span>
24
- </a>
27
+ <a class="btn btn-primary" href="{% url 'apps:apps_marketplace' %}">Visit Apps Marketplace</a>
28
+ </div>
25
29
  </div>
26
-
27
- <a class="btn btn-primary" href="{% url 'apps:apps_marketplace' %}">Visit Apps Marketplace</a>
28
30
  </div>
29
-
30
- <h1>{% block page_heading %}{% render_title %}{% endblock %}</h1>
31
-
32
31
  <div class="row">
33
32
  <div class="col-lg-12">
34
33
  {% if filter_form %}
@@ -47,13 +46,4 @@
47
46
  {% block javascript %}
48
47
  {{ block.super }}
49
48
  <script src="{% static 'js/tableconfig.js' %}"></script>
50
-
51
- <script>
52
- // Set display anchor links without losing other potentially active query params such as applied filters.
53
- [...document.querySelectorAll('.set-apps-display')].forEach(button => {
54
- const queryParams = new URLSearchParams(window.location.search);
55
- queryParams.set('display', button.dataset.display);
56
- button.setAttribute('href', `?${queryParams.toString()}`);
57
- });
58
- </script>
59
49
  {% endblock %}
@@ -223,4 +223,68 @@
223
223
  </div>
224
224
  {% include 'inc/paginator.html' with paginator=vdc_table.paginator page=vdc_table.page %}
225
225
  {% endif %}
226
+ {% if vpn_table %}
227
+ <div class="card">
228
+ <div class="card-header">
229
+ <strong>VPNs</strong>
230
+ </div>
231
+ {% include 'inc/table.html' with table=vpn_table %}
232
+ {% if perms.vpn.add_vpn %}
233
+ <div class="card-footer text-end d-print-none">
234
+ <a href="{% url 'vpn:vpn_add' %}?role={{ object.pk }}" class="btn btn-sm btn-primary">
235
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VPN
236
+ </a>
237
+ </div>
238
+ {% endif %}
239
+ </div>
240
+ {% include 'inc/paginator.html' with paginator=vpn_table.paginator page=vpn_table.page %}
241
+ {% endif %}
242
+ {% if vpn_profile_table %}
243
+ <div class="card">
244
+ <div class="card-header">
245
+ <strong>VPN Profiles</strong>
246
+ </div>
247
+ {% include 'inc/table.html' with table=vpn_profile_table %}
248
+ {% if perms.vpn.add_vpnprofile %}
249
+ <div class="card-footer text-end d-print-none">
250
+ <a href="{% url 'vpn:vpnprofile_add' %}?role={{ object.pk }}" class="btn btn-sm btn-primary">
251
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VPN Profile
252
+ </a>
253
+ </div>
254
+ {% endif %}
255
+ </div>
256
+ {% include 'inc/paginator.html' with paginator=vpn_profile_table.paginator page=vpn_profile_table.page %}
257
+ {% endif %}
258
+ {% if vpn_tunnel_table %}
259
+ <div class="card">
260
+ <div class="card-header">
261
+ <strong>VPN Tunnels</strong>
262
+ </div>
263
+ {% include 'inc/table.html' with table=vpn_tunnel_table %}
264
+ {% if perms.vpn.add_vpntunnel %}
265
+ <div class="card-footer text-end d-print-none">
266
+ <a href="{% url 'vpn:vpntunnel_add' %}?role={{ object.pk }}" class="btn btn-sm btn-primary">
267
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VPN Tunnel
268
+ </a>
269
+ </div>
270
+ {% endif %}
271
+ </div>
272
+ {% include 'inc/paginator.html' with paginator=vpn_tunnel_table.paginator page=vpn_tunnel_table.page %}
273
+ {% endif %}
274
+ {% if vpn_tunnel_endpoint_table %}
275
+ <div class="card">
276
+ <div class="card-header">
277
+ <strong>VPN Tunnel Endpoints</strong>
278
+ </div>
279
+ {% include 'inc/table.html' with table=vpn_tunnel_endpoint_table %}
280
+ {% if perms.vpn.add_vpntunnelendpoint %}
281
+ <div class="card-footer text-end d-print-none">
282
+ <a href="{% url 'vpn:vpntunnelendpoint_add' %}?role={{ object.pk }}" class="btn btn-sm btn-primary">
283
+ <span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VPN Tunnel Endpoint
284
+ </a>
285
+ </div>
286
+ {% endif %}
287
+ </div>
288
+ {% include 'inc/paginator.html' with paginator=vpn_tunnel_endpoint_table.paginator page=vpn_tunnel_endpoint_table.page %}
289
+ {% endif %}
226
290
  {% endblock content_full_width_page %}
@@ -102,7 +102,8 @@
102
102
  <td>
103
103
  {{ object.start_time|timezone:object.time_zone|date:settings.SHORT_DATETIME_FORMAT }}
104
104
  {% if default_time_zone != object.time_zone %}
105
- <br>{{ object.start_time|timezone:default_time_zone|date:settings.SHORT_DATETIME_FORMAT }}
105
+ {{ object.time_zone }}
106
+ <br>{{ object.start_time|timezone:default_time_zone|date:settings.SHORT_DATETIME_FORMAT }} {{ default_time_zone }}
106
107
  {% endif %}
107
108
  </td>
108
109
  </tr>
@@ -112,7 +113,8 @@
112
113
  {% if object.last_run_at %}
113
114
  {{ object.last_run_at|timezone:object.time_zone|date:settings.SHORT_DATETIME_FORMAT }}
114
115
  {% if default_time_zone != object.time_zone %}
115
- <br>{{ object.last_run_at|timezone:default_time_zone|date:SHORT_DATETIME_FORMAT }}
116
+ {{ object.time_zone }}
117
+ <br>{{ object.last_run_at|timezone:default_time_zone|date:settings.SHORT_DATETIME_FORMAT }} {{ default_time_zone }}
116
118
  {% endif %}
117
119
  {% else %}
118
120
  {{ object.last_run_at|placeholder }}
@@ -1,2 +1,2 @@
1
- {% extends "extras/secretsgroup_retrieve.html" %}
1
+ {% extends "generic/object_retrieve.html" %}
2
2
  {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,2 +1,2 @@
1
- {% extends 'extras/tag_retrieve.html' %}
1
+ {% extends 'generic/object_retrieve.html' %}
2
2
  {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}