nautobot 2.4.10__py3-none-any.whl → 2.4.11__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 (416) hide show
  1. nautobot/cloud/tests/test_views.py +13 -1
  2. nautobot/cloud/views.py +39 -9
  3. nautobot/core/celery/__init__.py +21 -0
  4. nautobot/core/celery/encoders.py +3 -0
  5. nautobot/core/forms/forms.py +4 -1
  6. nautobot/core/jobs/bulk_actions.py +8 -8
  7. nautobot/core/jobs/cleanup.py +11 -0
  8. nautobot/core/management/commands/generate_test_data.py +2 -1
  9. nautobot/core/templates/generic/object_retrieve.html +1 -1
  10. nautobot/core/testing/mixins.py +19 -1
  11. nautobot/core/testing/views.py +104 -8
  12. nautobot/core/tests/test_jobs.py +20 -4
  13. nautobot/core/tests/test_utils.py +193 -0
  14. nautobot/core/tests/test_views_utils.py +53 -2
  15. nautobot/core/ui/object_detail.py +4 -0
  16. nautobot/core/utils/lookup.py +4 -2
  17. nautobot/core/utils/module_loading.py +86 -58
  18. nautobot/core/views/generic.py +2 -12
  19. nautobot/core/views/mixins.py +19 -1
  20. nautobot/core/views/renderers.py +4 -13
  21. nautobot/core/views/utils.py +16 -0
  22. nautobot/dcim/api/serializers.py +13 -0
  23. nautobot/dcim/api/urls.py +1 -0
  24. nautobot/dcim/api/views.py +20 -0
  25. nautobot/dcim/apps.py +1 -0
  26. nautobot/dcim/factory.py +11 -0
  27. nautobot/dcim/filters/__init__.py +110 -0
  28. nautobot/dcim/forms.py +205 -19
  29. nautobot/dcim/migrations/0070_modulefamily_models.py +92 -0
  30. nautobot/dcim/models/__init__.py +2 -0
  31. nautobot/dcim/models/device_component_templates.py +14 -0
  32. nautobot/dcim/models/device_components.py +13 -1
  33. nautobot/dcim/models/devices.py +62 -0
  34. nautobot/dcim/navigation.py +16 -0
  35. nautobot/dcim/tables/__init__.py +2 -0
  36. nautobot/dcim/tables/devices.py +48 -0
  37. nautobot/dcim/tables/devicetypes.py +35 -1
  38. nautobot/dcim/tables/template_code.py +2 -0
  39. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +1 -90
  40. nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
  41. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +1 -63
  42. nautobot/dcim/templates/dcim/location.html +2 -249
  43. nautobot/dcim/templates/dcim/location_edit.html +2 -38
  44. nautobot/dcim/templates/dcim/location_retrieve.html +249 -0
  45. nautobot/dcim/templates/dcim/location_update.html +38 -0
  46. nautobot/dcim/templates/dcim/module_update.html +1 -0
  47. nautobot/dcim/templates/dcim/modulebay_retrieve.html +93 -1
  48. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +31 -0
  49. nautobot/dcim/templates/dcim/moduletype_retrieve.html +6 -0
  50. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -160
  51. nautobot/dcim/tests/test_api.py +35 -0
  52. nautobot/dcim/tests/test_filters.py +102 -3
  53. nautobot/dcim/tests/test_models.py +146 -0
  54. nautobot/dcim/tests/test_views.py +70 -97
  55. nautobot/dcim/urls.py +4 -22
  56. nautobot/dcim/views.py +439 -153
  57. nautobot/extras/api/views.py +9 -2
  58. nautobot/extras/datasources/git.py +11 -3
  59. nautobot/extras/forms/forms.py +9 -5
  60. nautobot/extras/jobs.py +4 -2
  61. nautobot/extras/models/datasources.py +5 -8
  62. nautobot/extras/models/jobs.py +5 -0
  63. nautobot/extras/plugins/__init__.py +3 -0
  64. nautobot/extras/tables.py +40 -3
  65. nautobot/extras/templates/extras/configcontext.html +2 -220
  66. nautobot/extras/templates/extras/configcontext_edit.html +2 -50
  67. nautobot/extras/templates/extras/configcontext_retrieve.html +2 -0
  68. nautobot/extras/templates/extras/configcontext_update.html +50 -0
  69. nautobot/extras/templates/extras/configcontextschema.html +2 -48
  70. nautobot/extras/templates/extras/configcontextschema_edit.html +2 -19
  71. nautobot/extras/templates/extras/configcontextschema_retrieve.html +48 -0
  72. nautobot/extras/templates/extras/configcontextschema_update.html +19 -0
  73. nautobot/extras/templates/extras/inc/configcontext_data.html +1 -0
  74. nautobot/extras/templates/extras/inc/json_data.html +1 -1
  75. nautobot/extras/templates/extras/inc/json_format.html +2 -2
  76. nautobot/extras/templates/extras/job_edit.html +12 -6
  77. nautobot/extras/templates/extras/tag.html +2 -52
  78. nautobot/extras/templates/extras/tag_edit.html +2 -15
  79. nautobot/extras/templates/extras/tag_retrieve.html +52 -0
  80. nautobot/extras/templates/extras/tag_update.html +15 -0
  81. nautobot/extras/templates/extras/team_retrieve.html +2 -2
  82. nautobot/extras/tests/test_api.py +15 -15
  83. nautobot/extras/tests/test_filters.py +4 -4
  84. nautobot/extras/tests/test_jobs.py +23 -10
  85. nautobot/extras/tests/test_models.py +19 -8
  86. nautobot/extras/tests/test_plugins.py +6 -3
  87. nautobot/extras/tests/test_views.py +66 -11
  88. nautobot/extras/urls.py +4 -134
  89. nautobot/extras/views.py +113 -158
  90. nautobot/ipam/models.py +19 -4
  91. nautobot/ipam/tables.py +19 -0
  92. nautobot/ipam/templates/ipam/vlan.html +2 -84
  93. nautobot/ipam/templates/ipam/vlan_edit.html +2 -24
  94. nautobot/ipam/templates/ipam/vlan_retrieve.html +84 -0
  95. nautobot/ipam/templates/ipam/vlan_update.html +24 -0
  96. nautobot/ipam/tests/test_views.py +5 -0
  97. nautobot/ipam/urls.py +1 -21
  98. nautobot/ipam/views.py +45 -70
  99. nautobot/project-static/docs/404.html +31 -8
  100. nautobot/project-static/docs/apps/index.html +31 -8
  101. nautobot/project-static/docs/apps/nautobot-apps.html +31 -8
  102. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +31 -8
  103. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +31 -8
  104. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +31 -8
  105. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +31 -8
  106. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +31 -8
  107. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +31 -8
  108. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +31 -8
  109. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +31 -8
  110. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +31 -8
  111. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +31 -8
  112. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +31 -8
  113. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +31 -8
  114. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +31 -8
  115. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +31 -8
  116. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +31 -8
  117. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +31 -8
  118. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +31 -8
  119. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +31 -8
  120. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +31 -8
  121. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +120 -8
  122. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +31 -8
  123. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +31 -8
  124. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +31 -8
  125. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +31 -8
  126. nautobot/project-static/docs/development/apps/api/configuration-view.html +31 -8
  127. nautobot/project-static/docs/development/apps/api/database-backend-config.html +31 -8
  128. nautobot/project-static/docs/development/apps/api/models/django-admin.html +31 -8
  129. nautobot/project-static/docs/development/apps/api/models/global-search.html +31 -8
  130. nautobot/project-static/docs/development/apps/api/models/graphql.html +31 -8
  131. nautobot/project-static/docs/development/apps/api/models/index.html +31 -8
  132. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +40 -8
  133. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +31 -8
  134. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +31 -8
  135. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +31 -8
  136. nautobot/project-static/docs/development/apps/api/platform-features/index.html +31 -8
  137. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +31 -8
  138. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +31 -8
  139. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +31 -8
  140. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +32 -9
  141. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +31 -8
  142. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +31 -8
  143. nautobot/project-static/docs/development/apps/api/prometheus.html +31 -8
  144. nautobot/project-static/docs/development/apps/api/setup.html +31 -8
  145. nautobot/project-static/docs/development/apps/api/testing.html +31 -8
  146. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +31 -8
  147. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +31 -8
  148. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +31 -8
  149. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +31 -8
  150. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +31 -8
  151. nautobot/project-static/docs/development/apps/api/views/base-template.html +31 -8
  152. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +31 -8
  153. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +31 -8
  154. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +31 -8
  155. nautobot/project-static/docs/development/apps/api/views/index.html +31 -8
  156. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +31 -8
  157. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -8
  158. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +31 -8
  159. nautobot/project-static/docs/development/apps/api/views/notes.html +31 -8
  160. nautobot/project-static/docs/development/apps/api/views/rest-api.html +31 -8
  161. nautobot/project-static/docs/development/apps/api/views/urls.html +31 -8
  162. nautobot/project-static/docs/development/apps/index.html +31 -8
  163. nautobot/project-static/docs/development/apps/migration/code-updates.html +31 -8
  164. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +31 -8
  165. nautobot/project-static/docs/development/apps/migration/from-v1.html +31 -8
  166. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +31 -8
  167. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +31 -8
  168. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +31 -8
  169. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +31 -8
  170. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +31 -8
  171. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +31 -8
  172. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +31 -8
  173. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +31 -8
  174. nautobot/project-static/docs/development/apps/porting-from-netbox.html +31 -8
  175. nautobot/project-static/docs/development/core/application-registry.html +31 -8
  176. nautobot/project-static/docs/development/core/best-practices.html +31 -8
  177. nautobot/project-static/docs/development/core/bootstrap-ui.html +31 -8
  178. nautobot/project-static/docs/development/core/caching.html +31 -8
  179. nautobot/project-static/docs/development/core/controllers.html +31 -8
  180. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +31 -8
  181. nautobot/project-static/docs/development/core/generic-views.html +31 -8
  182. nautobot/project-static/docs/development/core/getting-started.html +31 -8
  183. nautobot/project-static/docs/development/core/homepage.html +31 -8
  184. nautobot/project-static/docs/development/core/index.html +31 -8
  185. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +31 -8
  186. nautobot/project-static/docs/development/core/model-checklist.html +31 -8
  187. nautobot/project-static/docs/development/core/model-features.html +31 -8
  188. nautobot/project-static/docs/development/core/natural-keys.html +31 -8
  189. nautobot/project-static/docs/development/core/navigation-menu.html +31 -8
  190. nautobot/project-static/docs/development/core/release-checklist.html +31 -8
  191. nautobot/project-static/docs/development/core/role-internals.html +31 -8
  192. nautobot/project-static/docs/development/core/settings.html +31 -8
  193. nautobot/project-static/docs/development/core/style-guide.html +31 -8
  194. nautobot/project-static/docs/development/core/templates.html +31 -8
  195. nautobot/project-static/docs/development/core/testing.html +31 -8
  196. nautobot/project-static/docs/development/core/ui-component-framework.html +31 -8
  197. nautobot/project-static/docs/development/core/user-preferences.html +31 -8
  198. nautobot/project-static/docs/development/index.html +31 -8
  199. nautobot/project-static/docs/development/jobs/getting-started.html +35 -8
  200. nautobot/project-static/docs/development/jobs/index.html +31 -8
  201. nautobot/project-static/docs/development/jobs/installation.html +31 -8
  202. nautobot/project-static/docs/development/jobs/job-extensions.html +31 -8
  203. nautobot/project-static/docs/development/jobs/job-logging.html +31 -8
  204. nautobot/project-static/docs/development/jobs/job-patterns.html +31 -8
  205. nautobot/project-static/docs/development/jobs/job-structure.html +31 -8
  206. nautobot/project-static/docs/development/jobs/migration/from-v1.html +31 -8
  207. nautobot/project-static/docs/development/jobs/testing.html +31 -8
  208. nautobot/project-static/docs/index.html +31 -8
  209. nautobot/project-static/docs/insert-analytics.sh +36 -0
  210. nautobot/project-static/docs/objects.inv +0 -0
  211. nautobot/project-static/docs/overview/application_stack.html +31 -8
  212. nautobot/project-static/docs/overview/design_philosophy.html +31 -8
  213. nautobot/project-static/docs/release-notes/index.html +31 -8
  214. nautobot/project-static/docs/release-notes/version-1.0.html +31 -8
  215. nautobot/project-static/docs/release-notes/version-1.1.html +31 -8
  216. nautobot/project-static/docs/release-notes/version-1.2.html +31 -8
  217. nautobot/project-static/docs/release-notes/version-1.3.html +31 -8
  218. nautobot/project-static/docs/release-notes/version-1.4.html +31 -8
  219. nautobot/project-static/docs/release-notes/version-1.5.html +31 -8
  220. nautobot/project-static/docs/release-notes/version-1.6.html +31 -8
  221. nautobot/project-static/docs/release-notes/version-2.0.html +31 -8
  222. nautobot/project-static/docs/release-notes/version-2.1.html +31 -8
  223. nautobot/project-static/docs/release-notes/version-2.2.html +31 -8
  224. nautobot/project-static/docs/release-notes/version-2.3.html +31 -8
  225. nautobot/project-static/docs/release-notes/version-2.4.html +252 -8
  226. nautobot/project-static/docs/search/search_index.json +1 -1
  227. nautobot/project-static/docs/sitemap.xml +302 -298
  228. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  229. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +31 -8
  230. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +31 -8
  231. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +31 -8
  232. nautobot/project-static/docs/user-guide/administration/configuration/index.html +31 -8
  233. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +31 -8
  234. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +31 -8
  235. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +31 -8
  236. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +31 -8
  237. nautobot/project-static/docs/user-guide/administration/guides/docker.html +31 -8
  238. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +31 -8
  239. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +31 -8
  240. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +31 -8
  241. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +31 -8
  242. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +31 -8
  243. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +31 -8
  244. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +31 -8
  245. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +31 -8
  246. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +31 -8
  247. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +31 -8
  248. nautobot/project-static/docs/user-guide/administration/installation/index.html +31 -8
  249. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +31 -8
  250. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +31 -8
  251. nautobot/project-static/docs/user-guide/administration/installation/services.html +31 -8
  252. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +31 -8
  253. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +31 -8
  254. nautobot/project-static/docs/user-guide/administration/security/index.html +31 -8
  255. nautobot/project-static/docs/user-guide/administration/security/notices.html +31 -8
  256. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +31 -8
  257. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +31 -8
  258. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +31 -8
  259. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +31 -8
  260. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +31 -8
  261. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +31 -8
  262. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +31 -8
  263. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +31 -8
  264. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +31 -8
  265. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +31 -8
  266. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +31 -8
  267. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +31 -8
  268. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +31 -8
  269. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +31 -8
  270. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +31 -8
  271. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +31 -8
  272. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +31 -8
  273. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +31 -8
  274. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +31 -8
  275. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +31 -8
  276. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +31 -8
  277. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +31 -8
  278. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +31 -8
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +31 -8
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +31 -8
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +31 -8
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +31 -8
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +31 -8
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +31 -8
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +31 -8
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +31 -8
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +31 -8
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +31 -8
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +31 -8
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +43 -20
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +31 -8
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +31 -8
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +31 -8
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +31 -8
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +31 -8
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +31 -8
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +31 -8
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +31 -8
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +31 -8
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +31 -8
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +35 -8
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +35 -8
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +35 -8
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +10261 -0
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +34 -11
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +31 -8
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +31 -8
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +31 -8
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +31 -8
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +31 -8
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +31 -8
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +31 -8
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +31 -8
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +31 -8
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +31 -8
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +31 -8
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +31 -8
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +31 -8
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +31 -8
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +31 -8
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +31 -8
  322. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +31 -8
  323. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +31 -8
  324. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +31 -8
  325. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +31 -8
  326. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +31 -8
  327. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +31 -8
  328. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +31 -8
  329. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +31 -8
  330. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +31 -8
  331. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +31 -8
  332. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +31 -8
  333. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +31 -8
  334. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +31 -8
  335. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +31 -8
  336. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +31 -8
  337. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +31 -8
  338. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +31 -8
  339. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +31 -8
  340. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +31 -8
  341. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +31 -8
  342. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +31 -8
  343. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +31 -8
  344. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +31 -8
  345. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +31 -8
  346. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +31 -8
  347. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +31 -8
  348. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +31 -8
  349. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +31 -8
  350. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +31 -8
  351. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +31 -8
  352. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +31 -8
  353. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +31 -8
  354. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +31 -8
  355. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +31 -8
  356. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +31 -8
  357. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +31 -8
  358. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +41 -15
  359. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +31 -8
  360. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +31 -8
  361. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +31 -8
  362. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +31 -8
  363. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +31 -8
  364. nautobot/project-static/docs/user-guide/index.html +31 -8
  365. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +31 -8
  366. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +31 -8
  367. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +31 -8
  368. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +31 -8
  369. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +31 -8
  370. nautobot/project-static/docs/user-guide/platform-functionality/events.html +31 -8
  371. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +31 -8
  372. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +31 -8
  373. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +37 -9
  374. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +31 -8
  375. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +31 -8
  376. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +31 -8
  377. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +31 -8
  378. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +31 -8
  379. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +31 -8
  380. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +31 -8
  381. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +31 -8
  382. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +31 -8
  383. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +31 -8
  384. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +31 -8
  385. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +31 -8
  386. nautobot/project-static/docs/user-guide/platform-functionality/note.html +31 -8
  387. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +31 -8
  388. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +31 -8
  389. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +31 -8
  390. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +31 -8
  391. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +31 -8
  392. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +31 -8
  393. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +31 -8
  394. nautobot/project-static/docs/user-guide/platform-functionality/role.html +31 -8
  395. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +31 -8
  396. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +31 -8
  397. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +31 -8
  398. nautobot/project-static/docs/user-guide/platform-functionality/status.html +31 -8
  399. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +31 -8
  400. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +31 -8
  401. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +31 -8
  402. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +31 -8
  403. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +31 -8
  404. nautobot/tenancy/tables.py +2 -0
  405. nautobot/virtualization/tests/test_views.py +1 -1
  406. nautobot/wireless/forms.py +0 -1
  407. nautobot/wireless/models.py +1 -1
  408. nautobot/wireless/tables.py +7 -0
  409. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/METADATA +4 -4
  410. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/RECORD +416 -401
  411. /nautobot/dcim/templates/dcim/{platform_edit.html → platform_create.html} +0 -0
  412. /nautobot/extras/test_jobs/{pass.py → pass_job.py} +0 -0
  413. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/LICENSE.txt +0 -0
  414. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/NOTICE +0 -0
  415. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/WHEEL +0 -0
  416. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,92 @@
1
+ # Generated by Django 4.2.19 on 2025-03-18 17:22
2
+
3
+ import uuid
4
+
5
+ import django.core.serializers.json
6
+ from django.db import migrations, models
7
+ import django.db.models.deletion
8
+
9
+ import nautobot.core.models.fields
10
+ import nautobot.extras.models.mixins
11
+
12
+
13
+ class Migration(migrations.Migration):
14
+ dependencies = [
15
+ ("extras", "0122_add_graphqlquery_owner_content_type"),
16
+ ("dcim", "0069_softwareimagefile_external_integration"),
17
+ ]
18
+
19
+ operations = [
20
+ migrations.AddField(
21
+ model_name="modulebay",
22
+ name="requires_first_party_modules",
23
+ field=models.BooleanField(default=False),
24
+ ),
25
+ migrations.AddField(
26
+ model_name="modulebaytemplate",
27
+ name="requires_first_party_modules",
28
+ field=models.BooleanField(default=False),
29
+ ),
30
+ migrations.CreateModel(
31
+ name="ModuleFamily",
32
+ fields=[
33
+ (
34
+ "id",
35
+ models.UUIDField(
36
+ default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True
37
+ ),
38
+ ),
39
+ ("created", models.DateTimeField(auto_now_add=True, null=True)),
40
+ ("last_updated", models.DateTimeField(auto_now=True, null=True)),
41
+ (
42
+ "_custom_field_data",
43
+ models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
44
+ ),
45
+ ("name", models.CharField(max_length=255, unique=True)),
46
+ ("description", models.CharField(blank=True, max_length=255)),
47
+ ("tags", nautobot.core.models.fields.TagsField(through="extras.TaggedItem", to="extras.Tag")),
48
+ ],
49
+ options={
50
+ "verbose_name_plural": "module families",
51
+ "ordering": ["name"],
52
+ },
53
+ bases=(
54
+ nautobot.extras.models.mixins.DynamicGroupMixin,
55
+ nautobot.extras.models.mixins.NotesMixin,
56
+ models.Model,
57
+ ),
58
+ ),
59
+ migrations.AddField(
60
+ model_name="modulebay",
61
+ name="module_family",
62
+ field=models.ForeignKey(
63
+ blank=True,
64
+ null=True,
65
+ on_delete=django.db.models.deletion.PROTECT,
66
+ related_name="module_bays",
67
+ to="dcim.modulefamily",
68
+ ),
69
+ ),
70
+ migrations.AddField(
71
+ model_name="modulebaytemplate",
72
+ name="module_family",
73
+ field=models.ForeignKey(
74
+ blank=True,
75
+ null=True,
76
+ on_delete=django.db.models.deletion.PROTECT,
77
+ related_name="module_bay_templates",
78
+ to="dcim.modulefamily",
79
+ ),
80
+ ),
81
+ migrations.AddField(
82
+ model_name="moduletype",
83
+ name="module_family",
84
+ field=models.ForeignKey(
85
+ blank=True,
86
+ null=True,
87
+ on_delete=django.db.models.deletion.PROTECT,
88
+ related_name="module_types",
89
+ to="dcim.modulefamily",
90
+ ),
91
+ ),
92
+ ]
@@ -38,6 +38,7 @@ from .devices import (
38
38
  InterfaceVDCAssignment,
39
39
  Manufacturer,
40
40
  Module,
41
+ ModuleFamily,
41
42
  ModuleType,
42
43
  Platform,
43
44
  SoftwareImageFile,
@@ -81,6 +82,7 @@ __all__ = (
81
82
  "Module",
82
83
  "ModuleBay",
83
84
  "ModuleBayTemplate",
85
+ "ModuleFamily",
84
86
  "ModuleType",
85
87
  "PathEndpoint",
86
88
  "Platform",
@@ -481,6 +481,18 @@ class ModuleBayTemplate(ModularComponentTemplateModel):
481
481
  )
482
482
  label = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Physical label")
483
483
  description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
484
+ module_family = models.ForeignKey(
485
+ to="dcim.ModuleFamily",
486
+ on_delete=models.PROTECT,
487
+ related_name="module_bay_templates",
488
+ blank=True,
489
+ null=True,
490
+ help_text="Module family that can be installed in this bay. Leave blank for no restriction.",
491
+ )
492
+ requires_first_party_modules = models.BooleanField(
493
+ default=False,
494
+ help_text="This bay will only accept modules from the same manufacturer as the parent device or module",
495
+ )
484
496
 
485
497
  natural_key_field_names = ["device_type", "module_type", "name"]
486
498
 
@@ -505,6 +517,8 @@ class ModuleBayTemplate(ModularComponentTemplateModel):
505
517
  position=self.position,
506
518
  label=self.label,
507
519
  description=self.description,
520
+ module_family=self.module_family,
521
+ requires_first_party_modules=self.requires_first_party_modules,
508
522
  _custom_field_data=custom_field_data,
509
523
  )
510
524
 
@@ -1218,6 +1218,18 @@ class ModuleBay(PrimaryModel):
1218
1218
  blank=True,
1219
1219
  null=True,
1220
1220
  )
1221
+ module_family = models.ForeignKey(
1222
+ to="dcim.ModuleFamily",
1223
+ on_delete=models.PROTECT,
1224
+ related_name="module_bays",
1225
+ blank=True,
1226
+ null=True,
1227
+ help_text="Module family that can be installed in this bay",
1228
+ )
1229
+ requires_first_party_modules = models.BooleanField(
1230
+ default=False,
1231
+ help_text="This bay will only accept modules from the same manufacturer as the parent device or module",
1232
+ )
1221
1233
  name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, db_index=True)
1222
1234
  _name = NaturalOrderingField(target_field="name", max_length=CHARFIELD_MAX_LENGTH, blank=True, db_index=True)
1223
1235
  position = models.CharField(
@@ -1228,7 +1240,7 @@ class ModuleBay(PrimaryModel):
1228
1240
  label = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Physical label")
1229
1241
  description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
1230
1242
 
1231
- clone_fields = ["parent_device", "parent_module"]
1243
+ clone_fields = ["parent_device", "parent_module", "module_family", "requires_first_party_modules"]
1232
1244
 
1233
1245
  # The recursive nature of this model combined with the fact that it can be a child of a
1234
1246
  # device or location makes our natural key implementation unusable, so just use the pk
@@ -1550,6 +1550,30 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
1550
1550
  #
1551
1551
 
1552
1552
 
1553
+ @extras_features(
1554
+ "custom_links",
1555
+ "custom_validators",
1556
+ "export_templates",
1557
+ "graphql",
1558
+ "webhooks",
1559
+ )
1560
+ class ModuleFamily(PrimaryModel):
1561
+ """
1562
+ A ModuleFamily represents a classification of ModuleTypes.
1563
+ It is used to enforce compatibility between ModuleBays and Modules.
1564
+ """
1565
+
1566
+ name = models.CharField(max_length=CHARFIELD_MAX_LENGTH, unique=True)
1567
+ description = models.CharField(max_length=CHARFIELD_MAX_LENGTH, blank=True)
1568
+
1569
+ class Meta:
1570
+ ordering = ["name"]
1571
+ verbose_name_plural = "module families"
1572
+
1573
+ def __str__(self):
1574
+ return self.name
1575
+
1576
+
1553
1577
  # TODO: 5840 - Translate comments field from devicetype library, Nautobot doesn't use that field for ModuleType
1554
1578
  @extras_features(
1555
1579
  "custom_links",
@@ -1577,6 +1601,13 @@ class ModuleType(PrimaryModel):
1577
1601
  """
1578
1602
 
1579
1603
  manufacturer = models.ForeignKey(to="dcim.Manufacturer", on_delete=models.PROTECT, related_name="module_types")
1604
+ module_family = models.ForeignKey(
1605
+ to="dcim.ModuleFamily",
1606
+ on_delete=models.PROTECT,
1607
+ related_name="module_types",
1608
+ blank=True,
1609
+ null=True,
1610
+ )
1580
1611
  model = models.CharField(max_length=CHARFIELD_MAX_LENGTH)
1581
1612
  part_number = models.CharField(
1582
1613
  max_length=CHARFIELD_MAX_LENGTH, blank=True, help_text="Discrete part number (optional)"
@@ -1585,6 +1616,7 @@ class ModuleType(PrimaryModel):
1585
1616
 
1586
1617
  clone_fields = [
1587
1618
  "manufacturer",
1619
+ "module_family",
1588
1620
  ]
1589
1621
 
1590
1622
  class Meta:
@@ -1810,6 +1842,36 @@ class Module(PrimaryModel):
1810
1842
  {"location": f'Modules may not associate to locations of type "{self.location.location_type}".'}
1811
1843
  )
1812
1844
 
1845
+ # Validate module family compatibility
1846
+ if self.parent_module_bay and self.parent_module_bay.module_family:
1847
+ if self.module_type.module_family != self.parent_module_bay.module_family:
1848
+ module_family_name = self.parent_module_bay.module_family.name
1849
+ if self.module_type.module_family is None:
1850
+ module_type_family = "not assigned to a family"
1851
+ else:
1852
+ module_type_family = f"in the family {self.module_type.module_family.name}"
1853
+ raise ValidationError(
1854
+ {
1855
+ "module_type": f"The selected module bay requires a module type in the family {module_family_name}, "
1856
+ f"but the selected module type is {module_type_family}."
1857
+ }
1858
+ )
1859
+
1860
+ # Validate module manufacturer constraint
1861
+ if self.parent_module_bay and self.parent_module_bay.requires_first_party_modules:
1862
+ if self.parent_module_bay.parent_device:
1863
+ parent_mfr = self.parent_module_bay.parent_device.device_type.manufacturer
1864
+ elif self.parent_module_bay.parent_module:
1865
+ parent_mfr = self.parent_module_bay.parent_module.module_type.manufacturer
1866
+ else:
1867
+ parent_mfr = None
1868
+ if parent_mfr and self.module_type.manufacturer != parent_mfr:
1869
+ raise ValidationError(
1870
+ {
1871
+ "module_type": "The selected module bay requires a module type from the same manufacturer as the parent device or module"
1872
+ }
1873
+ )
1874
+
1813
1875
  def save(self, *args, **kwargs):
1814
1876
  is_new = not self.present_in_database
1815
1877
 
@@ -293,6 +293,22 @@ menu_items = (
293
293
  ),
294
294
  ),
295
295
  ),
296
+ NavMenuItem(
297
+ link="dcim:modulefamily_list",
298
+ name="Module Families",
299
+ weight=300,
300
+ permissions=[
301
+ "dcim.view_modulefamily",
302
+ ],
303
+ buttons=(
304
+ NavMenuAddButton(
305
+ link="dcim:modulefamily_add",
306
+ permissions=[
307
+ "dcim.add_modulefamily",
308
+ ],
309
+ ),
310
+ ),
311
+ ),
296
312
  ),
297
313
  ),
298
314
  NavMenuGroup(
@@ -30,6 +30,7 @@ from .devices import (
30
30
  InterfaceTable,
31
31
  InventoryItemTable,
32
32
  ModuleBayTable,
33
+ ModuleFamilyTable,
33
34
  ModuleModuleBayTable,
34
35
  ModuleTable,
35
36
  PlatformTable,
@@ -104,6 +105,7 @@ __all__ = (
104
105
  "ManufacturerTable",
105
106
  "ModuleBayTable",
106
107
  "ModuleBayTemplateTable",
108
+ "ModuleFamilyTable",
107
109
  "ModuleModuleBayTable",
108
110
  "ModuleTable",
109
111
  "ModuleTypeTable",
@@ -26,6 +26,7 @@ from nautobot.dcim.models import (
26
26
  InventoryItem,
27
27
  Module,
28
28
  ModuleBay,
29
+ ModuleFamily,
29
30
  Platform,
30
31
  PowerOutlet,
31
32
  PowerPort,
@@ -86,6 +87,7 @@ __all__ = (
86
87
  "InterfaceTable",
87
88
  "InventoryItemTable",
88
89
  "ModuleBayTable",
90
+ "ModuleFamilyTable",
89
91
  "ModuleModuleBayTable",
90
92
  "ModuleTable",
91
93
  "PlatformTable",
@@ -275,6 +277,7 @@ class ModuleTable(StatusTableMixin, RoleTableMixin, BaseTable):
275
277
  )
276
278
  location = tables.Column(linkify=True)
277
279
  tenant = TenantColumn()
280
+ module_type__module_family = tables.Column(linkify=True, verbose_name="Family")
278
281
  tags = TagColumn(url_name="dcim:module_list")
279
282
  actions = ButtonsColumn(Module, prepend_template=MODULE_BUTTONS)
280
283
 
@@ -283,6 +286,7 @@ class ModuleTable(StatusTableMixin, RoleTableMixin, BaseTable):
283
286
  fields = (
284
287
  "pk",
285
288
  "module_type",
289
+ "module_family",
286
290
  "parent_module_bay",
287
291
  "location",
288
292
  "serial",
@@ -296,6 +300,7 @@ class ModuleTable(StatusTableMixin, RoleTableMixin, BaseTable):
296
300
  default_columns = (
297
301
  "pk",
298
302
  "module_type",
303
+ "module_family",
299
304
  "parent_module_bay",
300
305
  "location",
301
306
  "serial",
@@ -307,6 +312,40 @@ class ModuleTable(StatusTableMixin, RoleTableMixin, BaseTable):
307
312
  )
308
313
 
309
314
 
315
+ class ModuleFamilyTable(BaseTable):
316
+ pk = ToggleColumn()
317
+ name = tables.Column(linkify=True)
318
+ module_type_count = LinkedCountColumn(
319
+ viewname="dcim:moduletype_list", url_params={"module_family": "pk"}, verbose_name="Module Types"
320
+ )
321
+ module_bay_count = LinkedCountColumn(
322
+ viewname="dcim:modulebay_list", url_params={"module_family": "pk"}, verbose_name="Module Bays"
323
+ )
324
+ tags = TagColumn()
325
+ actions = ButtonsColumn(ModuleFamily)
326
+
327
+ class Meta(BaseTable.Meta):
328
+ model = ModuleFamily
329
+ fields = (
330
+ "pk",
331
+ "name",
332
+ "description",
333
+ "module_type_count",
334
+ "module_bay_count",
335
+ "tags",
336
+ "created",
337
+ "last_updated",
338
+ "actions",
339
+ )
340
+ default_columns = (
341
+ "name",
342
+ "description",
343
+ "module_type_count",
344
+ "module_bay_count",
345
+ "actions",
346
+ )
347
+
348
+
310
349
  #
311
350
  # Device components
312
351
  #
@@ -943,6 +982,7 @@ class ModuleBayTable(BaseTable):
943
982
  installed_module = tables.Column(linkify=True, verbose_name="Installed Module")
944
983
  installed_module__status = ColoredLabelColumn()
945
984
  tags = TagColumn(url_name="dcim:devicebay_list")
985
+ module_family = tables.Column(linkify=True, verbose_name="Family")
946
986
 
947
987
  class Meta(BaseTable.Meta):
948
988
  model = ModuleBay
@@ -953,6 +993,7 @@ class ModuleBayTable(BaseTable):
953
993
  "name",
954
994
  "position",
955
995
  "label",
996
+ "module_family",
956
997
  "description",
957
998
  "installed_module",
958
999
  "installed_module__status",
@@ -965,6 +1006,7 @@ class ModuleBayTable(BaseTable):
965
1006
  "name",
966
1007
  "position",
967
1008
  "label",
1009
+ "module_family",
968
1010
  "description",
969
1011
  "installed_module",
970
1012
  "installed_module__status",
@@ -1008,8 +1050,10 @@ class DeviceModuleBayTable(ModuleBayTable):
1008
1050
  '"></i> <a href="{{ record.get_absolute_url }}">{{ value }}</a>',
1009
1051
  attrs={"td": {"class": "text-nowrap"}},
1010
1052
  )
1053
+ module_family = tables.Column(linkify=True, verbose_name="Family")
1011
1054
  installed_module = tables.Column(linkify=True, verbose_name="Installed Module")
1012
1055
  installed_module__status = ColoredLabelColumn(verbose_name="Installed Module Status")
1056
+ requires_first_party_modules = BooleanColumn(verbose_name="First-Party Only")
1013
1057
  actions = ButtonsColumn(model=ModuleBay, buttons=("edit", "delete"), prepend_template=MODULEBAY_BUTTONS)
1014
1058
 
1015
1059
  class Meta(ModularDeviceComponentTable.Meta):
@@ -1018,6 +1062,8 @@ class DeviceModuleBayTable(ModuleBayTable):
1018
1062
  "pk",
1019
1063
  "name",
1020
1064
  "position",
1065
+ "module_family",
1066
+ "requires_first_party_modules",
1021
1067
  "installed_module",
1022
1068
  "installed_module__status",
1023
1069
  "label",
@@ -1029,6 +1075,8 @@ class DeviceModuleBayTable(ModuleBayTable):
1029
1075
  "pk",
1030
1076
  "name",
1031
1077
  "position",
1078
+ "module_family",
1079
+ "requires_first_party_modules",
1032
1080
  "installed_module",
1033
1081
  "installed_module__status",
1034
1082
  "actions",
@@ -158,6 +158,7 @@ class ModuleTypeTable(BaseTable):
158
158
  pk = ToggleColumn()
159
159
  manufacturer = tables.Column(linkify=True)
160
160
  model = tables.Column(linkify=True, verbose_name="Module Type")
161
+ module_family = tables.Column(linkify=True, verbose_name="Family")
161
162
  module_count = LinkedCountColumn(
162
163
  viewname="dcim:module_list",
163
164
  url_params={"module_type": "pk"},
@@ -172,6 +173,7 @@ class ModuleTypeTable(BaseTable):
172
173
  "model",
173
174
  "manufacturer",
174
175
  "part_number",
176
+ "module_family",
175
177
  "module_count",
176
178
  "tags",
177
179
  )
@@ -180,6 +182,7 @@ class ModuleTypeTable(BaseTable):
180
182
  "model",
181
183
  "manufacturer",
182
184
  "part_number",
185
+ "module_family",
183
186
  "module_count",
184
187
  )
185
188
 
@@ -333,8 +336,39 @@ class ModuleBayTemplateTable(ComponentTemplateTable):
333
336
  buttons=("edit", "delete"),
334
337
  return_url_extra=r"%3Ftab=modulebays",
335
338
  )
339
+ module_family = tables.Column(verbose_name="Family", linkify=True)
340
+ requires_first_party_modules = BooleanColumn(verbose_name="Requires First-Party Modules")
336
341
 
337
342
  class Meta(BaseTable.Meta):
338
343
  model = ModuleBayTemplate
339
- fields = ("pk", "name", "position", "label", "description", "actions")
344
+ fields = (
345
+ "pk",
346
+ "name",
347
+ "position",
348
+ "module_family",
349
+ "label",
350
+ "requires_first_party_modules",
351
+ "description",
352
+ "actions",
353
+ )
354
+ default_columns = (
355
+ "pk",
356
+ "name",
357
+ "position",
358
+ "module_family",
359
+ "label",
360
+ "requires_first_party_modules",
361
+ "description",
362
+ "actions",
363
+ )
364
+ field_order = (
365
+ "pk",
366
+ "name",
367
+ "position",
368
+ "module_family",
369
+ "label",
370
+ "requires_first_party_modules",
371
+ "description",
372
+ "actions",
373
+ )
340
374
  empty_text = "None"
@@ -93,7 +93,9 @@ LINKED_RECORD_COUNT = """
93
93
 
94
94
  TREE_LINK = """
95
95
  {% load helpers %}
96
+ {% if not table.hide_hierarchy_ui %}
96
97
  {% tree_hierarchy_ui_representation record.tree_depth|as_range table.hide_hierarchy_ui %}
98
+ {% endif %}
97
99
  <a href="{{ record.get_absolute_url }}">{{ record.name }}</a>
98
100
  """
99
101
 
@@ -1,91 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_nav_tabs %}
5
- {% if wireless_networks_count %}
6
- <li role="presentation"{% if request.GET.tab == 'wireless_networks' %} class="active"{% endif %}>
7
- <a href="{{ object.get_absolute_url }}#wireless_networks" onclick="switch_tab(this.href, reload=false)" aria-controls="wireless_networks" role="tab" data-toggle="tab">
8
- Wireless Networks {% badge wireless_networks_count %}
9
- </a>
10
- </li>
11
- {% endif %}
12
- {% if radio_profiles_count %}
13
- <li role="presentation"{% if request.GET.tab == 'radio_profiles' %} class="active"{% endif %}>
14
- <a href="{{ object.get_absolute_url }}#radio_profiles" onclick="switch_tab(this.href, reload=false)" aria-controls="radio_profiles" role="tab" data-toggle="tab">
15
- Radio Profiles {% badge radio_profiles_count %}
16
- </a>
17
- </li>
18
- {% endif %}
19
- {% endblock extra_nav_tabs %}
20
-
21
- {% block extra_tab_content %}
22
- {% if wireless_networks_count %}
23
- <div id="wireless_networks" role="tabpanel" class="tab-pane {% if not active_tab and not request.GET.tab or request.GET.tab == "wireless_networks" %}active{% else %}fade{% endif %}">
24
- <div class="panel panel-default">
25
- <div class="panel-heading">
26
- <strong>Wireless Networks</strong>
27
- </div>
28
- {% include 'inc/table.html' with table=wireless_networks_table %}
29
- </div>
30
- {% include 'inc/paginator.html' with paginator=wireless_networks_table.paginator page=wireless_networks_table.page %}
31
- </div>
32
- {% endif %}
33
- {% if radio_profiles_count %}
34
- <div id="radio_profiles" role="tabpanel" class="tab-pane {% if not active_tab and not request.GET.tab or request.GET.tab == "radio_profiles" %}active{% else %}fade{% endif %}">
35
- <div class="panel panel-default">
36
- <div class="panel-heading">
37
- <strong>Radio Profiles</strong>
38
- </div>
39
- {% include 'panel_table.html' with table=radio_profiles_table %}
40
- </div>
41
- {% include 'inc/paginator.html' with paginator=radio_profiles_table.paginator page=radio_profiles_table.page %}
42
- </div>
43
- {% endif %}
44
- {% endblock extra_tab_content %}
45
-
46
- {% block content_left_page %}
47
- <div class="panel panel-default">
48
- <div class="panel-heading">
49
- <strong>Controller</strong>
50
- </div>
51
- <div class="table-responsive">
52
- <table class="table table-hover panel-body attr-table">
53
- <tr>
54
- <td>Name</td>
55
- <td>{{ object.name|placeholder }}</td>
56
- </tr>
57
- <tr>
58
- <td>Controller</td>
59
- <td>{{ object.controller|hyperlinked_object }}</td>
60
- </tr>
61
- <tr>
62
- <td>Parent</td>
63
- <td>{{ object.parent|hyperlinked_object }}</td>
64
- </tr>
65
- <tr>
66
- <td>Capabilities</td>
67
- <td>{{ object.get_capabilities_display }}</td>
68
- </tr>
69
- <tr>
70
- <td>Weight</td>
71
- <td>{{ object.weight }}</td>
72
- </tr>
73
- {% include 'inc/tenant_table_row.html' %}
74
- <tr>
75
- <td>Description</td>
76
- <td>{{ object.description|placeholder }}</td>
77
- </tr>
78
- </table>
79
- </div>
80
- </div>
81
- {% endblock content_left_page %}
82
-
83
- {% block content_full_width_page %}
84
- <div class="panel panel-default">
85
- <div class="panel-heading">
86
- <strong>Devices</strong>
87
- </div>
88
- {% include 'responsive_table.html' with table=devices_table %}
89
- </div>
90
- {% include 'inc/paginator.html' with paginator=devices_table.paginator page=devices_table.page %}
91
- {% endblock content_full_width_page %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -10,7 +10,7 @@
10
10
  {% endif %}
11
11
  {% endif %}
12
12
  {% if perms.dcim.delete_cable %}
13
- <a href="{% url 'dcim:cable_delete' pk=cable.pk %}?return_url={{ object.get_absolute_url }}" title="Remove cable" class="btn btn-danger btn-xs">
13
+ <a href="{% url 'dcim:cable_delete' pk=cable.pk %}?return_url={{ request.path }}" title="Remove cable" class="btn btn-danger btn-xs">
14
14
  <i class="mdi mdi-ethernet-cable-off" aria-hidden="true"></i>
15
15
  </a>
16
16
  {% endif %}
@@ -1,64 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_buttons %}
5
- {% if perms.dcim.change_interfaceredundancygroup %}
6
-
7
- <div class="btn-group">
8
- <a href="{% url 'dcim:interfaceredundancygroupassociation_add' %}?interface_redundancy_group={{ object.pk }}&return_url={% url 'dcim:interfaceredundancygroup' pk=object.pk %}"
9
- class="btn btn-primary">
10
- <span class="mdi mdi-plus-thick" aria-hidden="true"></span>
11
- Add Interface
12
- </a>
13
- </div>
14
-
15
- {% endif %}
16
- {% endblock extra_buttons %}
17
-
18
-
19
- {% block content_left_page %}
20
- <div class="panel panel-default">
21
- <div class="panel-heading">
22
- <strong>Interface Redundancy Group</strong>
23
- </div>
24
- <table class="table table-hover panel-body attr-table">
25
- <tr>
26
- <td>Status</td>
27
- <td>
28
- <span class="label" style="color: {{ object.status.color|fgcolor }};
29
- background-color: #{{ object.status.color }}">{{ object.get_status_display }}
30
- </span>
31
- </td>
32
- </tr>
33
- <tr>
34
- <td>Description</td>
35
- <td>{{ object.description | placeholder }}</td>
36
- </tr>
37
- <tr>
38
- <td>Virtual IP</td>
39
- <td>{{ object.virtual_ip | hyperlinked_object }}</td>
40
- </tr>
41
- <tr>
42
- <td>Redundancy Protocol</td>
43
- <td>{{ object.protocol | upper | placeholder }}</td>
44
- </tr>
45
- <tr>
46
- <td>Protocol Group ID</td>
47
- <td>{{ object.protocol_group_id | placeholder }}</td>
48
- </tr>
49
- <tr>
50
- <td>Secrets Group</td>
51
- <td>{{ object.secrets_group|hyperlinked_object }}</td>
52
- </tr>
53
- </table>
54
- </div>
55
- {% endblock content_left_page %}
56
-
57
- {% block content_full_width_page %}
58
- <div class="panel panel-default">
59
- <div class="panel-heading">
60
- <strong>Interfaces</strong>
61
- </div>
62
- {% include 'responsive_table.html' with table=interface_table %}
63
- </div>
64
- {% endblock content_full_width_page %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}