nautobot 2.4.14__py3-none-any.whl → 2.4.15__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 (433) hide show
  1. nautobot/apps/choices.py +8 -0
  2. nautobot/apps/ui.py +14 -0
  3. nautobot/core/api/views.py +2 -0
  4. nautobot/core/choices.py +4 -0
  5. nautobot/core/filters.py +21 -41
  6. nautobot/core/management/commands/check_job_approval_status.py +47 -0
  7. nautobot/core/management/commands/generate_test_data.py +1 -1
  8. nautobot/core/management/commands/migrate.py +1 -1
  9. nautobot/core/models/tree_queries.py +17 -0
  10. nautobot/core/settings.py +2 -2
  11. nautobot/core/tables.py +25 -2
  12. nautobot/core/templates/base_django.html +1 -1
  13. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  14. nautobot/core/templates/generic/object_list.html +17 -20
  15. nautobot/core/templates/inc/breadcrumbs.html +14 -0
  16. nautobot/core/templatetags/buttons.py +2 -4
  17. nautobot/core/templatetags/helpers.py +29 -6
  18. nautobot/core/templatetags/ui_framework.py +21 -0
  19. nautobot/core/testing/filters.py +20 -3
  20. nautobot/core/testing/forms.py +1 -1
  21. nautobot/core/tests/integration/test_filters.py +2 -2
  22. nautobot/core/tests/test_breadcrumbs.py +366 -0
  23. nautobot/core/tests/test_commands.py +40 -0
  24. nautobot/core/tests/test_filters.py +51 -1
  25. nautobot/core/tests/test_forms.py +1 -1
  26. nautobot/core/tests/test_graphql.py +4 -4
  27. nautobot/core/tests/test_titles.py +183 -0
  28. nautobot/core/tests/test_tree_queries.py +30 -0
  29. nautobot/core/tests/test_views.py +2 -2
  30. nautobot/core/tests/test_views_utils.py +1 -1
  31. nautobot/core/ui/breadcrumbs.py +538 -0
  32. nautobot/core/ui/bulk_buttons.py +53 -0
  33. nautobot/core/ui/object_detail.py +31 -8
  34. nautobot/core/ui/titles.py +127 -0
  35. nautobot/core/ui/utils.py +25 -0
  36. nautobot/core/utils/migrations.py +1 -1
  37. nautobot/core/views/__init__.py +1 -1
  38. nautobot/core/views/mixins.py +26 -1
  39. nautobot/core/views/renderers.py +20 -2
  40. nautobot/core/views/utils.py +13 -12
  41. nautobot/dcim/api/serializers.py +9 -0
  42. nautobot/dcim/choices.py +53 -0
  43. nautobot/dcim/filters/__init__.py +15 -3
  44. nautobot/dcim/forms.py +120 -7
  45. nautobot/dcim/management/commands/trace_paths.py +1 -1
  46. nautobot/dcim/migrations/0072_alter_powerfeed_options_and_more.py +97 -0
  47. nautobot/dcim/models/device_component_templates.py +8 -0
  48. nautobot/dcim/models/device_components.py +31 -12
  49. nautobot/dcim/models/devices.py +1 -1
  50. nautobot/dcim/models/power.py +171 -10
  51. nautobot/dcim/models/racks.py +7 -4
  52. nautobot/dcim/tables/devices.py +2 -0
  53. nautobot/dcim/tables/devicetypes.py +1 -0
  54. nautobot/dcim/tables/power.py +30 -2
  55. nautobot/dcim/templates/dcim/device.html +2 -2
  56. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -214
  57. nautobot/dcim/templates/dcim/location_retrieve.html +2 -2
  58. nautobot/dcim/templates/dcim/powerfeed_edit.html +8 -0
  59. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -1
  60. nautobot/dcim/tests/integration/test_device_bulk_operations.py +61 -0
  61. nautobot/dcim/tests/test_api.py +24 -4
  62. nautobot/dcim/tests/test_filters.py +91 -13
  63. nautobot/dcim/tests/test_models.py +262 -0
  64. nautobot/dcim/tests/test_views.py +20 -12
  65. nautobot/dcim/utils.py +9 -0
  66. nautobot/dcim/views.py +390 -77
  67. nautobot/extras/factory.py +19 -20
  68. nautobot/extras/filters/__init__.py +3 -2
  69. nautobot/extras/filters/mixins.py +15 -1
  70. nautobot/extras/forms/__init__.py +2 -1
  71. nautobot/extras/forms/forms.py +62 -0
  72. nautobot/extras/managers.py +4 -1
  73. nautobot/extras/migrations/0125_jobresult_date_started.py +18 -0
  74. nautobot/extras/models/customfields.py +1 -2
  75. nautobot/extras/models/datasources.py +1 -2
  76. nautobot/extras/models/jobs.py +7 -3
  77. nautobot/extras/plugins/views.py +24 -1
  78. nautobot/extras/secrets/__init__.py +1 -1
  79. nautobot/extras/tables.py +9 -0
  80. nautobot/extras/templates/extras/customfield.html +2 -129
  81. nautobot/extras/templates/extras/customfield_edit.html +2 -108
  82. nautobot/extras/templates/extras/customfield_retrieve.html +129 -0
  83. nautobot/extras/templates/extras/customfield_update.html +108 -0
  84. nautobot/extras/templates/extras/inc/jobresult.html +7 -3
  85. nautobot/extras/templates/extras/jobresult.html +2 -155
  86. nautobot/extras/templates/extras/jobresult_retrieve.html +155 -0
  87. nautobot/extras/templates/extras/marketplace.html +5 -6
  88. nautobot/extras/templates/extras/note.html +2 -53
  89. nautobot/extras/templates/extras/note_retrieve.html +53 -0
  90. nautobot/extras/templates/extras/plugins_list.html +5 -6
  91. nautobot/extras/templatetags/custom_links.py +2 -2
  92. nautobot/extras/templatetags/job_buttons.py +1 -1
  93. nautobot/extras/templatetags/plugins.py +1 -1
  94. nautobot/extras/tests/integration/test_computedfields.py +2 -2
  95. nautobot/extras/tests/integration/test_customfields.py +14 -11
  96. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  97. nautobot/extras/tests/integration/test_notes.py +1 -1
  98. nautobot/extras/tests/integration/test_plugins.py +6 -6
  99. nautobot/extras/tests/integration/test_relationships.py +2 -2
  100. nautobot/extras/tests/test_filters.py +9 -0
  101. nautobot/extras/tests/test_forms.py +2 -2
  102. nautobot/extras/tests/test_plugins.py +2 -3
  103. nautobot/extras/tests/test_relationships.py +7 -7
  104. nautobot/extras/tests/test_views.py +172 -1
  105. nautobot/extras/urls.py +3 -59
  106. nautobot/extras/utils.py +1 -1
  107. nautobot/extras/views.py +77 -178
  108. nautobot/ipam/tables.py +8 -15
  109. nautobot/ipam/tests/migration/test_migrations.py +8 -8
  110. nautobot/ipam/tests/test_api.py +2 -2
  111. nautobot/ipam/tests/test_models.py +1 -1
  112. nautobot/project-static/docs/404.html +23 -0
  113. nautobot/project-static/docs/apps/index.html +23 -0
  114. nautobot/project-static/docs/apps/nautobot-apps.html +23 -0
  115. nautobot/project-static/docs/assets/_mkdocstrings.css +44 -6
  116. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +28 -0
  117. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +25 -0
  118. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +128 -20
  119. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +37 -4
  120. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +39 -6
  121. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +25 -0
  122. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +24 -0
  123. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +32 -5
  124. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +41 -8
  125. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +39 -7
  126. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +43 -10
  127. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +74 -59
  128. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +143 -28
  129. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +43 -12
  130. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +135 -53
  131. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +229 -36
  132. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +27 -1
  133. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +30 -1
  134. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +162 -18
  135. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +258 -51
  136. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5987 -2620
  137. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +25 -0
  138. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +154 -55
  139. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +150 -35
  140. nautobot/project-static/docs/development/apps/api/configuration-view.html +23 -0
  141. nautobot/project-static/docs/development/apps/api/database-backend-config.html +23 -0
  142. nautobot/project-static/docs/development/apps/api/models/django-admin.html +23 -0
  143. nautobot/project-static/docs/development/apps/api/models/global-search.html +23 -0
  144. nautobot/project-static/docs/development/apps/api/models/graphql.html +23 -0
  145. nautobot/project-static/docs/development/apps/api/models/index.html +23 -0
  146. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +23 -0
  147. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +23 -0
  148. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +23 -0
  149. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +23 -0
  150. nautobot/project-static/docs/development/apps/api/platform-features/index.html +23 -0
  151. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +23 -0
  152. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +23 -0
  153. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +23 -0
  154. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +23 -0
  155. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +23 -0
  156. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +23 -0
  157. nautobot/project-static/docs/development/apps/api/prometheus.html +23 -0
  158. nautobot/project-static/docs/development/apps/api/setup.html +23 -0
  159. nautobot/project-static/docs/development/apps/api/testing.html +23 -0
  160. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +23 -0
  161. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +23 -0
  162. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +23 -0
  163. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +23 -0
  164. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +23 -0
  165. nautobot/project-static/docs/development/apps/api/views/base-template.html +23 -0
  166. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +23 -0
  167. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +23 -0
  168. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +23 -0
  169. nautobot/project-static/docs/development/apps/api/views/index.html +23 -0
  170. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +23 -0
  171. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -2
  172. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +23 -0
  173. nautobot/project-static/docs/development/apps/api/views/notes.html +23 -0
  174. nautobot/project-static/docs/development/apps/api/views/rest-api.html +23 -0
  175. nautobot/project-static/docs/development/apps/api/views/urls.html +23 -0
  176. nautobot/project-static/docs/development/apps/index.html +23 -0
  177. nautobot/project-static/docs/development/apps/migration/code-updates.html +23 -0
  178. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +23 -0
  179. nautobot/project-static/docs/development/apps/migration/from-v1.html +23 -0
  180. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +23 -0
  181. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +23 -0
  182. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +23 -0
  183. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +23 -0
  184. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +26 -3
  185. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +10544 -0
  186. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +23 -0
  187. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +23 -0
  188. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +23 -0
  189. nautobot/project-static/docs/development/apps/porting-from-netbox.html +26 -3
  190. nautobot/project-static/docs/development/core/application-registry.html +23 -0
  191. nautobot/project-static/docs/development/core/best-practices.html +23 -0
  192. nautobot/project-static/docs/development/core/bootstrap-ui.html +23 -0
  193. nautobot/project-static/docs/development/core/caching.html +23 -0
  194. nautobot/project-static/docs/development/core/controllers.html +23 -0
  195. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +23 -0
  196. nautobot/project-static/docs/development/core/generic-views.html +23 -0
  197. nautobot/project-static/docs/development/core/getting-started.html +23 -0
  198. nautobot/project-static/docs/development/core/homepage.html +23 -0
  199. nautobot/project-static/docs/development/core/index.html +23 -0
  200. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +23 -0
  201. nautobot/project-static/docs/development/core/model-checklist.html +23 -0
  202. nautobot/project-static/docs/development/core/model-features.html +23 -0
  203. nautobot/project-static/docs/development/core/natural-keys.html +23 -0
  204. nautobot/project-static/docs/development/core/navigation-menu.html +23 -0
  205. nautobot/project-static/docs/development/core/release-checklist.html +23 -0
  206. nautobot/project-static/docs/development/core/role-internals.html +23 -0
  207. nautobot/project-static/docs/development/core/settings.html +23 -0
  208. nautobot/project-static/docs/development/core/style-guide.html +23 -0
  209. nautobot/project-static/docs/development/core/templates.html +23 -0
  210. nautobot/project-static/docs/development/core/testing.html +23 -0
  211. nautobot/project-static/docs/development/core/ui-component-framework.html +713 -255
  212. nautobot/project-static/docs/development/core/user-preferences.html +23 -0
  213. nautobot/project-static/docs/development/index.html +23 -0
  214. nautobot/project-static/docs/development/jobs/getting-started.html +23 -0
  215. nautobot/project-static/docs/development/jobs/index.html +23 -0
  216. nautobot/project-static/docs/development/jobs/installation.html +23 -0
  217. nautobot/project-static/docs/development/jobs/job-extensions.html +23 -0
  218. nautobot/project-static/docs/development/jobs/job-logging.html +23 -0
  219. nautobot/project-static/docs/development/jobs/job-patterns.html +23 -0
  220. nautobot/project-static/docs/development/jobs/job-structure.html +23 -0
  221. nautobot/project-static/docs/development/jobs/migration/from-v1.html +23 -0
  222. nautobot/project-static/docs/development/jobs/testing.html +23 -0
  223. nautobot/project-static/docs/index.html +23 -0
  224. nautobot/project-static/docs/media/development/core/ui-component-framework/breadcrumbs-titles-data-flow.png +0 -0
  225. nautobot/project-static/docs/media/power_distribution.png +0 -0
  226. nautobot/project-static/docs/objects.inv +0 -0
  227. nautobot/project-static/docs/overview/application_stack.html +23 -0
  228. nautobot/project-static/docs/overview/design_philosophy.html +23 -0
  229. nautobot/project-static/docs/release-notes/index.html +23 -0
  230. nautobot/project-static/docs/release-notes/version-1.0.html +23 -0
  231. nautobot/project-static/docs/release-notes/version-1.1.html +23 -0
  232. nautobot/project-static/docs/release-notes/version-1.2.html +23 -0
  233. nautobot/project-static/docs/release-notes/version-1.3.html +23 -0
  234. nautobot/project-static/docs/release-notes/version-1.4.html +23 -0
  235. nautobot/project-static/docs/release-notes/version-1.5.html +23 -0
  236. nautobot/project-static/docs/release-notes/version-1.6.html +23 -0
  237. nautobot/project-static/docs/release-notes/version-2.0.html +23 -0
  238. nautobot/project-static/docs/release-notes/version-2.1.html +23 -0
  239. nautobot/project-static/docs/release-notes/version-2.2.html +23 -0
  240. nautobot/project-static/docs/release-notes/version-2.3.html +23 -0
  241. nautobot/project-static/docs/release-notes/version-2.4.html +231 -0
  242. nautobot/project-static/docs/requirements.txt +2 -2
  243. nautobot/project-static/docs/search/search_index.json +1 -1
  244. nautobot/project-static/docs/sitemap.xml +303 -299
  245. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  246. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +23 -0
  247. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +23 -0
  248. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +23 -0
  249. nautobot/project-static/docs/user-guide/administration/configuration/index.html +23 -0
  250. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +23 -0
  251. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +23 -0
  252. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +23 -0
  253. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +23 -0
  254. nautobot/project-static/docs/user-guide/administration/guides/docker.html +23 -0
  255. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +23 -0
  256. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +23 -0
  257. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +23 -0
  258. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +23 -0
  259. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +23 -0
  260. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +23 -0
  261. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +23 -0
  262. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +23 -0
  263. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +23 -0
  264. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +23 -0
  265. nautobot/project-static/docs/user-guide/administration/installation/index.html +23 -0
  266. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +23 -0
  267. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +23 -0
  268. nautobot/project-static/docs/user-guide/administration/installation/services.html +23 -0
  269. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +23 -0
  270. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +23 -0
  271. nautobot/project-static/docs/user-guide/administration/security/index.html +23 -0
  272. nautobot/project-static/docs/user-guide/administration/security/notices.html +23 -0
  273. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +284 -219
  274. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +23 -0
  275. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +23 -0
  276. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +23 -0
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +23 -0
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +23 -0
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +23 -0
  280. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +23 -0
  281. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +23 -0
  282. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +23 -0
  283. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +23 -0
  284. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +23 -0
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +23 -0
  286. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +23 -0
  287. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +23 -0
  288. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +23 -0
  289. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +23 -0
  290. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +23 -0
  291. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +23 -0
  292. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +23 -0
  293. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +23 -0
  294. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +23 -0
  295. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +23 -0
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +23 -0
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +23 -0
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +23 -0
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +23 -0
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +23 -0
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +23 -0
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +23 -0
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +23 -0
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +23 -0
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +23 -0
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +23 -0
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +23 -0
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +23 -0
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +23 -0
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +23 -0
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +23 -0
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +23 -0
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +23 -0
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +23 -0
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +23 -0
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +23 -0
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +23 -0
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +23 -0
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +23 -0
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +23 -0
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +23 -0
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +23 -0
  323. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +23 -0
  324. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +305 -5
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +24 -1
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +23 -0
  327. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +136 -3
  328. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +41 -1
  329. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +40 -0
  330. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +23 -0
  331. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +23 -0
  332. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +23 -0
  333. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +23 -0
  334. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +23 -0
  335. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +23 -0
  336. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +23 -0
  337. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +23 -0
  338. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +23 -0
  339. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +23 -0
  340. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +23 -0
  341. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +23 -0
  342. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +23 -0
  343. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +23 -0
  344. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +23 -0
  345. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +23 -0
  346. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +23 -0
  347. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +23 -0
  348. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +23 -0
  349. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +23 -0
  350. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +23 -0
  351. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +23 -0
  352. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +23 -0
  353. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +23 -0
  354. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +23 -0
  355. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +23 -0
  356. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +23 -0
  357. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +23 -0
  358. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +23 -0
  359. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +23 -0
  360. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +23 -0
  361. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +23 -0
  362. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +23 -0
  363. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +23 -0
  364. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +23 -0
  365. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +23 -0
  366. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +23 -0
  367. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +23 -0
  368. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +23 -0
  369. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +23 -0
  370. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +23 -0
  371. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +23 -0
  372. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +23 -0
  373. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +23 -0
  374. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +23 -0
  375. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +23 -0
  376. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +23 -0
  377. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +23 -0
  378. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +23 -0
  379. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +23 -0
  380. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +23 -0
  381. nautobot/project-static/docs/user-guide/index.html +23 -0
  382. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +23 -0
  383. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +23 -0
  384. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +23 -0
  385. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +23 -0
  386. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +23 -0
  387. nautobot/project-static/docs/user-guide/platform-functionality/events.html +23 -0
  388. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +23 -0
  389. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +23 -0
  390. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +23 -0
  391. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +23 -0
  392. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +23 -0
  393. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +23 -0
  394. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +23 -0
  395. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +24 -1
  396. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +23 -0
  397. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +23 -0
  398. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +23 -0
  399. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +23 -0
  400. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +23 -0
  401. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +23 -0
  402. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +23 -0
  403. nautobot/project-static/docs/user-guide/platform-functionality/note.html +23 -0
  404. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +23 -0
  405. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +23 -0
  406. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +23 -0
  407. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +23 -0
  408. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +23 -0
  409. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +23 -0
  410. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +23 -0
  411. nautobot/project-static/docs/user-guide/platform-functionality/role.html +23 -0
  412. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +23 -0
  413. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +23 -0
  414. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +23 -0
  415. nautobot/project-static/docs/user-guide/platform-functionality/status.html +23 -0
  416. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +23 -0
  417. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +23 -0
  418. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +23 -0
  419. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +23 -0
  420. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +23 -0
  421. nautobot/users/tests/test_api.py +2 -2
  422. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -252
  423. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -75
  424. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +252 -0
  425. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +75 -0
  426. nautobot/virtualization/urls.py +3 -61
  427. nautobot/virtualization/views.py +48 -72
  428. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/METADATA +24 -24
  429. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/RECORD +433 -416
  430. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/LICENSE.txt +0 -0
  431. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/NOTICE +0 -0
  432. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/WHEEL +0 -0
  433. {nautobot-2.4.14.dist-info → nautobot-2.4.15.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,7 @@
1
1
  from django.contrib.contenttypes.models import ContentType
2
2
  from django.db.models import Model, Q
3
+ from django.utils.encoding import force_str
4
+ from django.utils.text import capfirst
3
5
  import django_filters
4
6
  from django_filters.constants import EMPTY_VALUES
5
7
  from django_filters.utils import verbose_lookup_expr
@@ -131,11 +133,21 @@ class CustomFieldModelFilterSetMixin(django_filters.FilterSet):
131
133
  # Create new filters for each lookup expression in the map
132
134
  for lookup_name, lookup_expr in lookup_map.items():
133
135
  new_filter_name = f"{filter_name}__{lookup_name}"
136
+
137
+ # Based on logic in BaseFilterSet._generate_lookup_expression_filters
138
+ verbose_expression = (
139
+ ["exclude", custom_field.label] if lookup_name.startswith("n") else [custom_field.label]
140
+ )
141
+ if isinstance(lookup_expr, str):
142
+ verbose_expression.append(verbose_lookup_expr(lookup_expr))
143
+ verbose_expression = [force_str(part) for part in verbose_expression if part]
144
+ label = capfirst(" ".join(verbose_expression))
145
+
134
146
  new_filter = filter_type(
135
147
  field_name=custom_field.key,
136
148
  lookup_expr=lookup_expr,
137
149
  custom_field=custom_field,
138
- label=f"{custom_field.label} ({verbose_lookup_expr(lookup_expr)})",
150
+ label=label,
139
151
  exclude=lookup_name.startswith("n"),
140
152
  )
141
153
 
@@ -297,6 +309,7 @@ class RoleModelFilterSetMixin(django_filters.FilterSet):
297
309
  field_name="role",
298
310
  query_params={"content_types": [cls._meta.model._meta.label_lower]},
299
311
  )
312
+ cls.declared_filters["role"] = filters["role"] # pylint: disable=no-member
300
313
 
301
314
  return filters
302
315
 
@@ -326,5 +339,6 @@ class StatusModelFilterSetMixin(django_filters.FilterSet):
326
339
  field_name="status",
327
340
  query_params={"content_types": [cls._meta.model._meta.label_lower]},
328
341
  )
342
+ cls.declared_filters["status"] = filters["status"] # pylint: disable=no-member
329
343
 
330
344
  return filters
@@ -12,5 +12,6 @@ from .contacts import (
12
12
  TeamFilterForm,
13
13
  TeamForm,
14
14
  )
15
- from .forms import * # noqa: F403 # undefined-local-with-import-star
15
+
16
16
  from .mixins import * # noqa: F403 # undefined-local-with-import-star
17
+ from .forms import * # noqa: F403 # undefined-local-with-import-star
@@ -43,6 +43,7 @@ from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
43
43
  from nautobot.dcim.models import Device, DeviceRedundancyGroup, DeviceType, Location, Platform
44
44
  from nautobot.extras.choices import (
45
45
  ButtonClassChoices,
46
+ CustomFieldFilterLogicChoices,
46
47
  DynamicGroupTypeChoices,
47
48
  JobExecutionType,
48
49
  JobQueueTypeChoices,
@@ -134,6 +135,7 @@ __all__ = (
134
135
  "ConfigContextSchemaForm",
135
136
  "CustomFieldBulkCreateForm", # 2.0 TODO remove this deprecated class
136
137
  "CustomFieldBulkDeleteForm",
138
+ "CustomFieldBulkEditForm",
137
139
  "CustomFieldChoiceFormSet",
138
140
  "CustomFieldFilterForm",
139
141
  "CustomFieldForm",
@@ -465,6 +467,66 @@ class CustomFieldDescriptionField(CommentField):
465
467
  return "Also used as the help text when editing models using this custom field.<br>" + super().default_helptext
466
468
 
467
469
 
470
+ class CustomFieldBulkEditForm(BootstrapMixin, NoteModelBulkEditFormMixin):
471
+ pk = forms.ModelMultipleChoiceField(queryset=CustomField.objects.all(), widget=forms.MultipleHiddenInput)
472
+ grouping = forms.CharField(
473
+ required=False,
474
+ max_length=CHARFIELD_MAX_LENGTH,
475
+ label="Grouping",
476
+ help_text="Human-readable grouping that this custom field belongs to.",
477
+ )
478
+ description = forms.CharField(
479
+ required=False,
480
+ max_length=CHARFIELD_MAX_LENGTH,
481
+ label="Description",
482
+ help_text="A helpful description for this field.",
483
+ )
484
+ required = forms.NullBooleanField(
485
+ required=False,
486
+ widget=BulkEditNullBooleanSelect,
487
+ label="Required",
488
+ help_text="If true, this field is required when creating new objects or editing an existing object.",
489
+ )
490
+ filter_logic = forms.ChoiceField(
491
+ required=False,
492
+ choices=add_blank_choice(CustomFieldFilterLogicChoices.CHOICES),
493
+ label="Filter logic",
494
+ help_text="Loose matches any instance of a given string; Exact matches the entire field.",
495
+ )
496
+ weight = forms.IntegerField(
497
+ required=False, label="Weight", help_text="Fields with higher weights appear lower in a form."
498
+ )
499
+ advanced_ui = forms.NullBooleanField(
500
+ required=False,
501
+ widget=BulkEditNullBooleanSelect,
502
+ label="Move to Advanced tab",
503
+ help_text="Hide this field from the object's primary information tab. It will appear in the 'Advanced' tab instead.",
504
+ )
505
+ add_content_types = MultipleContentTypeField(
506
+ limit_choices_to=FeatureQuery("custom_fields"), required=False, label="Add Content Types"
507
+ )
508
+ remove_content_types = MultipleContentTypeField(
509
+ limit_choices_to=FeatureQuery("custom_fields"), required=False, label="Remove Content Types"
510
+ )
511
+
512
+ class Meta:
513
+ model = CustomField
514
+ fields = (
515
+ "grouping",
516
+ "description",
517
+ "required",
518
+ "filter_logic",
519
+ "weight",
520
+ "advanced_ui",
521
+ "add_content_types",
522
+ "remove_content_types",
523
+ )
524
+ nullable_fields = [
525
+ "grouping",
526
+ "description",
527
+ ]
528
+
529
+
468
530
  class CustomFieldForm(BootstrapMixin, forms.ModelForm):
469
531
  label = forms.CharField(
470
532
  required=True, max_length=CHARFIELD_MAX_LENGTH, help_text="Name of the field as displayed to users."
@@ -111,10 +111,13 @@ class JobResultManager(BaseManager.from_queryset(RestrictedQuerySet), TaskResult
111
111
  except Job.DoesNotExist:
112
112
  pass
113
113
 
114
+ if "date_started" in kwargs:
115
+ fields["date_started"] = kwargs["date_started"]
116
+
114
117
  obj, created = self.using(using).get_or_create(id=task_id, defaults=fields)
115
118
 
116
119
  if not created:
117
- # Make sure `date_done` is allowed to stay null until the task reacheas a ready state.
120
+ # Make sure `date_done` is allowed to stay null until the task reaches a ready state.
118
121
  #
119
122
  # Default behavior in `django-celery-results` has this field as a
120
123
  # `DateField(auto_now=True)` which just automatically updates the `date_done` field on every
@@ -0,0 +1,18 @@
1
+ # Generated by Django 4.2.23 on 2025-08-11 16:18
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+ dependencies = [
8
+ ("django_celery_results", "0012_taskresult_date_started"),
9
+ ("extras", "0124_add_joblogentry_index"),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name="jobresult",
15
+ name="date_started",
16
+ field=models.DateTimeField(blank=True, db_index=True, null=True),
17
+ ),
18
+ ]
@@ -514,8 +514,7 @@ class CustomField(
514
514
  blank=True,
515
515
  null=True,
516
516
  help_text=(
517
- "Default value for the field (must be a JSON value). Encapsulate strings with double quotes (e.g. "
518
- '"Foo").'
517
+ 'Default value for the field (must be a JSON value). Encapsulate strings with double quotes (e.g. "Foo").'
519
518
  ),
520
519
  )
521
520
  weight = models.PositiveSmallIntegerField(
@@ -100,8 +100,7 @@ class GitRepository(PrimaryModel):
100
100
 
101
101
  if self.present_in_database and self.slug != self.__initial_slug:
102
102
  raise ValidationError(
103
- f"Slug cannot be changed once set. Current slug is {self.__initial_slug}, "
104
- f"requested slug is {self.slug}"
103
+ f"Slug cannot be changed once set. Current slug is {self.__initial_slug}, requested slug is {self.slug}"
105
104
  )
106
105
 
107
106
  if not self.present_in_database:
@@ -650,6 +650,7 @@ class JobResult(BaseModel, CustomFieldModel):
650
650
  help_text="Registered name of the Celery task for this job. Internal use only.",
651
651
  )
652
652
  date_created = models.DateTimeField(auto_now_add=True, db_index=True)
653
+ date_started = models.DateTimeField(null=True, blank=True, db_index=True)
653
654
  date_done = models.DateTimeField(null=True, blank=True, db_index=True)
654
655
  user = models.ForeignKey(
655
656
  to=settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name="+", blank=True, null=True
@@ -714,7 +715,7 @@ class JobResult(BaseModel, CustomFieldModel):
714
715
  natural_key_field_names = ["id"]
715
716
 
716
717
  def __str__(self):
717
- return f"{self.name} started at {self.date_created} ({self.status})"
718
+ return f"{self.name} created at {self.date_created} ({self.status})"
718
719
 
719
720
  def as_dict(self):
720
721
  """This is required by the django-celery-results DB backend."""
@@ -736,7 +737,8 @@ class JobResult(BaseModel, CustomFieldModel):
736
737
  if not self.date_done:
737
738
  return None
738
739
 
739
- duration = self.date_done - self.date_created
740
+ # Older records may not have a date_started value, so we use date_created as a fallback.
741
+ duration = self.date_done - (self.date_started or self.date_created)
740
742
  minutes, seconds = divmod(duration.total_seconds(), 60)
741
743
 
742
744
  return f"{int(minutes)} minutes, {seconds:.2f} seconds"
@@ -754,7 +756,8 @@ class JobResult(BaseModel, CustomFieldModel):
754
756
  # Only add metrics if we have a related job model. If we are moving to a terminal state we should always
755
757
  # have a related job model, so this shouldn't be too tight of a restriction.
756
758
  if self.job_model:
757
- duration = self.date_done - self.date_created
759
+ # Older records may not have a date_started value, so we use date_created as a fallback.
760
+ duration = self.date_done - (self.date_started or self.date_created)
758
761
  JOB_RESULT_METRIC.labels(self.job_model.grouping, self.job_model.name, status).observe(
759
762
  duration.total_seconds()
760
763
  )
@@ -884,6 +887,7 @@ class JobResult(BaseModel, CustomFieldModel):
884
887
  # synchronous tasks are run before the JobResult is saved, so any fields required by
885
888
  # the job must be added before calling `apply()`
886
889
  job_result.celery_kwargs = job_celery_kwargs
890
+ job_result.date_started = timezone.now()
887
891
  job_result.save()
888
892
 
889
893
  # setup synchronous task logging
@@ -16,6 +16,8 @@ import yaml
16
16
 
17
17
  from nautobot.core.api.views import AuthenticatedAPIRootView, NautobotAPIVersionMixin
18
18
  from nautobot.core.forms import TableConfigForm
19
+ from nautobot.core.ui.breadcrumbs import Breadcrumbs, ViewNameBreadcrumbItem
20
+ from nautobot.core.ui.titles import Titles
19
21
  from nautobot.core.views.generic import GenericView
20
22
  from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
21
23
  from nautobot.extras.plugins.tables import InstalledAppsTable
@@ -84,6 +86,10 @@ class InstalledAppsView(GenericView):
84
86
  """
85
87
 
86
88
  table = InstalledAppsTable
89
+ breadcrumbs = Breadcrumbs(
90
+ items={"generic": [ViewNameBreadcrumbItem(view_name="apps:apps_list", label="Installed Apps")]}
91
+ )
92
+ view_titles = Titles(titles={"generic": "Installed Apps"})
87
93
 
88
94
  def get(self, request):
89
95
  marketplace_data = load_marketplace_data()
@@ -123,6 +129,9 @@ class InstalledAppsView(GenericView):
123
129
  "filter_form": None,
124
130
  "app_icons": app_icons,
125
131
  "display": display,
132
+ "view_action": "generic",
133
+ "breadcrumbs": self.breadcrumbs,
134
+ "view_titles": self.view_titles,
126
135
  },
127
136
  )
128
137
 
@@ -228,6 +237,11 @@ class MarketplaceView(GenericView):
228
237
  View for listing all available Apps.
229
238
  """
230
239
 
240
+ breadcrumbs = Breadcrumbs(
241
+ items={"generic": [ViewNameBreadcrumbItem(view_name="apps:apps_marketplace", label="Apps Marketplace")]}
242
+ )
243
+ view_titles = Titles(titles={"generic": "Apps Marketplace"})
244
+
231
245
  def get(self, request):
232
246
  marketplace_data = load_marketplace_data()
233
247
 
@@ -240,4 +254,13 @@ class MarketplaceView(GenericView):
240
254
  marketplace_app["installed"] = True
241
255
  break
242
256
 
243
- return render(request, "extras/marketplace.html", {"apps": marketplace_data["apps"]})
257
+ return render(
258
+ request,
259
+ "extras/marketplace.html",
260
+ {
261
+ "apps": marketplace_data["apps"],
262
+ "view_action": "generic",
263
+ "breadcrumbs": self.breadcrumbs,
264
+ "view_titles": self.view_titles,
265
+ },
266
+ )
@@ -65,7 +65,7 @@ def register_secrets_provider(provider):
65
65
  if provider.slug in registry["secrets_providers"]:
66
66
  raise KeyError(
67
67
  f'Cannot register {provider} as slug "{provider.slug}" is already registered '
68
- f'by {registry["secrets_providers"][provider.slug]}'
68
+ f"by {registry['secrets_providers'][provider.slug]}"
69
69
  )
70
70
  registry["secrets_providers"][provider.slug] = provider
71
71
 
nautobot/extras/tables.py CHANGED
@@ -890,6 +890,8 @@ class JobResultTable(BaseTable):
890
890
  pk = ToggleColumn()
891
891
  job_model = tables.Column(linkify=True)
892
892
  date_created = tables.DateTimeColumn(linkify=True, format=settings.SHORT_DATETIME_FORMAT)
893
+ date_started = tables.DateTimeColumn(linkify=True, format=settings.SHORT_DATETIME_FORMAT)
894
+ date_done = tables.DateTimeColumn(linkify=True, format=settings.SHORT_DATETIME_FORMAT)
893
895
  status = tables.TemplateColumn(
894
896
  template_code="{% include 'extras/inc/job_label.html' with result=record %}",
895
897
  )
@@ -961,6 +963,8 @@ class JobResultTable(BaseTable):
961
963
  fields = (
962
964
  "pk",
963
965
  "date_created",
966
+ "date_started",
967
+ "date_done",
964
968
  "name",
965
969
  "job_model",
966
970
  "scheduled_job",
@@ -1193,6 +1197,11 @@ class ObjectChangeTable(BaseTable):
1193
1197
  "request_id",
1194
1198
  )
1195
1199
 
1200
+ def __init__(self, *args, **kwargs):
1201
+ super().__init__(*args, **kwargs)
1202
+ # The `object_repr` column also uses the `changed_object` generic-foreign-key value
1203
+ self.add_conditional_prefetch("object_repr", "changed_object")
1204
+
1196
1205
 
1197
1206
  #
1198
1207
  # Relationship
@@ -1,129 +1,2 @@
1
- {% extends 'generic/object_retrieve.html' %}
2
- {% load buttons %}
3
- {% load helpers %}
4
-
5
- {% block content_left_page %}
6
- <div class="panel panel-default">
7
- <div class="panel-heading">
8
- <strong>Custom Field</strong>
9
- </div>
10
- <table class="table table-hover panel-body attr-table">
11
- <tr>
12
- <td>Label</td>
13
- <td>{{ object.label }}</td>
14
- </tr>
15
- <tr>
16
- <td>Key</td>
17
- <td>{{ object.key }}</td>
18
- </tr>
19
- <tr>
20
- <td>Type</td>
21
- <td>{{ object.type | capfirst }}</td>
22
- </tr>
23
- <tr>
24
- <td>Weight</td>
25
- <td>{{ object.weight }}</td>
26
- </tr>
27
- <tr>
28
- <td>Grouping</td>
29
- <td>{{ object.grouping | placeholder }}</td>
30
- </tr>
31
- <tr>
32
- <td>Description</td>
33
- <td>{{ object.description | render_markdown | placeholder }}</td>
34
- </tr>
35
- <tr>
36
- <td>Required</td>
37
- <td>{{ object.required | render_boolean }}</td>
38
- </tr>
39
- <tr>
40
- <td>Default</td>
41
- <td>
42
- {% if object.type == "markdown" %}
43
- {{ object.default | render_markdown | placeholder }}
44
- {% elif object.type == "json" and object.default is not None %}
45
- <pre>{{ object.default | render_json }}</pre>
46
- {% else %}
47
- {{ object.default | placeholder }}
48
- {% endif %}
49
- </td>
50
- </tr>
51
- <tr>
52
- <td>Filter Logic</td>
53
- <td>{{ object.filter_logic | capfirst }}</td>
54
- </tr>
55
- <tr>
56
- <td>Move to Advanced Tab</td>
57
- <td>{{ object.advanced_ui | render_boolean }}</td>
58
- </tr>
59
- </table>
60
- </div>
61
- {% if object.custom_field_choices.exists %}
62
- <div class="panel panel-default">
63
- <div class="panel-heading">
64
- <strong>Custom Field Choices</strong>
65
- </div>
66
- <table class="table table-hover panel-body attr-table">
67
- <thead>
68
- <tr>
69
- <th>Value</th>
70
- <th>Weight</th>
71
- </tr>
72
- </thead>
73
- <tbody>
74
- {% for choice in object.custom_field_choices.all %}
75
- <tr>
76
- <td>{{ choice.value }}</td>
77
- <td>{{ choice.weight }}</td>
78
- </tr>
79
- {% endfor %}
80
- </tbody>
81
- </table>
82
- </div>
83
- {% endif %}
84
- {% endblock content_left_page %}
85
-
86
- {% block content_right_page %}
87
- <div class="panel panel-default">
88
- <div class="panel-heading">
89
- <strong>Assignment</strong>
90
- </div>
91
- <table class="table table-hover panel-body attr-table">
92
- <tr>
93
- <td>Content Types</td>
94
- <td>
95
- <ul>
96
- {% for ct in object.content_types.all %}
97
- <li>{{ ct }}</li>
98
- {% endfor %}
99
- </ul>
100
- </td>
101
- </tr>
102
- </table>
103
- </div>
104
- <div class="panel panel-default">
105
- <div class="panel-heading">
106
- <strong>Validation Rules</strong>
107
- </div>
108
- <table class="table table-hover panel-body attr-table">
109
- <tr>
110
- <td>Minimum Value/Length</td>
111
- <td>{{ object.validation_minimum | placeholder }}</td>
112
- </tr>
113
- <tr>
114
- <td>Maximum Value/Length</td>
115
- <td>{{ object.validation_maximum | placeholder }}</td>
116
- </tr>
117
- <tr>
118
- <td>Validation Regex</td>
119
- <td>
120
- {% if object.validation_regex %}
121
- <code>{{ object.validation_regex | placeholder }}</code>
122
- {% else %}
123
- {{ object.validation_regex | placeholder }}
124
- {% endif %}
125
- </td>
126
- </tr>
127
- </table>
128
- </div>
129
- {% endblock content_right_page %}
1
+ {% extends 'extras/customfield_retrieve.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,108 +1,2 @@
1
- {% extends 'generic/object_create.html' %}
2
- {% load static %}
3
- {% load form_helpers %}
4
-
5
- {% block form %}
6
- <div class="panel panel-default">
7
- <div class="panel-heading"><strong>Custom Field</strong></div>
8
- <div class="panel-body">
9
- {% render_field form.label %}
10
- {% render_field form.grouping %}
11
- {% render_field form.key %}
12
- {% render_field form.type %}
13
- {% render_field form.weight %}
14
- {% render_field form.description %}
15
- {% render_field form.required %}
16
- {% render_field form.default %}
17
- {% render_field form.filter_logic %}
18
- {% render_field form.advanced_ui %}
19
- </div>
20
- </div>
21
- <div class="panel panel-default">
22
- <div class="panel-heading"><strong>Assignment</strong></div>
23
- <div class="panel-body">
24
- {% render_field form.content_types %}
25
- </div>
26
- </div>
27
- <div class="panel panel-default">
28
- <div class="panel-heading"><strong>Validation Rules</strong></div>
29
- <div class="panel-body">
30
- {% render_field form.validation_minimum %}
31
- {% render_field form.validation_maximum %}
32
- {% render_field form.validation_regex %}
33
- </div>
34
- </div>
35
- <div class="panel panel-default">
36
- <div class="panel-heading"><strong>Custom Field Choices</strong></div>
37
- <div class="panel-body">
38
- {% if choices.errors %}
39
- <div class="text-danger">
40
- Please correct the error(s) below:
41
-
42
- {% for choice in choices.forms %}
43
- {% if choice.errors %}
44
- {% for error in choice.errors.values %}{{ error }}{% endfor %}
45
- {% endif %}
46
- {% endfor %}
47
- </div>
48
- {% endif %}
49
- {{ choices.non_field_errors }}
50
- <table class="table" id="custom-field-choices">
51
- {{ choices.management_form }}
52
- {% for choice in choices.forms %}
53
- {% if forloop.first %}
54
- <thead>
55
- <tr>
56
- {% for field in choice.visible_fields %}
57
- <th>{{ field.label|capfirst }}</th>
58
- {% endfor %}
59
- </tr>
60
- </thead>
61
- {% endif %}
62
- <tr class="formset_row-{{ choices.prefix }}">
63
- {% for field in choice.visible_fields %}
64
- <td>
65
- {# Include the hidden fields in the form #}
66
- {% if forloop.first %}
67
- {% for hidden in choice.hidden_fields %}
68
- {{ hidden }}
69
- {% endfor %}
70
- {% endif %}
71
- {{ field }}
72
- {% if field.errors %}
73
- <ul>
74
- {% for error in field.errors %}
75
- {# Embed an HTML comment indicating the error for extraction by tests #}
76
- <!-- FORM-ERROR {{ field.name }}: {{ error }} -->
77
- <li class="text-danger">{{ error }}</li>
78
- {% endfor %}
79
- </ul>
80
- {% endif %}
81
- </td>
82
- {% endfor %}
83
- </tr>
84
- {% endfor %}
85
- </table>
86
- </div>
87
- </div>
88
- {% include 'inc/extras_features_edit_form_fields.html' %}
89
-
90
- {% endblock form %}
91
-
92
- {% block javascript %}
93
- {{ block.super }}
94
- <script src="{% static 'jquery/jquery.formset.js' %}"></script>
95
- <script type="text/javascript">
96
- const slugify_prefer_underscores = true; // Custom fields work better in GraphQL (etc.) with underscore-based slugs
97
- $('.formset_row-{{ choices.prefix }}').formset({
98
- addText: '<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add another Custom Field Choice',
99
- addCssClass: 'btn btn-primary add-row',
100
- deleteText: '<span class="mdi mdi-trash-can-outline" aria-hidden="true"></span>',
101
- deleteCssClass: 'btn btn-danger delete-row',
102
- prefix: '{{ choices.prefix }}',
103
- formCssClass: 'dynamic-formset-{{ choices.prefix }}',
104
- keepFieldValues: 'input[type="number"]',
105
- added: jsify_form
106
- });
107
- </script>
108
- {% endblock javascript %}
1
+ {% extends 'extras/customfield_update.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}