nautobot 2.2.9__py3-none-any.whl → 2.3.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (697) hide show
  1. nautobot/apps/forms.py +4 -0
  2. nautobot/apps/models.py +10 -1
  3. nautobot/circuits/__init__.py +0 -1
  4. nautobot/circuits/apps.py +1 -0
  5. nautobot/circuits/factory.py +15 -3
  6. nautobot/circuits/filters.py +13 -0
  7. nautobot/circuits/forms.py +13 -0
  8. nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
  9. nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
  10. nautobot/circuits/models.py +16 -3
  11. nautobot/circuits/tables.py +16 -2
  12. nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
  13. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
  15. nautobot/circuits/tests/test_api.py +7 -5
  16. nautobot/circuits/tests/test_filters.py +12 -5
  17. nautobot/circuits/tests/test_models.py +33 -2
  18. nautobot/circuits/views.py +2 -3
  19. nautobot/cloud/__init__.py +0 -0
  20. nautobot/cloud/api/__init__.py +0 -0
  21. nautobot/cloud/api/serializers.py +54 -0
  22. nautobot/cloud/api/urls.py +16 -0
  23. nautobot/cloud/api/views.py +48 -0
  24. nautobot/cloud/apps.py +13 -0
  25. nautobot/cloud/factory.py +111 -0
  26. nautobot/cloud/filters.py +184 -0
  27. nautobot/cloud/forms.py +333 -0
  28. nautobot/cloud/homepage.py +43 -0
  29. nautobot/cloud/migrations/0001_initial.py +304 -0
  30. nautobot/cloud/migrations/__init__.py +0 -0
  31. nautobot/cloud/models.py +247 -0
  32. nautobot/cloud/navigation.py +85 -0
  33. nautobot/cloud/tables.py +173 -0
  34. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
  35. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +128 -0
  36. nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
  37. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +100 -0
  38. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +65 -0
  39. nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
  40. nautobot/cloud/tests/__init__.py +0 -0
  41. nautobot/cloud/tests/test_api.py +248 -0
  42. nautobot/cloud/tests/test_filters.py +113 -0
  43. nautobot/cloud/tests/test_models.py +43 -0
  44. nautobot/cloud/tests/test_views.py +153 -0
  45. nautobot/cloud/urls.py +14 -0
  46. nautobot/cloud/views.py +181 -0
  47. nautobot/core/__init__.py +0 -3
  48. nautobot/core/api/metadata.py +1 -0
  49. nautobot/core/api/parsers.py +7 -1
  50. nautobot/core/api/urls.py +1 -0
  51. nautobot/core/api/utils.py +1 -0
  52. nautobot/core/api/views.py +4 -0
  53. nautobot/core/apps/__init__.py +6 -3
  54. nautobot/core/constants.py +8 -0
  55. nautobot/core/factory.py +32 -1
  56. nautobot/core/filters.py +96 -28
  57. nautobot/core/forms/fields.py +10 -4
  58. nautobot/core/forms/forms.py +1 -1
  59. nautobot/core/forms/widgets.py +18 -1
  60. nautobot/core/graphql/generators.py +2 -2
  61. nautobot/core/graphql/schema.py +34 -4
  62. nautobot/core/jobs/__init__.py +17 -6
  63. nautobot/core/jobs/cleanup.py +100 -0
  64. nautobot/core/jobs/groups.py +38 -0
  65. nautobot/core/management/commands/generate_test_data.py +116 -3
  66. nautobot/core/models/__init__.py +34 -9
  67. nautobot/core/models/generics.py +19 -3
  68. nautobot/core/models/name_color_content_types.py +7 -28
  69. nautobot/core/models/querysets.py +4 -3
  70. nautobot/core/models/tree_queries.py +1 -1
  71. nautobot/core/models/utils.py +21 -5
  72. nautobot/core/settings.py +4 -30
  73. nautobot/core/settings.yaml +34 -27
  74. nautobot/core/settings_funcs.py +103 -0
  75. nautobot/core/tables.py +127 -56
  76. nautobot/core/templates/admin/search_form.html +1 -1
  77. nautobot/core/templates/buttons/add.html +11 -3
  78. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
  79. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
  80. nautobot/core/templates/buttons/export.html +101 -53
  81. nautobot/core/templates/buttons/job_import.html +11 -3
  82. nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
  83. nautobot/core/templates/generic/object_bulk_update.html +3 -1
  84. nautobot/core/templates/generic/object_changelog.html +0 -9
  85. nautobot/core/templates/generic/object_list.html +156 -17
  86. nautobot/core/templates/generic/object_retrieve.html +80 -16
  87. nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
  88. nautobot/core/templates/inc/javascript.html +2 -0
  89. nautobot/core/templates/inc/media.html +2 -2
  90. nautobot/core/templates/inc/nav_menu.html +1 -0
  91. nautobot/core/templates/inc/paginator.html +7 -7
  92. nautobot/core/templates/inc/search_panel.html +2 -2
  93. nautobot/core/templates/inc/table.html +2 -2
  94. nautobot/core/templates/nautobot_config.py.j2 +13 -23
  95. nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
  96. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
  97. nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
  98. nautobot/core/templates/utilities/theme_preview.html +25 -8
  99. nautobot/core/templates/utilities/worker_status.html +152 -0
  100. nautobot/core/templatetags/buttons.py +335 -38
  101. nautobot/core/templatetags/form_helpers.py +1 -1
  102. nautobot/core/templatetags/helpers.py +181 -11
  103. nautobot/core/testing/api.py +5 -4
  104. nautobot/core/testing/filters.py +51 -13
  105. nautobot/core/testing/mixins.py +46 -0
  106. nautobot/core/testing/models.py +22 -0
  107. nautobot/core/testing/schema.py +4 -8
  108. nautobot/core/testing/views.py +31 -14
  109. nautobot/core/tests/integration/test_general_functionality.py +1 -1
  110. nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
  111. nautobot/core/tests/integration/test_swagger.py +1 -1
  112. nautobot/core/tests/nautobot_config.py +0 -1
  113. nautobot/core/tests/runner.py +2 -2
  114. nautobot/core/tests/test_api.py +1 -0
  115. nautobot/core/tests/test_authentication.py +7 -2
  116. nautobot/core/tests/test_filters.py +11 -9
  117. nautobot/core/tests/test_forms.py +9 -0
  118. nautobot/core/tests/test_graphql.py +27 -16
  119. nautobot/core/tests/test_jobs.py +123 -74
  120. nautobot/core/tests/test_tables.py +3 -1
  121. nautobot/core/tests/test_templatetags_helpers.py +12 -5
  122. nautobot/core/tests/test_utils.py +31 -20
  123. nautobot/core/tests/test_views.py +6 -6
  124. nautobot/core/urls.py +8 -3
  125. nautobot/core/utils/deprecation.py +29 -0
  126. nautobot/core/utils/filtering.py +12 -9
  127. nautobot/core/utils/lookup.py +37 -2
  128. nautobot/core/utils/requests.py +4 -1
  129. nautobot/core/views/__init__.py +137 -24
  130. nautobot/core/views/generic.py +118 -66
  131. nautobot/core/views/mixins.py +104 -35
  132. nautobot/core/views/paginator.py +9 -3
  133. nautobot/core/views/renderers.py +121 -56
  134. nautobot/core/views/utils.py +79 -1
  135. nautobot/dcim/__init__.py +0 -1
  136. nautobot/dcim/api/serializers.py +180 -44
  137. nautobot/dcim/api/urls.py +7 -3
  138. nautobot/dcim/api/views.py +53 -7
  139. nautobot/dcim/apps.py +3 -0
  140. nautobot/dcim/choices.py +25 -0
  141. nautobot/dcim/constants.py +7 -0
  142. nautobot/dcim/factory.py +249 -18
  143. nautobot/dcim/filters/__init__.py +369 -193
  144. nautobot/dcim/filters/mixins.py +274 -1
  145. nautobot/dcim/forms.py +817 -109
  146. nautobot/dcim/graphql/types.py +2 -2
  147. nautobot/dcim/homepage.py +1 -1
  148. nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
  149. nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
  150. nautobot/dcim/migrations/0061_module_models.py +861 -0
  151. nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
  152. nautobot/dcim/models/__init__.py +8 -0
  153. nautobot/dcim/models/cables.py +15 -0
  154. nautobot/dcim/models/device_component_templates.py +207 -53
  155. nautobot/dcim/models/device_components.py +275 -106
  156. nautobot/dcim/models/devices.py +466 -13
  157. nautobot/dcim/navigation.py +47 -0
  158. nautobot/dcim/signals.py +3 -3
  159. nautobot/dcim/tables/__init__.py +35 -23
  160. nautobot/dcim/tables/devices.py +231 -59
  161. nautobot/dcim/tables/devicetypes.py +65 -9
  162. nautobot/dcim/tables/racks.py +5 -1
  163. nautobot/dcim/tables/template_code.py +46 -26
  164. nautobot/dcim/templates/dcim/cable_connect.html +76 -3
  165. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
  166. nautobot/dcim/templates/dcim/device/base.html +15 -7
  167. nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
  168. nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
  169. nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
  170. nautobot/dcim/templates/dcim/device/frontports.html +2 -3
  171. nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
  172. nautobot/dcim/templates/dcim/device/inventory.html +2 -3
  173. nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
  174. nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
  175. nautobot/dcim/templates/dcim/device/powerports.html +2 -3
  176. nautobot/dcim/templates/dcim/device/rearports.html +2 -3
  177. nautobot/dcim/templates/dcim/device.html +45 -1
  178. nautobot/dcim/templates/dcim/device_component.html +13 -5
  179. nautobot/dcim/templates/dcim/device_list.html +2 -1
  180. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -6
  181. nautobot/dcim/templates/dcim/devicetype.html +99 -98
  182. nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
  183. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  184. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
  185. nautobot/dcim/templates/dcim/interface.html +17 -2
  186. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
  187. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  188. nautobot/dcim/templates/dcim/manufacturer.html +24 -0
  189. nautobot/dcim/templates/dcim/module/base.html +97 -0
  190. nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
  191. nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
  192. nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
  193. nautobot/dcim/templates/dcim/module_destroy.html +5 -0
  194. nautobot/dcim/templates/dcim/module_frontports.html +53 -0
  195. nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
  196. nautobot/dcim/templates/dcim/module_list.html +20 -0
  197. nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
  198. nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
  199. nautobot/dcim/templates/dcim/module_powerports.html +53 -0
  200. nautobot/dcim/templates/dcim/module_rearports.html +53 -0
  201. nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
  202. nautobot/dcim/templates/dcim/module_update.html +71 -0
  203. nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
  204. nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
  205. nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
  206. nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
  207. nautobot/dcim/templates/dcim/moduletype_retrieve.html +142 -0
  208. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
  209. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
  210. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  211. nautobot/dcim/tests/test_api.py +691 -208
  212. nautobot/dcim/tests/test_filters.py +836 -217
  213. nautobot/dcim/tests/test_models.py +1072 -39
  214. nautobot/dcim/tests/test_views.py +1488 -358
  215. nautobot/dcim/urls.py +17 -2
  216. nautobot/dcim/utils.py +2 -3
  217. nautobot/dcim/views.py +1107 -120
  218. nautobot/extras/__init__.py +0 -1
  219. nautobot/extras/api/serializers.py +115 -3
  220. nautobot/extras/api/urls.py +12 -0
  221. nautobot/extras/api/views.py +125 -7
  222. nautobot/extras/apps.py +2 -2
  223. nautobot/extras/choices.py +43 -0
  224. nautobot/extras/context_managers.py +13 -8
  225. nautobot/extras/datasources/git.py +2 -0
  226. nautobot/extras/factory.py +422 -9
  227. nautobot/extras/filters/__init__.py +174 -3
  228. nautobot/extras/filters/mixins.py +46 -43
  229. nautobot/extras/forms/base.py +17 -4
  230. nautobot/extras/forms/forms.py +227 -8
  231. nautobot/extras/forms/mixins.py +93 -0
  232. nautobot/extras/graphql/types.py +23 -10
  233. nautobot/extras/homepage.py +16 -13
  234. nautobot/extras/jobs.py +2 -2
  235. nautobot/extras/management/__init__.py +1 -0
  236. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
  237. nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
  238. nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
  239. nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
  240. nautobot/extras/migrations/0111_metadata.py +162 -0
  241. nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
  242. nautobot/extras/migrations/0113_saved_views.py +77 -0
  243. nautobot/extras/models/__init__.py +15 -1
  244. nautobot/extras/models/change_logging.py +3 -3
  245. nautobot/extras/models/contacts.py +4 -0
  246. nautobot/extras/models/customfields.py +18 -3
  247. nautobot/extras/models/groups.py +389 -225
  248. nautobot/extras/models/jobs.py +4 -84
  249. nautobot/extras/models/metadata.py +441 -0
  250. nautobot/extras/models/mixins.py +72 -62
  251. nautobot/extras/models/models.py +116 -9
  252. nautobot/extras/models/relationships.py +9 -2
  253. nautobot/extras/models/tags.py +13 -2
  254. nautobot/extras/navigation.py +57 -0
  255. nautobot/extras/plugins/__init__.py +3 -1
  256. nautobot/extras/querysets.py +30 -66
  257. nautobot/extras/signals.py +96 -114
  258. nautobot/extras/tables.py +171 -47
  259. nautobot/extras/templates/extras/dynamicgroup.html +44 -15
  260. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
  261. nautobot/extras/templates/extras/job.html +1 -1
  262. nautobot/extras/templates/extras/job_detail.html +0 -11
  263. nautobot/extras/templates/extras/jobresult.html +61 -74
  264. nautobot/extras/templates/extras/metadatatype_create.html +89 -0
  265. nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
  266. nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
  267. nautobot/extras/templates/extras/objectchange_list.html +0 -12
  268. nautobot/extras/templates/extras/plugins_list.html +1 -3
  269. nautobot/extras/templates/extras/role_retrieve.html +48 -0
  270. nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
  271. nautobot/extras/tests/integration/test_customfields.py +1 -0
  272. nautobot/extras/tests/test_api.py +501 -22
  273. nautobot/extras/tests/test_changelog.py +20 -9
  274. nautobot/extras/tests/test_context_managers.py +22 -15
  275. nautobot/extras/tests/test_datasources.py +13 -1
  276. nautobot/extras/tests/test_dynamicgroups.py +201 -171
  277. nautobot/extras/tests/test_filters.py +211 -12
  278. nautobot/extras/tests/test_jobs.py +4 -4
  279. nautobot/extras/tests/test_models.py +499 -4
  280. nautobot/extras/tests/test_relationships.py +1 -0
  281. nautobot/extras/tests/test_views.py +565 -28
  282. nautobot/extras/tests/test_webhooks.py +1 -1
  283. nautobot/extras/urls.py +5 -0
  284. nautobot/extras/utils.py +56 -45
  285. nautobot/extras/views.py +585 -96
  286. nautobot/ipam/__init__.py +0 -1
  287. nautobot/ipam/apps.py +1 -0
  288. nautobot/ipam/factory.py +17 -19
  289. nautobot/ipam/filters.py +14 -1
  290. nautobot/ipam/forms.py +9 -5
  291. nautobot/ipam/graphql/types.py +2 -2
  292. nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
  293. nautobot/ipam/models.py +23 -9
  294. nautobot/ipam/querysets.py +1 -1
  295. nautobot/ipam/signals.py +4 -2
  296. nautobot/ipam/tables.py +1 -0
  297. nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
  298. nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
  299. nautobot/ipam/templates/ipam/prefix.html +1 -0
  300. nautobot/ipam/tests/test_api.py +37 -18
  301. nautobot/ipam/tests/test_filters.py +26 -2
  302. nautobot/ipam/tests/test_models.py +8 -3
  303. nautobot/ipam/tests/test_querysets.py +1 -1
  304. nautobot/ipam/tests/test_views.py +3 -2
  305. nautobot/ipam/urls.py +2 -2
  306. nautobot/ipam/views.py +25 -28
  307. nautobot/project-static/css/base.css +20 -1
  308. nautobot/project-static/css/dark.css +11 -0
  309. nautobot/project-static/docs/404.html +884 -80
  310. nautobot/project-static/docs/apps/index.html +884 -80
  311. nautobot/project-static/docs/apps/nautobot-apps.html +884 -80
  312. nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
  313. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +911 -112
  314. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +896 -93
  315. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1457 -790
  316. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +927 -136
  317. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +969 -180
  318. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +893 -91
  319. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +889 -85
  320. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +983 -185
  321. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +938 -143
  322. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1064 -274
  323. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1190 -346
  324. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1663 -865
  325. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1156 -373
  326. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2200 -1502
  327. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2229 -1421
  328. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +904 -103
  329. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +955 -155
  330. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1002 -215
  331. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1911 -1275
  332. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1835 -1091
  333. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +896 -93
  334. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2323 -1693
  335. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1785 -1023
  336. nautobot/project-static/docs/development/apps/api/configuration-view.html +884 -80
  337. nautobot/project-static/docs/development/apps/api/database-backend-config.html +884 -80
  338. nautobot/project-static/docs/development/apps/api/models/django-admin.html +884 -80
  339. nautobot/project-static/docs/development/apps/api/models/global-search.html +884 -80
  340. nautobot/project-static/docs/development/apps/api/models/graphql.html +884 -80
  341. nautobot/project-static/docs/development/apps/api/models/index.html +922 -81
  342. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +884 -80
  343. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +884 -80
  344. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +884 -80
  345. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +884 -80
  346. nautobot/project-static/docs/development/apps/api/platform-features/index.html +884 -80
  347. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +884 -80
  348. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +884 -80
  349. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +884 -80
  350. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +884 -80
  351. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +884 -80
  352. nautobot/project-static/docs/development/apps/api/prometheus.html +884 -80
  353. nautobot/project-static/docs/development/apps/api/setup.html +884 -80
  354. nautobot/project-static/docs/development/apps/api/testing.html +884 -80
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +884 -80
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +884 -80
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +884 -80
  358. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +884 -80
  359. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +884 -80
  360. nautobot/project-static/docs/development/apps/api/views/base-template.html +884 -80
  361. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +884 -80
  362. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +884 -80
  363. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +884 -80
  364. nautobot/project-static/docs/development/apps/api/views/index.html +884 -80
  365. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +884 -80
  366. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +884 -80
  367. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +884 -80
  368. nautobot/project-static/docs/development/apps/api/views/notes.html +884 -80
  369. nautobot/project-static/docs/development/apps/api/views/rest-api.html +884 -80
  370. nautobot/project-static/docs/development/apps/api/views/urls.html +884 -80
  371. nautobot/project-static/docs/development/apps/index.html +884 -80
  372. nautobot/project-static/docs/development/apps/migration/code-updates.html +884 -80
  373. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +884 -80
  374. nautobot/project-static/docs/development/apps/migration/from-v1.html +884 -80
  375. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +884 -80
  376. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +884 -80
  377. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +884 -80
  378. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +884 -80
  379. nautobot/project-static/docs/development/apps/porting-from-netbox.html +884 -80
  380. nautobot/project-static/docs/development/core/application-registry.html +884 -80
  381. nautobot/project-static/docs/development/core/best-practices.html +885 -80
  382. nautobot/project-static/docs/development/core/bootstrap-ui.html +884 -80
  383. nautobot/project-static/docs/development/core/caching.html +884 -80
  384. nautobot/project-static/docs/development/core/controllers.html +884 -80
  385. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +884 -80
  386. nautobot/project-static/docs/development/core/generic-views.html +884 -80
  387. nautobot/project-static/docs/development/core/getting-started.html +884 -80
  388. nautobot/project-static/docs/development/core/homepage.html +884 -80
  389. nautobot/project-static/docs/development/core/index.html +884 -91
  390. nautobot/project-static/docs/development/core/model-checklist.html +887 -81
  391. nautobot/project-static/docs/development/core/model-features.html +884 -80
  392. nautobot/project-static/docs/development/core/natural-keys.html +884 -80
  393. nautobot/project-static/docs/development/core/navigation-menu.html +884 -80
  394. nautobot/project-static/docs/development/core/release-checklist.html +887 -83
  395. nautobot/project-static/docs/development/core/role-internals.html +884 -80
  396. nautobot/project-static/docs/development/core/settings.html +884 -80
  397. nautobot/project-static/docs/development/core/style-guide.html +885 -81
  398. nautobot/project-static/docs/development/core/templates.html +896 -81
  399. nautobot/project-static/docs/development/core/testing.html +884 -80
  400. nautobot/project-static/docs/development/core/user-preferences.html +884 -80
  401. nautobot/project-static/docs/development/index.html +884 -80
  402. nautobot/project-static/docs/development/jobs/index.html +1247 -457
  403. nautobot/project-static/docs/development/jobs/migration/from-v1.html +884 -80
  404. nautobot/project-static/docs/index.html +13 -8228
  405. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
  406. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
  407. nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
  408. nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
  409. nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
  410. nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
  411. nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
  412. nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
  413. nautobot/project-static/docs/models/dcim/module.html +15 -0
  414. nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
  415. nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
  416. nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
  417. nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
  418. nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
  419. nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
  420. nautobot/project-static/docs/models/extras/role.html +15 -0
  421. nautobot/project-static/docs/models/extras/savedview.html +15 -0
  422. nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
  423. nautobot/project-static/docs/models/extras/status.html +15 -0
  424. nautobot/project-static/docs/objects.inv +0 -0
  425. nautobot/project-static/docs/overview/application_stack.html +892 -81
  426. nautobot/project-static/docs/overview/design_philosophy.html +886 -82
  427. nautobot/project-static/docs/overview/index.html +9032 -13
  428. nautobot/project-static/docs/release-notes/index.html +887 -83
  429. nautobot/project-static/docs/release-notes/version-1.0.html +884 -80
  430. nautobot/project-static/docs/release-notes/version-1.1.html +884 -80
  431. nautobot/project-static/docs/release-notes/version-1.2.html +884 -80
  432. nautobot/project-static/docs/release-notes/version-1.3.html +884 -80
  433. nautobot/project-static/docs/release-notes/version-1.4.html +884 -80
  434. nautobot/project-static/docs/release-notes/version-1.5.html +885 -81
  435. nautobot/project-static/docs/release-notes/version-1.6.html +885 -81
  436. nautobot/project-static/docs/release-notes/version-2.0.html +884 -80
  437. nautobot/project-static/docs/release-notes/version-2.1.html +884 -80
  438. nautobot/project-static/docs/release-notes/version-2.2.html +990 -323
  439. nautobot/project-static/docs/release-notes/version-2.3.html +9524 -0
  440. nautobot/project-static/docs/requirements.txt +4 -4
  441. nautobot/project-static/docs/search/search_index.json +1 -1
  442. nautobot/project-static/docs/sitemap.xml +335 -260
  443. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  444. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +884 -80
  445. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +884 -80
  446. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +884 -80
  447. nautobot/project-static/docs/user-guide/administration/configuration/index.html +884 -80
  448. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +983 -197
  449. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +884 -80
  450. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +884 -80
  451. nautobot/project-static/docs/user-guide/administration/guides/caching.html +884 -80
  452. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +888 -84
  453. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +884 -80
  454. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +884 -80
  455. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +884 -80
  456. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +884 -80
  457. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +884 -80
  458. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +884 -80
  459. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +884 -80
  460. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +884 -80
  461. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +884 -80
  462. nautobot/project-static/docs/user-guide/administration/installation/index.html +888 -80
  463. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +884 -80
  464. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +884 -80
  465. nautobot/project-static/docs/user-guide/administration/installation/services.html +888 -80
  466. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +900 -91
  467. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +884 -80
  468. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +884 -80
  469. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +884 -80
  470. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +884 -80
  471. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +915 -163
  472. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +884 -80
  473. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +884 -80
  474. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +884 -80
  475. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +884 -80
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +884 -80
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +884 -80
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +884 -80
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +884 -80
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +884 -80
  481. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +884 -80
  482. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +884 -80
  483. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +885 -81
  484. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +884 -80
  485. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +888 -80
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +887 -83
  487. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
  488. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
  489. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
  494. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +898 -94
  495. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +915 -97
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +915 -97
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +910 -92
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +915 -97
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +898 -94
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +898 -94
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +905 -97
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +912 -108
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +913 -109
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +910 -106
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +898 -94
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +906 -97
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +918 -100
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +928 -110
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +920 -98
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +898 -94
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +929 -111
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +920 -102
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +910 -106
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +913 -109
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +914 -106
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +908 -104
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +898 -94
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +932 -75
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +916 -98
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +898 -94
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +935 -78
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +913 -95
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +921 -117
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +910 -106
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +898 -94
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +914 -96
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +916 -98
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +898 -94
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +898 -94
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +898 -94
  535. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +884 -80
  536. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +884 -80
  537. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +889 -81
  538. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +889 -81
  539. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +884 -80
  540. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +884 -80
  541. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +884 -80
  542. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +884 -80
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +884 -80
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +884 -80
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +884 -80
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +884 -80
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +884 -80
  548. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +884 -80
  549. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +893 -88
  550. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +884 -80
  551. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +884 -80
  552. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +884 -80
  553. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +884 -80
  554. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +884 -80
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +889 -81
  556. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +884 -80
  557. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +884 -80
  558. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +884 -80
  559. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +884 -80
  560. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +884 -80
  561. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +884 -80
  562. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +884 -80
  563. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +884 -80
  564. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +884 -80
  565. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +884 -80
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +884 -80
  567. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +884 -80
  568. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +884 -80
  569. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
  570. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
  571. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
  572. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
  573. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
  574. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
  575. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
  576. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
  577. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
  578. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
  579. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
  580. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
  581. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
  582. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
  583. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
  584. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
  585. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
  586. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
  587. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
  589. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
  590. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
  591. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
  592. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
  593. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
  594. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +884 -80
  595. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +884 -80
  596. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +884 -80
  597. nautobot/project-static/docs/user-guide/index.html +884 -80
  598. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +884 -80
  599. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +884 -80
  600. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +884 -80
  601. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +884 -80
  602. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1250 -777
  603. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +887 -83
  604. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +884 -80
  605. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +884 -80
  606. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +884 -80
  607. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +884 -80
  608. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +884 -80
  609. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +884 -80
  610. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +887 -83
  611. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +884 -80
  612. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +884 -80
  613. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +888 -80
  614. nautobot/project-static/docs/user-guide/platform-functionality/metadata.html +8948 -0
  615. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +887 -83
  616. nautobot/project-static/docs/user-guide/platform-functionality/note.html +884 -80
  617. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +884 -80
  618. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +884 -80
  619. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +884 -80
  620. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +884 -80
  621. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +884 -80
  622. nautobot/project-static/docs/user-guide/platform-functionality/role.html +887 -83
  623. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
  624. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +887 -83
  625. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
  626. nautobot/project-static/docs/user-guide/platform-functionality/status.html +884 -80
  627. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +884 -80
  628. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +942 -113
  629. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +884 -80
  630. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +884 -80
  631. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +884 -80
  632. nautobot/project-static/js/forms.js +71 -0
  633. nautobot/project-static/js/table_sorting_indicator.js +46 -0
  634. nautobot/project-static/js/tableconfig.js +6 -1
  635. nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
  636. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
  637. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
  638. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
  639. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
  640. nautobot/tenancy/__init__.py +0 -1
  641. nautobot/tenancy/apps.py +1 -0
  642. nautobot/tenancy/factory.py +3 -2
  643. nautobot/tenancy/filters/__init__.py +1 -0
  644. nautobot/tenancy/forms.py +1 -1
  645. nautobot/tenancy/templates/tenancy/tenant.html +22 -18
  646. nautobot/tenancy/views.py +11 -10
  647. nautobot/users/__init__.py +0 -1
  648. nautobot/users/api/serializers.py +1 -1
  649. nautobot/users/api/views.py +4 -2
  650. nautobot/users/apps.py +3 -2
  651. nautobot/users/factory.py +3 -3
  652. nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
  653. nautobot/users/models.py +12 -0
  654. nautobot/users/tests/test_filters.py +6 -3
  655. nautobot/users/urls.py +8 -0
  656. nautobot/virtualization/__init__.py +0 -1
  657. nautobot/virtualization/apps.py +1 -0
  658. nautobot/virtualization/filters.py +6 -1
  659. nautobot/virtualization/forms.py +11 -3
  660. nautobot/virtualization/graphql/types.py +2 -2
  661. nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
  662. nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
  663. nautobot/virtualization/tables.py +15 -5
  664. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  665. nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
  666. nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
  667. nautobot/virtualization/tests/test_api.py +9 -4
  668. nautobot/virtualization/tests/test_filters.py +22 -0
  669. nautobot/virtualization/tests/test_models.py +7 -3
  670. nautobot/virtualization/tests/test_views.py +19 -3
  671. nautobot/virtualization/urls.py +2 -2
  672. nautobot/virtualization/views.py +10 -32
  673. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/METADATA +21 -19
  674. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/RECORD +679 -559
  675. nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
  676. nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
  677. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
  678. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
  679. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
  680. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
  681. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
  682. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
  683. nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
  684. nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
  685. nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
  686. nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
  687. nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
  688. nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
  689. nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
  690. nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
  691. nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
  692. nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
  693. /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
  694. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/LICENSE.txt +0 -0
  695. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/NOTICE +0 -0
  696. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/WHEEL +0 -0
  697. {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/entry_points.txt +0 -0
@@ -7,14 +7,15 @@ import time
7
7
  from db_file_storage.views import get_file
8
8
  from django.apps import apps
9
9
  from django.conf import settings
10
+ from django.contrib import messages
10
11
  from django.contrib.auth.decorators import permission_required
11
- from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin
12
+ from django.contrib.auth.mixins import AccessMixin, LoginRequiredMixin, UserPassesTestMixin
12
13
  from django.contrib.contenttypes.models import ContentType
13
14
  from django.http import HttpResponseForbidden, HttpResponseServerError, JsonResponse
14
15
  from django.shortcuts import get_object_or_404, render
15
16
  from django.template import loader, RequestContext, Template
16
17
  from django.template.exceptions import TemplateDoesNotExist
17
- from django.urls import resolve, reverse
18
+ from django.urls import NoReverseMatch, resolve, reverse
18
19
  from django.utils.encoding import smart_str
19
20
  from django.views.csrf import csrf_failure as _csrf_failure
20
21
  from django.views.decorators.csrf import requires_csrf_token
@@ -37,6 +38,7 @@ from rest_framework.response import Response
37
38
  from rest_framework.versioning import AcceptHeaderVersioning
38
39
  from rest_framework.views import APIView
39
40
 
41
+ from nautobot.core.celery import app
40
42
  from nautobot.core.constants import SEARCH_MAX_RESULTS
41
43
  from nautobot.core.forms import SearchForm
42
44
  from nautobot.core.releases import get_latest_release
@@ -125,6 +127,112 @@ class HomeView(AccessMixin, TemplateView):
125
127
  return self.render_to_response(context)
126
128
 
127
129
 
130
+ class WorkerStatusView(UserPassesTestMixin, TemplateView):
131
+ template_name = "utilities/worker_status.html"
132
+
133
+ def test_func(self):
134
+ return self.request.user.is_staff
135
+
136
+ def get(self, request, *args, **kwargs):
137
+ from nautobot.extras.models import JobResult
138
+ from nautobot.extras.tables import JobResultTable
139
+
140
+ # Sort queues but move the default queue to the front so that it appears first
141
+ def sort_queues(queue):
142
+ return (queue != settings.CELERY_TASK_DEFAULT_QUEUE, queue) # False sorts before true in Python sorted
143
+
144
+ # Sort workers on hostname first, then worker name -- celery worker names are in the form name@hostname (celery@worker.example.com)
145
+ def sort_workers(worker):
146
+ return list(reversed(worker.split("@")))
147
+
148
+ # Use a long timeout to retrieve the initial list of workers
149
+ max_timeout = 60
150
+ timeout = request.GET.get("timeout", "5")
151
+ if not timeout.isdigit():
152
+ timeout = 5
153
+ elif int(timeout) > max_timeout:
154
+ timeout = max_timeout
155
+ else:
156
+ timeout = int(timeout)
157
+ celery_inspect = app.control.inspect(timeout=timeout)
158
+
159
+ # stats() returns a dict of {worker_name: stats_dict}
160
+ worker_stats = celery_inspect.stats()
161
+
162
+ if worker_stats:
163
+ # Set explicit list of workers to speed up subsequent queries
164
+ celery_inspect = app.control.inspect(list(worker_stats.keys()), timeout=5.0)
165
+
166
+ # active() returns a dict of {worker_name: [task_dict, task_dict, ...]}
167
+ active_tasks = celery_inspect.active() or {}
168
+
169
+ # reserved() returns a dict of {worker_name: [task_dict, task_dict, ...]}
170
+ reserved_tasks = celery_inspect.reserved() or {}
171
+
172
+ # active_queues() returns a dict of {worker_name: [queue_dict, queue_dict, ...]}
173
+ active_queues = celery_inspect.active_queues() or {}
174
+ else:
175
+ # No workers were found, default to empty dicts for all commands
176
+ worker_stats = active_tasks = reserved_tasks = active_queues = {}
177
+
178
+ workers = []
179
+ for worker_name in sorted(worker_stats, key=sort_workers):
180
+ worker_details = worker_stats[worker_name]
181
+ active_task_job_results = JobResult.objects.filter(
182
+ id__in=[task["id"] for task in active_tasks.get(worker_name, [])]
183
+ ).only("name", "date_created")
184
+ reserved_task_job_results = JobResult.objects.filter(
185
+ id__in=[task["id"] for task in reserved_tasks.get(worker_name, [])]
186
+ ).only("name", "date_created")
187
+ running_tasks_table = JobResultTable(
188
+ active_task_job_results, exclude=["actions", "job_model", "summary", "user", "status"]
189
+ )
190
+ pending_tasks_table = JobResultTable(
191
+ reserved_task_job_results, exclude=["actions", "job_model", "summary", "user", "status"]
192
+ )
193
+
194
+ # Sort the worker's queue list
195
+ queues = sorted([queue["name"] for queue in active_queues.get(worker_name, [])], key=sort_queues)
196
+
197
+ workers.append(
198
+ {
199
+ "hostname": worker_name,
200
+ "running_tasks_table": running_tasks_table,
201
+ "pending_tasks_table": pending_tasks_table,
202
+ "queues": queues,
203
+ "uptime": worker_details["uptime"],
204
+ }
205
+ )
206
+
207
+ # Count the number of workers per queue
208
+ queue_worker_count = {
209
+ settings.CELERY_TASK_DEFAULT_QUEUE: set(),
210
+ }
211
+ for worker_name, task_queue_list in active_queues.items():
212
+ distinct_queues = {q["name"] for q in task_queue_list}
213
+ for queue in distinct_queues:
214
+ queue_worker_count.setdefault(queue, set())
215
+ queue_worker_count[queue].add(worker_name)
216
+
217
+ # Sort the queue_worker_count dictionary by queue name, then by worker hostname/name
218
+ # Then make the default queue the first entry
219
+ queue_worker_count = {
220
+ queue_name: sorted(queue_worker_count[queue_name], key=sort_workers)
221
+ for queue_name in sorted(queue_worker_count, key=sort_queues)
222
+ }
223
+
224
+ context = {
225
+ "worker_status": {
226
+ "max_timeout": max_timeout,
227
+ "queue_worker_count": queue_worker_count,
228
+ "timeout": timeout,
229
+ "workers": workers,
230
+ },
231
+ }
232
+
233
+ return self.render_to_response(context)
234
+
235
+
128
236
  class ThemePreviewView(LoginRequiredMixin, TemplateView):
129
237
  template_name = "utilities/theme_preview.html"
130
238
 
@@ -132,6 +240,8 @@ class ThemePreviewView(LoginRequiredMixin, TemplateView):
132
240
  return {
133
241
  "content_type": ContentType.objects.get_for_model(Status),
134
242
  "object": Status.objects.first(),
243
+ "verbose_name": Status.objects.all().model._meta.verbose_name,
244
+ "verbose_name_plural": Status.objects.all().model._meta.verbose_name_plural,
135
245
  }
136
246
 
137
247
 
@@ -177,28 +287,31 @@ class SearchView(AccessMixin, View):
177
287
  # corresponding to that URL, and finally the queryset, filterset, and table classes needed
178
288
  # to find and display the model search results.
179
289
  url = get_route_for_model(f"{label}.{modelname}", "list")
180
- view_func = resolve(reverse(url)).func
181
- # For a UIViewSet, view_func.cls gets what we need; for an ObjectListView, view_func.view_class is it.
182
- view_or_viewset = getattr(view_func, "cls", getattr(view_func, "view_class", None))
183
- queryset = view_or_viewset.queryset.restrict(request.user, "view")
184
- # For a UIViewSet, .filterset_class, for an ObjectListView, .filterset.
185
- filterset = getattr(view_or_viewset, "filterset_class", getattr(view_or_viewset, "filterset", None))
186
- # For a UIViewSet, .table_class, for an ObjectListView, .table.
187
- table = getattr(view_or_viewset, "table_class", getattr(view_or_viewset, "table", None))
188
-
189
- # Construct the results table for this object type
190
- filtered_queryset = filterset({"q": form.cleaned_data["q"]}, queryset=queryset).qs
191
- table = table(filtered_queryset, orderable=False)
192
- table.paginate(per_page=SEARCH_MAX_RESULTS)
193
-
194
- if table.page:
195
- results.append(
196
- {
197
- "name": queryset.model._meta.verbose_name_plural,
198
- "table": table,
199
- "url": f"{reverse(url)}?q={form.cleaned_data.get('q')}",
200
- }
201
- )
290
+ try:
291
+ view_func = resolve(reverse(url)).func
292
+ # For UIViewSet, view_func.cls gets what we need; for an ObjectListView, view_func.view_class is it.
293
+ view_or_viewset = getattr(view_func, "cls", getattr(view_func, "view_class", None))
294
+ queryset = view_or_viewset.queryset.restrict(request.user, "view")
295
+ # For a UIViewSet, .filterset_class, for an ObjectListView, .filterset.
296
+ filterset = getattr(view_or_viewset, "filterset_class", getattr(view_or_viewset, "filterset", None))
297
+ # For a UIViewSet, .table_class, for an ObjectListView, .table.
298
+ table = getattr(view_or_viewset, "table_class", getattr(view_or_viewset, "table", None))
299
+
300
+ # Construct the results table for this object type
301
+ filtered_queryset = filterset({"q": form.cleaned_data["q"]}, queryset=queryset).qs
302
+ table = table(filtered_queryset, orderable=False)
303
+ table.paginate(per_page=SEARCH_MAX_RESULTS)
304
+
305
+ if table.page:
306
+ results.append(
307
+ {
308
+ "name": queryset.model._meta.verbose_name_plural,
309
+ "table": table,
310
+ "url": f"{reverse(url)}?q={form.cleaned_data.get('q')}",
311
+ }
312
+ )
313
+ except NoReverseMatch:
314
+ messages.error(request, f'Missing URL "{url}" - unable to show search results for {modelname}.')
202
315
 
203
316
  return render(
204
317
  request,
@@ -5,6 +5,7 @@ import re
5
5
  from django.conf import settings
6
6
  from django.contrib import messages
7
7
  from django.contrib.auth.mixins import LoginRequiredMixin
8
+ from django.contrib.auth.models import AnonymousUser
8
9
  from django.contrib.contenttypes.models import ContentType
9
10
  from django.core.exceptions import (
10
11
  FieldDoesNotExist,
@@ -12,10 +13,11 @@ from django.core.exceptions import (
12
13
  ValidationError,
13
14
  )
14
15
  from django.db import IntegrityError, transaction
15
- from django.db.models import ManyToManyField, ProtectedError
16
+ from django.db.models import ManyToManyField, ProtectedError, Q
16
17
  from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput
17
- from django.http import HttpResponse, JsonResponse
18
+ from django.http import HttpResponse
18
19
  from django.shortcuts import get_object_or_404, redirect, render
20
+ from django.urls import reverse
19
21
  from django.utils.encoding import iri_to_uri
20
22
  from django.utils.html import format_html
21
23
  from django.utils.http import url_has_allowed_host_and_scheme
@@ -38,7 +40,6 @@ from nautobot.core.forms import (
38
40
  from nautobot.core.forms.forms import DynamicFilterFormSet
39
41
  from nautobot.core.templatetags.helpers import bettertitle, validated_viewname
40
42
  from nautobot.core.utils.config import get_settings_or_config
41
- from nautobot.core.utils.lookup import get_created_and_last_updated_usernames_for_model
42
43
  from nautobot.core.utils.permissions import get_permission_for_model
43
44
  from nautobot.core.utils.requests import (
44
45
  convert_querydict_to_factory_formset_acceptable_querydict,
@@ -49,14 +50,15 @@ from nautobot.core.views.mixins import GetReturnURLMixin, ObjectPermissionRequir
49
50
  from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
50
51
  from nautobot.core.views.utils import (
51
52
  check_filter_for_display,
53
+ common_detail_view_context,
52
54
  get_csv_form_fields_from_serializer_class,
53
55
  handle_protectederror,
54
56
  import_csv_helper,
55
57
  prepare_cloned_fields,
58
+ view_changes_not_saved,
56
59
  )
57
60
  from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
58
- from nautobot.extras.models import ContactAssociation, ExportTemplate
59
- from nautobot.extras.tables import AssociatedContactsTable
61
+ from nautobot.extras.models import ExportTemplate, SavedView, UserSavedViewAssociation
60
62
  from nautobot.extras.utils import bulk_delete_with_bulk_change_logging, remove_prefix_from_cf_key
61
63
 
62
64
 
@@ -111,53 +113,17 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
111
113
  Generic GET handler for accessing an object.
112
114
  """
113
115
  instance = get_object_or_404(self.queryset, **kwargs)
114
- # Get the ObjectChange records to populate the advanced tab information
115
- created_by, last_updated_by = get_created_and_last_updated_usernames_for_model(instance)
116
-
117
- # TODO: this feels inelegant - should the tabs lookup be a dedicated endpoint rather than piggybacking
118
- # on the object-retrieve endpoint?
119
- # TODO: similar functionality probably needed in NautobotUIViewSet as well, not currently present
120
- if request.GET.get("viewconfig", None) == "true":
121
- # TODO: we shouldn't be importing a private-named function from another module. Should it be renamed?
122
- from nautobot.extras.templatetags.plugins import _get_registered_content
123
-
124
- temp_fake_context = {
125
- "object": instance,
126
- "request": request,
127
- "settings": {},
128
- "csrf_token": "",
129
- "perms": {},
130
- }
116
+ content_type = ContentType.objects.get_for_model(self.queryset.model)
117
+ context = {
118
+ "object": instance,
119
+ "content_type": content_type,
120
+ "verbose_name": self.queryset.model._meta.verbose_name,
121
+ "verbose_name_plural": self.queryset.model._meta.verbose_name_plural,
122
+ **common_detail_view_context(request, instance),
123
+ **self.get_extra_context(request, instance),
124
+ }
131
125
 
132
- plugin_tabs = _get_registered_content(instance, "detail_tabs", temp_fake_context, return_html=False)
133
- resp = {"tabs": plugin_tabs}
134
- return JsonResponse(resp)
135
- else:
136
- content_type = ContentType.objects.get_for_model(self.queryset.model)
137
- context = {
138
- "object": instance,
139
- "content_type": content_type,
140
- "verbose_name": self.queryset.model._meta.verbose_name,
141
- "verbose_name_plural": self.queryset.model._meta.verbose_name_plural,
142
- "created_by": created_by,
143
- "last_updated_by": last_updated_by,
144
- **self.get_extra_context(request, instance),
145
- }
146
- if instance.is_contact_associable_model:
147
- paginate = {"paginator_class": EnhancedPaginator, "per_page": get_paginate_count(request)}
148
- associations = (
149
- ContactAssociation.objects.filter(
150
- associated_object_id=instance.id,
151
- associated_object_type=content_type,
152
- )
153
- .restrict(request.user, "view")
154
- .order_by("role__name")
155
- )
156
- associations_table = AssociatedContactsTable(associations, orderable=False)
157
- RequestConfig(request, paginate).configure(associations_table)
158
- associations_table.columns.show("pk")
159
- context["associated_contacts_table"] = associations_table
160
- return render(request, self.get_template_name(), context)
126
+ return render(request, self.get_template_name(), context)
161
127
 
162
128
 
163
129
  class ObjectListView(ObjectPermissionRequiredMixin, View):
@@ -184,12 +150,19 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
184
150
  "page", # used by django-tables2.RequestConfig
185
151
  "per_page", # used by get_paginate_count
186
152
  "sort", # table sorting
153
+ "saved_view", # saved_view indicator pk or composite keys
154
+ "table_changes_pending", # indicator for if there is any table changes not applied to the saved view
155
+ "all_filters_removed", # indicator for if all filters have been removed from the saved view
156
+ "clear_view", # indicator for if the clear view button is clicked or not
187
157
  )
188
158
 
189
159
  def get_filter_params(self, request):
190
160
  """Helper function - take request.GET and discard any parameters that are not used for queryset filtering."""
191
- filter_params = request.GET.copy()
192
- return get_filterable_params_from_filter_params(filter_params, self.non_filter_params, self.filterset())
161
+ params = request.GET.copy()
162
+ filter_params = get_filterable_params_from_filter_params(params, self.non_filter_params, self.filterset())
163
+ if params.get("saved_view") and not filter_params and not params.get("all_filters_removed"):
164
+ return SavedView.objects.get(pk=params.get("saved_view")).config.get("filter_params", {})
165
+ return filter_params
193
166
 
194
167
  def get_required_permission(self):
195
168
  return get_permission_for_model(self.queryset.model, "view")
@@ -225,10 +198,41 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
225
198
  model = self.queryset.model
226
199
  content_type = ContentType.objects.get_for_model(model)
227
200
 
201
+ filter_params = request.GET
202
+ user = request.user
228
203
  display_filter_params = []
229
204
  dynamic_filter_form = None
230
205
  filter_form = None
231
206
  hide_hierarchy_ui = False
207
+ clear_view = request.GET.get("clear_view", False)
208
+
209
+ # If the user clicks on the clear view button, we do not check for global or user defaults
210
+ if not clear_view and not request.GET.get("saved_view"):
211
+ # Check if there is a default for this view for this specific user
212
+ app_label, model_name = model._meta.label.split(".")
213
+ view_name = f"{app_label}:{model_name.lower()}_list"
214
+
215
+ if not isinstance(user, AnonymousUser):
216
+ try:
217
+ user_default_saved_view_pk = UserSavedViewAssociation.objects.get(
218
+ user=user, view_name=view_name
219
+ ).saved_view.pk
220
+ # Saved view should either belong to the user or be public
221
+ SavedView.objects.get(
222
+ Q(pk=user_default_saved_view_pk),
223
+ Q(owner=user) | Q(is_shared=True),
224
+ )
225
+ sv_url = reverse("extras:savedview", kwargs={"pk": user_default_saved_view_pk})
226
+ return redirect(sv_url)
227
+ except ObjectDoesNotExist:
228
+ pass
229
+
230
+ # Check if there is a global default for this view
231
+ try:
232
+ global_saved_view = SavedView.objects.get(view=view_name, is_global_default=True)
233
+ return redirect(reverse("extras:savedview", kwargs={"pk": global_saved_view.pk}))
234
+ except ObjectDoesNotExist:
235
+ pass
232
236
 
233
237
  if self.filterset:
234
238
  filter_params = self.get_filter_params(request)
@@ -254,7 +258,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
254
258
 
255
259
  if request.GET:
256
260
  factory_formset_params = convert_querydict_to_factory_formset_acceptable_querydict(
257
- request.GET, filterset
261
+ filter_params, filterset
258
262
  )
259
263
  dynamic_filter_form = DynamicFilterFormSet(filterset=filterset, data=factory_formset_params)
260
264
  else:
@@ -296,18 +300,50 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
296
300
 
297
301
  table = None
298
302
  table_config_form = None
303
+ current_saved_view = None
304
+ current_saved_view_pk = self.request.GET.get("saved_view", None)
305
+ list_url = validated_viewname(model, "list")
306
+ # We are not using .restrict(request.user, "view") here
307
+ # User should be able to see any saved view that he has the list view access to.
308
+ if user.has_perms(["extras.view_savedview"]):
309
+ saved_views = SavedView.objects.filter(view=list_url).order_by("name").only("pk", "name")
310
+ else:
311
+ shared_saved_views = (
312
+ SavedView.objects.filter(view=list_url, is_shared=True).order_by("name").only("pk", "name")
313
+ )
314
+ user_owned_saved_views = (
315
+ SavedView.objects.filter(view=list_url, owner=user).order_by("name").only("pk", "name")
316
+ )
317
+ saved_views = shared_saved_views | user_owned_saved_views
299
318
  if self.table:
300
319
  # Construct the objects table
301
- if self.request.GET.getlist("sort"):
320
+ if current_saved_view_pk:
321
+ try:
322
+ # We are not using .restrict(request.user, "view") here
323
+ # User should be able to see any saved view that he has the list view access to.
324
+ current_saved_view = SavedView.objects.get(view=list_url, pk=current_saved_view_pk)
325
+ except ObjectDoesNotExist:
326
+ messages.error(request, f"Saved view {current_saved_view_pk} not found")
327
+ if self.request.GET.getlist("sort") or (
328
+ current_saved_view is not None and current_saved_view.config.get("sort_order")
329
+ ):
302
330
  hide_hierarchy_ui = True # hide tree hierarchy if custom sort is used
303
- table = self.table(self.queryset, user=request.user, hide_hierarchy_ui=hide_hierarchy_ui)
331
+ table_changes_pending = self.request.GET.get("table_changes_pending", False)
332
+
333
+ table = self.table(
334
+ self.queryset,
335
+ table_changes_pending=table_changes_pending,
336
+ saved_view=current_saved_view,
337
+ user=request.user,
338
+ hide_hierarchy_ui=hide_hierarchy_ui,
339
+ )
304
340
  if "pk" in table.base_columns and (permissions["change"] or permissions["delete"]):
305
341
  table.columns.show("pk")
306
342
 
307
343
  # Apply the request context
308
344
  paginate = {
309
345
  "paginator_class": EnhancedPaginator,
310
- "per_page": get_paginate_count(request),
346
+ "per_page": get_paginate_count(request, current_saved_view),
311
347
  }
312
348
  RequestConfig(request, paginate).configure(table)
313
349
  table_config_form = TableConfigForm(table=table)
@@ -320,10 +356,13 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
320
356
 
321
357
  # For the search form field, use a custom placeholder.
322
358
  q_placeholder = "Search " + bettertitle(model._meta.verbose_name_plural)
323
- search_form = SearchForm(data=request.GET, q_placeholder=q_placeholder)
359
+ search_form = SearchForm(data=filter_params, q_placeholder=q_placeholder)
324
360
 
325
361
  valid_actions = self.validate_action_buttons(request)
326
362
 
363
+ # Query SavedViews for dropdown button
364
+ new_changes_not_applied = view_changes_not_saved(request, self, current_saved_view)
365
+
327
366
  context = {
328
367
  "content_type": content_type,
329
368
  "table": table,
@@ -334,8 +373,12 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
334
373
  "filter_form": filter_form,
335
374
  "dynamic_filter_form": dynamic_filter_form,
336
375
  "search_form": search_form,
337
- "list_url": validated_viewname(model, "list"),
376
+ "list_url": list_url,
338
377
  "title": bettertitle(model._meta.verbose_name_plural),
378
+ "new_changes_not_applied": new_changes_not_applied,
379
+ "current_saved_view": current_saved_view,
380
+ "saved_views": saved_views,
381
+ "model": model,
339
382
  }
340
383
 
341
384
  # `extra_context()` would require `request` access, however `request` parameter cannot simply be
@@ -439,7 +482,12 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
439
482
  def post(self, request, *args, **kwargs):
440
483
  logger = logging.getLogger(__name__ + ".ObjectEditView")
441
484
  obj = self.alter_obj(self.get_object(kwargs), request, args, kwargs)
442
- form = self.model_form(data=request.POST, files=request.FILES, instance=obj)
485
+ form = self.model_form(
486
+ data=request.POST,
487
+ files=request.FILES,
488
+ initial=normalize_querydict(request.GET, form_class=self.model_form),
489
+ instance=obj,
490
+ )
443
491
  restrict_form_fields(form, request.user)
444
492
 
445
493
  if form.is_valid():
@@ -752,7 +800,9 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
752
800
 
753
801
  related_obj_pks = []
754
802
  for i, rel_obj_data in enumerate(data.get(field_name, [])):
755
- f = related_object_form(obj, rel_obj_data)
803
+ # add parent object key to related object data
804
+ rel_obj_data[obj._meta.verbose_name.replace(" ", "_")] = str(obj.pk)
805
+ f = related_object_form(rel_obj_data)
756
806
 
757
807
  for subfield_name, field in f.fields.items():
758
808
  if subfield_name not in rel_obj_data and hasattr(field, "initial"):
@@ -1210,7 +1260,7 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
1210
1260
  Delete objects in bulk.
1211
1261
 
1212
1262
  queryset: Custom queryset to use when retrieving objects (e.g. to select related objects)
1213
- filter: FilterSet to apply when deleting by QuerySet
1263
+ filterset: FilterSet to apply when deleting by QuerySet
1214
1264
  table: The table used to display devices being deleted
1215
1265
  form: The form class used to delete objects in bulk
1216
1266
  template_name: The name of the template
@@ -1336,7 +1386,7 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
1336
1386
  return get_permission_for_model(self.queryset.model, "add")
1337
1387
 
1338
1388
  def get(self, request):
1339
- form = self.form(initial=request.GET)
1389
+ form = self.form(initial=normalize_querydict(request.GET, form_class=self.form))
1340
1390
  model_form = self.model_form(request.GET)
1341
1391
 
1342
1392
  return render(
@@ -1352,8 +1402,8 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
1352
1402
 
1353
1403
  def post(self, request):
1354
1404
  logger = logging.getLogger(__name__ + ".ComponentCreateView")
1355
- form = self.form(request.POST, initial=request.GET)
1356
- model_form = self.model_form(request.POST)
1405
+ form = self.form(request.POST, initial=normalize_querydict(request.GET, form_class=self.form))
1406
+ model_form = self.model_form(request.POST, initial=normalize_querydict(request.GET, form_class=self.model_form))
1357
1407
 
1358
1408
  if form.is_valid():
1359
1409
  new_components = []
@@ -1368,7 +1418,9 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
1368
1418
  data["label"] = label
1369
1419
  if hasattr(form, "get_iterative_data"):
1370
1420
  data.update(form.get_iterative_data(i))
1371
- component_form = self.model_form(data)
1421
+ component_form = self.model_form(
1422
+ data, initial=normalize_querydict(request.GET, form_class=self.model_form)
1423
+ )
1372
1424
 
1373
1425
  if component_form.is_valid():
1374
1426
  new_components.append(component_form)