nautobot 2.2.9__py3-none-any.whl → 2.3.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/forms.py +4 -0
- nautobot/apps/models.py +10 -1
- nautobot/circuits/__init__.py +0 -1
- nautobot/circuits/apps.py +1 -0
- nautobot/circuits/factory.py +15 -3
- nautobot/circuits/filters.py +13 -0
- nautobot/circuits/forms.py +13 -0
- nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
- nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
- nautobot/circuits/models.py +16 -3
- nautobot/circuits/tables.py +16 -2
- nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
- nautobot/circuits/tests/test_api.py +7 -5
- nautobot/circuits/tests/test_filters.py +12 -5
- nautobot/circuits/tests/test_models.py +33 -2
- nautobot/circuits/views.py +2 -3
- nautobot/cloud/__init__.py +0 -0
- nautobot/cloud/api/__init__.py +0 -0
- nautobot/cloud/api/serializers.py +54 -0
- nautobot/cloud/api/urls.py +16 -0
- nautobot/cloud/api/views.py +48 -0
- nautobot/cloud/apps.py +13 -0
- nautobot/cloud/factory.py +111 -0
- nautobot/cloud/filters.py +184 -0
- nautobot/cloud/forms.py +333 -0
- nautobot/cloud/homepage.py +43 -0
- nautobot/cloud/migrations/0001_initial.py +304 -0
- nautobot/cloud/migrations/__init__.py +0 -0
- nautobot/cloud/models.py +247 -0
- nautobot/cloud/navigation.py +85 -0
- nautobot/cloud/tables.py +173 -0
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +128 -0
- nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +100 -0
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +65 -0
- nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
- nautobot/cloud/tests/__init__.py +0 -0
- nautobot/cloud/tests/test_api.py +248 -0
- nautobot/cloud/tests/test_filters.py +113 -0
- nautobot/cloud/tests/test_models.py +43 -0
- nautobot/cloud/tests/test_views.py +153 -0
- nautobot/cloud/urls.py +14 -0
- nautobot/cloud/views.py +181 -0
- nautobot/core/__init__.py +0 -3
- nautobot/core/api/metadata.py +1 -0
- nautobot/core/api/parsers.py +7 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/utils.py +1 -0
- nautobot/core/api/views.py +4 -0
- nautobot/core/apps/__init__.py +6 -3
- nautobot/core/constants.py +8 -0
- nautobot/core/factory.py +32 -1
- nautobot/core/filters.py +96 -28
- nautobot/core/forms/fields.py +10 -4
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/forms/widgets.py +18 -1
- nautobot/core/graphql/generators.py +2 -2
- nautobot/core/graphql/schema.py +34 -4
- nautobot/core/jobs/__init__.py +17 -6
- nautobot/core/jobs/cleanup.py +100 -0
- nautobot/core/jobs/groups.py +38 -0
- nautobot/core/management/commands/generate_test_data.py +116 -3
- nautobot/core/models/__init__.py +34 -9
- nautobot/core/models/generics.py +19 -3
- nautobot/core/models/name_color_content_types.py +7 -28
- nautobot/core/models/querysets.py +4 -3
- nautobot/core/models/tree_queries.py +1 -1
- nautobot/core/models/utils.py +21 -5
- nautobot/core/settings.py +4 -30
- nautobot/core/settings.yaml +34 -27
- nautobot/core/settings_funcs.py +103 -0
- nautobot/core/tables.py +127 -56
- nautobot/core/templates/admin/search_form.html +1 -1
- nautobot/core/templates/buttons/add.html +11 -3
- nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
- nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
- nautobot/core/templates/buttons/export.html +101 -53
- nautobot/core/templates/buttons/job_import.html +11 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
- nautobot/core/templates/generic/object_bulk_update.html +3 -1
- nautobot/core/templates/generic/object_changelog.html +0 -9
- nautobot/core/templates/generic/object_list.html +156 -17
- nautobot/core/templates/generic/object_retrieve.html +80 -16
- nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
- nautobot/core/templates/inc/javascript.html +2 -0
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/paginator.html +7 -7
- nautobot/core/templates/inc/search_panel.html +2 -2
- nautobot/core/templates/inc/table.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +13 -23
- nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
- nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
- nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
- nautobot/core/templates/utilities/theme_preview.html +25 -8
- nautobot/core/templates/utilities/worker_status.html +152 -0
- nautobot/core/templatetags/buttons.py +335 -38
- nautobot/core/templatetags/form_helpers.py +1 -1
- nautobot/core/templatetags/helpers.py +181 -11
- nautobot/core/testing/api.py +5 -4
- nautobot/core/testing/filters.py +51 -13
- nautobot/core/testing/mixins.py +46 -0
- nautobot/core/testing/models.py +22 -0
- nautobot/core/testing/schema.py +4 -8
- nautobot/core/testing/views.py +31 -14
- nautobot/core/tests/integration/test_general_functionality.py +1 -1
- nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
- nautobot/core/tests/integration/test_swagger.py +1 -1
- nautobot/core/tests/nautobot_config.py +0 -1
- nautobot/core/tests/runner.py +2 -2
- nautobot/core/tests/test_api.py +1 -0
- nautobot/core/tests/test_authentication.py +7 -2
- nautobot/core/tests/test_filters.py +11 -9
- nautobot/core/tests/test_forms.py +9 -0
- nautobot/core/tests/test_graphql.py +27 -16
- nautobot/core/tests/test_jobs.py +123 -74
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +12 -5
- nautobot/core/tests/test_utils.py +31 -20
- nautobot/core/tests/test_views.py +6 -6
- nautobot/core/urls.py +8 -3
- nautobot/core/utils/deprecation.py +29 -0
- nautobot/core/utils/filtering.py +12 -9
- nautobot/core/utils/lookup.py +37 -2
- nautobot/core/utils/requests.py +4 -1
- nautobot/core/views/__init__.py +137 -24
- nautobot/core/views/generic.py +118 -66
- nautobot/core/views/mixins.py +104 -35
- nautobot/core/views/paginator.py +9 -3
- nautobot/core/views/renderers.py +121 -56
- nautobot/core/views/utils.py +79 -1
- nautobot/dcim/__init__.py +0 -1
- nautobot/dcim/api/serializers.py +180 -44
- nautobot/dcim/api/urls.py +7 -3
- nautobot/dcim/api/views.py +53 -7
- nautobot/dcim/apps.py +3 -0
- nautobot/dcim/choices.py +25 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/factory.py +249 -18
- nautobot/dcim/filters/__init__.py +369 -193
- nautobot/dcim/filters/mixins.py +274 -1
- nautobot/dcim/forms.py +817 -109
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/homepage.py +1 -1
- nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
- nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
- nautobot/dcim/migrations/0061_module_models.py +861 -0
- nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
- nautobot/dcim/models/__init__.py +8 -0
- nautobot/dcim/models/cables.py +15 -0
- nautobot/dcim/models/device_component_templates.py +207 -53
- nautobot/dcim/models/device_components.py +275 -106
- nautobot/dcim/models/devices.py +466 -13
- nautobot/dcim/navigation.py +47 -0
- nautobot/dcim/signals.py +3 -3
- nautobot/dcim/tables/__init__.py +35 -23
- nautobot/dcim/tables/devices.py +231 -59
- nautobot/dcim/tables/devicetypes.py +65 -9
- nautobot/dcim/tables/racks.py +5 -1
- nautobot/dcim/tables/template_code.py +46 -26
- nautobot/dcim/templates/dcim/cable_connect.html +76 -3
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/device/base.html +15 -7
- nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
- nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
- nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
- nautobot/dcim/templates/dcim/device/frontports.html +2 -3
- nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
- nautobot/dcim/templates/dcim/device/inventory.html +2 -3
- nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
- nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
- nautobot/dcim/templates/dcim/device/powerports.html +2 -3
- nautobot/dcim/templates/dcim/device/rearports.html +2 -3
- nautobot/dcim/templates/dcim/device.html +45 -1
- nautobot/dcim/templates/dcim/device_component.html +13 -5
- nautobot/dcim/templates/dcim/device_list.html +2 -1
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -6
- nautobot/dcim/templates/dcim/devicetype.html +99 -98
- nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
- nautobot/dcim/templates/dcim/interface.html +17 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/manufacturer.html +24 -0
- nautobot/dcim/templates/dcim/module/base.html +97 -0
- nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
- nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
- nautobot/dcim/templates/dcim/module_destroy.html +5 -0
- nautobot/dcim/templates/dcim/module_frontports.html +53 -0
- nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
- nautobot/dcim/templates/dcim/module_list.html +20 -0
- nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
- nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
- nautobot/dcim/templates/dcim/module_powerports.html +53 -0
- nautobot/dcim/templates/dcim/module_rearports.html +53 -0
- nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
- nautobot/dcim/templates/dcim/module_update.html +71 -0
- nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
- nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
- nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +142 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
- nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
- nautobot/dcim/tests/test_api.py +691 -208
- nautobot/dcim/tests/test_filters.py +836 -217
- nautobot/dcim/tests/test_models.py +1072 -39
- nautobot/dcim/tests/test_views.py +1488 -358
- nautobot/dcim/urls.py +17 -2
- nautobot/dcim/utils.py +2 -3
- nautobot/dcim/views.py +1107 -120
- nautobot/extras/__init__.py +0 -1
- nautobot/extras/api/serializers.py +115 -3
- nautobot/extras/api/urls.py +12 -0
- nautobot/extras/api/views.py +125 -7
- nautobot/extras/apps.py +2 -2
- nautobot/extras/choices.py +43 -0
- nautobot/extras/context_managers.py +13 -8
- nautobot/extras/datasources/git.py +2 -0
- nautobot/extras/factory.py +422 -9
- nautobot/extras/filters/__init__.py +174 -3
- nautobot/extras/filters/mixins.py +46 -43
- nautobot/extras/forms/base.py +17 -4
- nautobot/extras/forms/forms.py +227 -8
- nautobot/extras/forms/mixins.py +93 -0
- nautobot/extras/graphql/types.py +23 -10
- nautobot/extras/homepage.py +16 -13
- nautobot/extras/jobs.py +2 -2
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
- nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
- nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
- nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
- nautobot/extras/migrations/0111_metadata.py +162 -0
- nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
- nautobot/extras/migrations/0113_saved_views.py +77 -0
- nautobot/extras/models/__init__.py +15 -1
- nautobot/extras/models/change_logging.py +3 -3
- nautobot/extras/models/contacts.py +4 -0
- nautobot/extras/models/customfields.py +18 -3
- nautobot/extras/models/groups.py +389 -225
- nautobot/extras/models/jobs.py +4 -84
- nautobot/extras/models/metadata.py +441 -0
- nautobot/extras/models/mixins.py +72 -62
- nautobot/extras/models/models.py +116 -9
- nautobot/extras/models/relationships.py +9 -2
- nautobot/extras/models/tags.py +13 -2
- nautobot/extras/navigation.py +57 -0
- nautobot/extras/plugins/__init__.py +3 -1
- nautobot/extras/querysets.py +30 -66
- nautobot/extras/signals.py +96 -114
- nautobot/extras/tables.py +171 -47
- nautobot/extras/templates/extras/dynamicgroup.html +44 -15
- nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
- nautobot/extras/templates/extras/job.html +1 -1
- nautobot/extras/templates/extras/job_detail.html +0 -11
- nautobot/extras/templates/extras/jobresult.html +61 -74
- nautobot/extras/templates/extras/metadatatype_create.html +89 -0
- nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
- nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
- nautobot/extras/templates/extras/objectchange_list.html +0 -12
- nautobot/extras/templates/extras/plugins_list.html +1 -3
- nautobot/extras/templates/extras/role_retrieve.html +48 -0
- nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
- nautobot/extras/tests/integration/test_customfields.py +1 -0
- nautobot/extras/tests/test_api.py +501 -22
- nautobot/extras/tests/test_changelog.py +20 -9
- nautobot/extras/tests/test_context_managers.py +22 -15
- nautobot/extras/tests/test_datasources.py +13 -1
- nautobot/extras/tests/test_dynamicgroups.py +201 -171
- nautobot/extras/tests/test_filters.py +211 -12
- nautobot/extras/tests/test_jobs.py +4 -4
- nautobot/extras/tests/test_models.py +499 -4
- nautobot/extras/tests/test_relationships.py +1 -0
- nautobot/extras/tests/test_views.py +565 -28
- nautobot/extras/tests/test_webhooks.py +1 -1
- nautobot/extras/urls.py +5 -0
- nautobot/extras/utils.py +56 -45
- nautobot/extras/views.py +585 -96
- nautobot/ipam/__init__.py +0 -1
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/factory.py +17 -19
- nautobot/ipam/filters.py +14 -1
- nautobot/ipam/forms.py +9 -5
- nautobot/ipam/graphql/types.py +2 -2
- nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
- nautobot/ipam/models.py +23 -9
- nautobot/ipam/querysets.py +1 -1
- nautobot/ipam/signals.py +4 -2
- nautobot/ipam/tables.py +1 -0
- nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/prefix.html +1 -0
- nautobot/ipam/tests/test_api.py +37 -18
- nautobot/ipam/tests/test_filters.py +26 -2
- nautobot/ipam/tests/test_models.py +8 -3
- nautobot/ipam/tests/test_querysets.py +1 -1
- nautobot/ipam/tests/test_views.py +3 -2
- nautobot/ipam/urls.py +2 -2
- nautobot/ipam/views.py +25 -28
- nautobot/project-static/css/base.css +20 -1
- nautobot/project-static/css/dark.css +11 -0
- nautobot/project-static/docs/404.html +884 -80
- nautobot/project-static/docs/apps/index.html +884 -80
- nautobot/project-static/docs/apps/nautobot-apps.html +884 -80
- nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +911 -112
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +896 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1457 -790
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +927 -136
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +969 -180
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +893 -91
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +889 -85
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +983 -185
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +938 -143
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1064 -274
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1190 -346
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1663 -865
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1156 -373
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2200 -1502
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2229 -1421
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +904 -103
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +955 -155
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1002 -215
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1911 -1275
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1835 -1091
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +896 -93
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2323 -1693
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1785 -1023
- nautobot/project-static/docs/development/apps/api/configuration-view.html +884 -80
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/global-search.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/graphql.html +884 -80
- nautobot/project-static/docs/development/apps/api/models/index.html +922 -81
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +884 -80
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +884 -80
- nautobot/project-static/docs/development/apps/api/prometheus.html +884 -80
- nautobot/project-static/docs/development/apps/api/setup.html +884 -80
- nautobot/project-static/docs/development/apps/api/testing.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +884 -80
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/base-template.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/index.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/notes.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +884 -80
- nautobot/project-static/docs/development/apps/api/views/urls.html +884 -80
- nautobot/project-static/docs/development/apps/index.html +884 -80
- nautobot/project-static/docs/development/apps/migration/code-updates.html +884 -80
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +884 -80
- nautobot/project-static/docs/development/apps/migration/from-v1.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +884 -80
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +884 -80
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +884 -80
- nautobot/project-static/docs/development/core/application-registry.html +884 -80
- nautobot/project-static/docs/development/core/best-practices.html +885 -80
- nautobot/project-static/docs/development/core/bootstrap-ui.html +884 -80
- nautobot/project-static/docs/development/core/caching.html +884 -80
- nautobot/project-static/docs/development/core/controllers.html +884 -80
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +884 -80
- nautobot/project-static/docs/development/core/generic-views.html +884 -80
- nautobot/project-static/docs/development/core/getting-started.html +884 -80
- nautobot/project-static/docs/development/core/homepage.html +884 -80
- nautobot/project-static/docs/development/core/index.html +884 -91
- nautobot/project-static/docs/development/core/model-checklist.html +887 -81
- nautobot/project-static/docs/development/core/model-features.html +884 -80
- nautobot/project-static/docs/development/core/natural-keys.html +884 -80
- nautobot/project-static/docs/development/core/navigation-menu.html +884 -80
- nautobot/project-static/docs/development/core/release-checklist.html +887 -83
- nautobot/project-static/docs/development/core/role-internals.html +884 -80
- nautobot/project-static/docs/development/core/settings.html +884 -80
- nautobot/project-static/docs/development/core/style-guide.html +885 -81
- nautobot/project-static/docs/development/core/templates.html +896 -81
- nautobot/project-static/docs/development/core/testing.html +884 -80
- nautobot/project-static/docs/development/core/user-preferences.html +884 -80
- nautobot/project-static/docs/development/index.html +884 -80
- nautobot/project-static/docs/development/jobs/index.html +1247 -457
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +884 -80
- nautobot/project-static/docs/index.html +13 -8228
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
- nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
- nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
- nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
- nautobot/project-static/docs/models/dcim/module.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
- nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
- nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
- nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
- nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
- nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
- nautobot/project-static/docs/models/extras/role.html +15 -0
- nautobot/project-static/docs/models/extras/savedview.html +15 -0
- nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
- nautobot/project-static/docs/models/extras/status.html +15 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +892 -81
- nautobot/project-static/docs/overview/design_philosophy.html +886 -82
- nautobot/project-static/docs/overview/index.html +9032 -13
- nautobot/project-static/docs/release-notes/index.html +887 -83
- nautobot/project-static/docs/release-notes/version-1.0.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.1.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.2.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.3.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.4.html +884 -80
- nautobot/project-static/docs/release-notes/version-1.5.html +885 -81
- nautobot/project-static/docs/release-notes/version-1.6.html +885 -81
- nautobot/project-static/docs/release-notes/version-2.0.html +884 -80
- nautobot/project-static/docs/release-notes/version-2.1.html +884 -80
- nautobot/project-static/docs/release-notes/version-2.2.html +990 -323
- nautobot/project-static/docs/release-notes/version-2.3.html +9524 -0
- nautobot/project-static/docs/requirements.txt +4 -4
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +335 -260
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +983 -197
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +884 -80
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +888 -84
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +884 -80
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/index.html +888 -80
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation/services.html +888 -80
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +900 -91
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +884 -80
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +884 -80
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +884 -80
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +884 -80
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +915 -163
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +884 -80
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +885 -81
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +888 -80
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +887 -83
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +910 -92
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +915 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +905 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +912 -108
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +913 -109
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +906 -97
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +918 -100
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +928 -110
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +920 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +929 -111
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +920 -102
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +913 -109
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +914 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +908 -104
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +932 -75
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +916 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +935 -78
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +913 -95
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +921 -117
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +910 -106
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +914 -96
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +916 -98
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +898 -94
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +889 -81
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +889 -81
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +893 -88
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +884 -80
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +889 -81
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +884 -80
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +884 -80
- nautobot/project-static/docs/user-guide/index.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1250 -777
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +888 -80
- nautobot/project-static/docs/user-guide/platform-functionality/metadata.html +8948 -0
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +887 -83
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +942 -113
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +884 -80
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +884 -80
- nautobot/project-static/js/forms.js +71 -0
- nautobot/project-static/js/table_sorting_indicator.js +46 -0
- nautobot/project-static/js/tableconfig.js +6 -1
- nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
- nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/tenancy/__init__.py +0 -1
- nautobot/tenancy/apps.py +1 -0
- nautobot/tenancy/factory.py +3 -2
- nautobot/tenancy/filters/__init__.py +1 -0
- nautobot/tenancy/forms.py +1 -1
- nautobot/tenancy/templates/tenancy/tenant.html +22 -18
- nautobot/tenancy/views.py +11 -10
- nautobot/users/__init__.py +0 -1
- nautobot/users/api/serializers.py +1 -1
- nautobot/users/api/views.py +4 -2
- nautobot/users/apps.py +3 -2
- nautobot/users/factory.py +3 -3
- nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
- nautobot/users/models.py +12 -0
- nautobot/users/tests/test_filters.py +6 -3
- nautobot/users/urls.py +8 -0
- nautobot/virtualization/__init__.py +0 -1
- nautobot/virtualization/apps.py +1 -0
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/forms.py +11 -3
- nautobot/virtualization/graphql/types.py +2 -2
- nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
- nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
- nautobot/virtualization/tables.py +15 -5
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
- nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
- nautobot/virtualization/tests/test_api.py +9 -4
- nautobot/virtualization/tests/test_filters.py +22 -0
- nautobot/virtualization/tests/test_models.py +7 -3
- nautobot/virtualization/tests/test_views.py +19 -3
- nautobot/virtualization/urls.py +2 -2
- nautobot/virtualization/views.py +10 -32
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/METADATA +21 -19
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/RECORD +679 -559
- nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
- nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
- nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
- nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
- nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
- nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
- nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
- nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
- nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
- nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
- /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.9.dist-info → nautobot-2.3.0b1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/forms.py
CHANGED
|
@@ -49,11 +49,21 @@ from nautobot.extras.forms import (
|
|
|
49
49
|
NoteModelFormMixin,
|
|
50
50
|
RoleModelBulkEditFormMixin,
|
|
51
51
|
RoleModelFilterFormMixin,
|
|
52
|
+
RoleNotRequiredModelFormMixin,
|
|
52
53
|
StatusModelBulkEditFormMixin,
|
|
53
54
|
StatusModelFilterFormMixin,
|
|
54
55
|
TagsBulkEditFormMixin,
|
|
55
56
|
)
|
|
56
|
-
from nautobot.extras.models import
|
|
57
|
+
from nautobot.extras.models import (
|
|
58
|
+
Contact,
|
|
59
|
+
ContactAssociation,
|
|
60
|
+
ExternalIntegration,
|
|
61
|
+
Role,
|
|
62
|
+
SecretsGroup,
|
|
63
|
+
Status,
|
|
64
|
+
Tag,
|
|
65
|
+
Team,
|
|
66
|
+
)
|
|
57
67
|
from nautobot.ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
|
|
58
68
|
from nautobot.ipam.models import IPAddress, IPAddressToInterface, VLAN, VLANLocationAssignment, VRF
|
|
59
69
|
from nautobot.tenancy.forms import TenancyFilterForm, TenancyForm
|
|
@@ -113,6 +123,10 @@ from .models import (
|
|
|
113
123
|
Location,
|
|
114
124
|
LocationType,
|
|
115
125
|
Manufacturer,
|
|
126
|
+
Module,
|
|
127
|
+
ModuleBay,
|
|
128
|
+
ModuleBayTemplate,
|
|
129
|
+
ModuleType,
|
|
116
130
|
Platform,
|
|
117
131
|
PowerFeed,
|
|
118
132
|
PowerOutlet,
|
|
@@ -172,6 +186,14 @@ class DeviceComponentFilterForm(NautobotFilterForm):
|
|
|
172
186
|
)
|
|
173
187
|
|
|
174
188
|
|
|
189
|
+
class ModularDeviceComponentFilterForm(DeviceComponentFilterForm):
|
|
190
|
+
module = DynamicModelMultipleChoiceField(
|
|
191
|
+
queryset=Module.objects.all(),
|
|
192
|
+
required=False,
|
|
193
|
+
label="Module",
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
|
|
175
197
|
class InterfaceCommonForm(forms.Form):
|
|
176
198
|
def clean(self):
|
|
177
199
|
super().clean()
|
|
@@ -242,6 +264,26 @@ class ComponentForm(BootstrapMixin, forms.Form):
|
|
|
242
264
|
)
|
|
243
265
|
|
|
244
266
|
|
|
267
|
+
class ModularComponentForm(ComponentForm):
|
|
268
|
+
name_pattern = ExpandableNameField(
|
|
269
|
+
label="Name",
|
|
270
|
+
help_text="""
|
|
271
|
+
Alphanumeric ranges are supported for bulk creation. Mixed cases and types within a single range
|
|
272
|
+
are not supported. Examples:
|
|
273
|
+
<ul>
|
|
274
|
+
<li><code>[ge,xe]-0/0/[0-9]</code></li>
|
|
275
|
+
<li><code>e[0-3][a-d,f]</code></li>
|
|
276
|
+
</ul>
|
|
277
|
+
|
|
278
|
+
The variables <code>{module}</code>, <code>{module.parent}</code>, <code>{module.parent.parent}</code>, etc.
|
|
279
|
+
may be used in the name field and will be replaced by the <code>position</code> of the module bay that the
|
|
280
|
+
module occupies (skipping over any bays with a blank <code>position</code>). These variables can be used
|
|
281
|
+
multiple times in the component name and there is no limit to the depth of parent levels.
|
|
282
|
+
Any variables that cannot be replaced by a suitable position value will remain unchanged.
|
|
283
|
+
""",
|
|
284
|
+
)
|
|
285
|
+
|
|
286
|
+
|
|
245
287
|
#
|
|
246
288
|
# Fields
|
|
247
289
|
#
|
|
@@ -897,48 +939,156 @@ class DeviceTypeFilterForm(NautobotFilterForm):
|
|
|
897
939
|
tags = TagFilterField(model)
|
|
898
940
|
|
|
899
941
|
|
|
942
|
+
#
|
|
943
|
+
# Module types
|
|
944
|
+
#
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
class ModuleTypeForm(NautobotModelForm):
|
|
948
|
+
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all())
|
|
949
|
+
|
|
950
|
+
class Meta:
|
|
951
|
+
model = ModuleType
|
|
952
|
+
fields = [
|
|
953
|
+
"manufacturer",
|
|
954
|
+
"model",
|
|
955
|
+
"part_number",
|
|
956
|
+
"tags",
|
|
957
|
+
]
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
class ModuleTypeImportForm(BootstrapMixin, forms.ModelForm):
|
|
961
|
+
"""
|
|
962
|
+
Form for JSON/YAML import of ModuleType objects.
|
|
963
|
+
|
|
964
|
+
TODO: at some point we'll want to add general-purpose YAML serialization/deserialization,
|
|
965
|
+
similar to what we've done for CSV in 2.0, but for the moment we're leaving this as-is so that we can remain
|
|
966
|
+
at least nominally compatible with the netbox-community/devicetype-library repo.
|
|
967
|
+
"""
|
|
968
|
+
|
|
969
|
+
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name="name")
|
|
970
|
+
|
|
971
|
+
class Meta:
|
|
972
|
+
model = ModuleType
|
|
973
|
+
fields = [
|
|
974
|
+
"manufacturer",
|
|
975
|
+
"model",
|
|
976
|
+
"part_number",
|
|
977
|
+
]
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
class ModuleTypeBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
981
|
+
pk = forms.ModelMultipleChoiceField(queryset=ModuleType.objects.all(), widget=forms.MultipleHiddenInput())
|
|
982
|
+
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
|
983
|
+
part_number = forms.CharField(required=False)
|
|
984
|
+
|
|
985
|
+
class Meta:
|
|
986
|
+
nullable_fields = []
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
class ModuleTypeFilterForm(NautobotFilterForm):
|
|
990
|
+
model = ModuleType
|
|
991
|
+
q = forms.CharField(required=False, label="Search")
|
|
992
|
+
manufacturer = DynamicModelMultipleChoiceField(
|
|
993
|
+
queryset=Manufacturer.objects.all(), to_field_name="name", required=False
|
|
994
|
+
)
|
|
995
|
+
has_console_ports = forms.NullBooleanField(
|
|
996
|
+
required=False,
|
|
997
|
+
label="Has console ports",
|
|
998
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
999
|
+
)
|
|
1000
|
+
has_console_server_ports = forms.NullBooleanField(
|
|
1001
|
+
required=False,
|
|
1002
|
+
label="Has console server ports",
|
|
1003
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
1004
|
+
)
|
|
1005
|
+
has_power_ports = forms.NullBooleanField(
|
|
1006
|
+
required=False,
|
|
1007
|
+
label="Has power ports",
|
|
1008
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
1009
|
+
)
|
|
1010
|
+
has_power_outlets = forms.NullBooleanField(
|
|
1011
|
+
required=False,
|
|
1012
|
+
label="Has power outlets",
|
|
1013
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
1014
|
+
)
|
|
1015
|
+
has_interfaces = forms.NullBooleanField(
|
|
1016
|
+
required=False,
|
|
1017
|
+
label="Has interfaces",
|
|
1018
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
1019
|
+
)
|
|
1020
|
+
tags = TagFilterField(model)
|
|
1021
|
+
|
|
1022
|
+
|
|
900
1023
|
#
|
|
901
1024
|
# Device component templates
|
|
902
1025
|
#
|
|
903
1026
|
|
|
904
1027
|
|
|
1028
|
+
class ComponentTemplateForm(NautobotModelForm):
|
|
1029
|
+
# TODO: placeholder values shouldn't be form controls, instead use:
|
|
1030
|
+
# <p class="form-control-static">{{ obj|hyperlinked_object_target_new_tab }}</p>
|
|
1031
|
+
device_type = DynamicModelChoiceField(
|
|
1032
|
+
queryset=DeviceType.objects.all(),
|
|
1033
|
+
)
|
|
1034
|
+
|
|
1035
|
+
|
|
1036
|
+
class ModularComponentTemplateForm(ComponentTemplateForm):
|
|
1037
|
+
device_type = DynamicModelChoiceField(
|
|
1038
|
+
queryset=DeviceType.objects.all(),
|
|
1039
|
+
required=False,
|
|
1040
|
+
)
|
|
1041
|
+
module_type = DynamicModelChoiceField(
|
|
1042
|
+
queryset=ModuleType.objects.all(),
|
|
1043
|
+
required=False,
|
|
1044
|
+
)
|
|
1045
|
+
|
|
1046
|
+
|
|
905
1047
|
class ComponentTemplateCreateForm(ComponentForm):
|
|
906
1048
|
"""
|
|
907
1049
|
Base form for the creation of device component templates (subclassed from ComponentTemplateModel).
|
|
908
1050
|
"""
|
|
909
1051
|
|
|
910
|
-
|
|
911
|
-
queryset=
|
|
912
|
-
required=False,
|
|
913
|
-
initial_params={"device_types": "device_type"},
|
|
1052
|
+
device_type = DynamicModelChoiceField(
|
|
1053
|
+
queryset=DeviceType.objects.all(),
|
|
914
1054
|
)
|
|
1055
|
+
description = forms.CharField(required=False)
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
class ModularComponentTemplateCreateForm(ModularComponentForm):
|
|
1059
|
+
"""
|
|
1060
|
+
Base form for the creation of modular device component templates (subclassed from ModularComponentTemplateModel).
|
|
1061
|
+
"""
|
|
1062
|
+
|
|
915
1063
|
device_type = DynamicModelChoiceField(
|
|
916
1064
|
queryset=DeviceType.objects.all(),
|
|
917
|
-
|
|
1065
|
+
required=False,
|
|
1066
|
+
)
|
|
1067
|
+
module_type = DynamicModelChoiceField(
|
|
1068
|
+
queryset=ModuleType.objects.all(),
|
|
1069
|
+
required=False,
|
|
918
1070
|
)
|
|
919
1071
|
description = forms.CharField(required=False)
|
|
920
1072
|
|
|
921
1073
|
|
|
922
|
-
class ConsolePortTemplateForm(
|
|
1074
|
+
class ConsolePortTemplateForm(ModularComponentTemplateForm):
|
|
923
1075
|
class Meta:
|
|
924
1076
|
model = ConsolePortTemplate
|
|
925
1077
|
fields = [
|
|
926
1078
|
"device_type",
|
|
1079
|
+
"module_type",
|
|
927
1080
|
"name",
|
|
928
1081
|
"label",
|
|
929
1082
|
"type",
|
|
930
1083
|
"description",
|
|
931
1084
|
]
|
|
932
|
-
widgets = {
|
|
933
|
-
"device_type": forms.HiddenInput(),
|
|
934
|
-
}
|
|
935
1085
|
|
|
936
1086
|
|
|
937
|
-
class ConsolePortTemplateCreateForm(
|
|
1087
|
+
class ConsolePortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
938
1088
|
type = forms.ChoiceField(choices=add_blank_choice(ConsolePortTypeChoices), widget=StaticSelect2())
|
|
939
1089
|
field_order = (
|
|
940
|
-
"manufacturer",
|
|
941
1090
|
"device_type",
|
|
1091
|
+
"module_type",
|
|
942
1092
|
"name_pattern",
|
|
943
1093
|
"label_pattern",
|
|
944
1094
|
"type",
|
|
@@ -959,26 +1109,24 @@ class ConsolePortTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
959
1109
|
nullable_fields = ["label", "type", "description"]
|
|
960
1110
|
|
|
961
1111
|
|
|
962
|
-
class ConsoleServerPortTemplateForm(
|
|
1112
|
+
class ConsoleServerPortTemplateForm(ModularComponentTemplateForm):
|
|
963
1113
|
class Meta:
|
|
964
1114
|
model = ConsoleServerPortTemplate
|
|
965
1115
|
fields = [
|
|
966
1116
|
"device_type",
|
|
1117
|
+
"module_type",
|
|
967
1118
|
"name",
|
|
968
1119
|
"label",
|
|
969
1120
|
"type",
|
|
970
1121
|
"description",
|
|
971
1122
|
]
|
|
972
|
-
widgets = {
|
|
973
|
-
"device_type": forms.HiddenInput(),
|
|
974
|
-
}
|
|
975
1123
|
|
|
976
1124
|
|
|
977
|
-
class ConsoleServerPortTemplateCreateForm(
|
|
1125
|
+
class ConsoleServerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
978
1126
|
type = forms.ChoiceField(choices=add_blank_choice(ConsolePortTypeChoices), widget=StaticSelect2())
|
|
979
1127
|
field_order = (
|
|
980
|
-
"manufacturer",
|
|
981
1128
|
"device_type",
|
|
1129
|
+
"module_type",
|
|
982
1130
|
"name_pattern",
|
|
983
1131
|
"label_pattern",
|
|
984
1132
|
"type",
|
|
@@ -1003,11 +1151,12 @@ class ConsoleServerPortTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1003
1151
|
nullable_fields = ["label", "type", "description"]
|
|
1004
1152
|
|
|
1005
1153
|
|
|
1006
|
-
class PowerPortTemplateForm(
|
|
1154
|
+
class PowerPortTemplateForm(ModularComponentTemplateForm):
|
|
1007
1155
|
class Meta:
|
|
1008
1156
|
model = PowerPortTemplate
|
|
1009
1157
|
fields = [
|
|
1010
1158
|
"device_type",
|
|
1159
|
+
"module_type",
|
|
1011
1160
|
"name",
|
|
1012
1161
|
"label",
|
|
1013
1162
|
"type",
|
|
@@ -1015,18 +1164,15 @@ class PowerPortTemplateForm(NautobotModelForm):
|
|
|
1015
1164
|
"allocated_draw",
|
|
1016
1165
|
"description",
|
|
1017
1166
|
]
|
|
1018
|
-
widgets = {
|
|
1019
|
-
"device_type": forms.HiddenInput(),
|
|
1020
|
-
}
|
|
1021
1167
|
|
|
1022
1168
|
|
|
1023
|
-
class PowerPortTemplateCreateForm(
|
|
1169
|
+
class PowerPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1024
1170
|
type = forms.ChoiceField(choices=add_blank_choice(PowerPortTypeChoices), required=False)
|
|
1025
1171
|
maximum_draw = forms.IntegerField(min_value=1, required=False, help_text="Maximum power draw (watts)")
|
|
1026
1172
|
allocated_draw = forms.IntegerField(min_value=1, required=False, help_text="Allocated power draw (watts)")
|
|
1027
1173
|
field_order = (
|
|
1028
|
-
"manufacturer",
|
|
1029
1174
|
"device_type",
|
|
1175
|
+
"module_type",
|
|
1030
1176
|
"name_pattern",
|
|
1031
1177
|
"label_pattern",
|
|
1032
1178
|
"type",
|
|
@@ -1058,11 +1204,12 @@ class PowerPortTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1058
1204
|
]
|
|
1059
1205
|
|
|
1060
1206
|
|
|
1061
|
-
class PowerOutletTemplateForm(
|
|
1207
|
+
class PowerOutletTemplateForm(ModularComponentTemplateForm):
|
|
1062
1208
|
class Meta:
|
|
1063
1209
|
model = PowerOutletTemplate
|
|
1064
1210
|
fields = [
|
|
1065
1211
|
"device_type",
|
|
1212
|
+
"module_type",
|
|
1066
1213
|
"name",
|
|
1067
1214
|
"label",
|
|
1068
1215
|
"type",
|
|
@@ -1070,21 +1217,22 @@ class PowerOutletTemplateForm(NautobotModelForm):
|
|
|
1070
1217
|
"feed_leg",
|
|
1071
1218
|
"description",
|
|
1072
1219
|
]
|
|
1073
|
-
widgets = {
|
|
1074
|
-
"device_type": forms.HiddenInput(),
|
|
1075
|
-
}
|
|
1076
1220
|
|
|
1077
1221
|
def __init__(self, *args, **kwargs):
|
|
1078
1222
|
super().__init__(*args, **kwargs)
|
|
1079
1223
|
|
|
1080
|
-
# Limit power_port_template choices to current DeviceType
|
|
1081
|
-
if
|
|
1224
|
+
# Limit power_port_template choices to current DeviceType or ModuleType
|
|
1225
|
+
if getattr(self.instance, "device_type", None):
|
|
1082
1226
|
self.fields["power_port_template"].queryset = PowerPortTemplate.objects.filter(
|
|
1083
1227
|
device_type=self.instance.device_type
|
|
1084
1228
|
)
|
|
1229
|
+
elif getattr(self.instance, "module_type", None):
|
|
1230
|
+
self.fields["power_port_template"].queryset = PowerPortTemplate.objects.filter(
|
|
1231
|
+
module_type=self.instance.module_type
|
|
1232
|
+
)
|
|
1085
1233
|
|
|
1086
1234
|
|
|
1087
|
-
class PowerOutletTemplateCreateForm(
|
|
1235
|
+
class PowerOutletTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1088
1236
|
type = forms.ChoiceField(choices=add_blank_choice(PowerOutletTypeChoices), required=False)
|
|
1089
1237
|
power_port_template = DynamicModelChoiceField(
|
|
1090
1238
|
queryset=PowerPortTemplate.objects.all(),
|
|
@@ -1097,8 +1245,8 @@ class PowerOutletTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
1097
1245
|
widget=StaticSelect2(),
|
|
1098
1246
|
)
|
|
1099
1247
|
field_order = (
|
|
1100
|
-
"manufacturer",
|
|
1101
1248
|
"device_type",
|
|
1249
|
+
"module_type",
|
|
1102
1250
|
"name_pattern",
|
|
1103
1251
|
"label_pattern",
|
|
1104
1252
|
"type",
|
|
@@ -1113,7 +1261,6 @@ class PowerOutletTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1113
1261
|
device_type = forms.ModelChoiceField(
|
|
1114
1262
|
queryset=DeviceType.objects.all(),
|
|
1115
1263
|
required=False,
|
|
1116
|
-
disabled=True,
|
|
1117
1264
|
widget=forms.HiddenInput(),
|
|
1118
1265
|
)
|
|
1119
1266
|
label = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
@@ -1145,11 +1292,12 @@ class PowerOutletTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1145
1292
|
self.fields["power_port_template"].widget.attrs["disabled"] = True
|
|
1146
1293
|
|
|
1147
1294
|
|
|
1148
|
-
class InterfaceTemplateForm(
|
|
1295
|
+
class InterfaceTemplateForm(ModularComponentTemplateForm):
|
|
1149
1296
|
class Meta:
|
|
1150
1297
|
model = InterfaceTemplate
|
|
1151
1298
|
fields = [
|
|
1152
1299
|
"device_type",
|
|
1300
|
+
"module_type",
|
|
1153
1301
|
"name",
|
|
1154
1302
|
"label",
|
|
1155
1303
|
"type",
|
|
@@ -1157,17 +1305,16 @@ class InterfaceTemplateForm(NautobotModelForm):
|
|
|
1157
1305
|
"description",
|
|
1158
1306
|
]
|
|
1159
1307
|
widgets = {
|
|
1160
|
-
"device_type": forms.HiddenInput(),
|
|
1161
1308
|
"type": StaticSelect2(),
|
|
1162
1309
|
}
|
|
1163
1310
|
|
|
1164
1311
|
|
|
1165
|
-
class InterfaceTemplateCreateForm(
|
|
1312
|
+
class InterfaceTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1166
1313
|
type = forms.ChoiceField(choices=InterfaceTypeChoices, widget=StaticSelect2())
|
|
1167
1314
|
mgmt_only = forms.BooleanField(required=False, label="Management only")
|
|
1168
1315
|
field_order = (
|
|
1169
|
-
"manufacturer",
|
|
1170
1316
|
"device_type",
|
|
1317
|
+
"module_type",
|
|
1171
1318
|
"name_pattern",
|
|
1172
1319
|
"label_pattern",
|
|
1173
1320
|
"type",
|
|
@@ -1191,11 +1338,12 @@ class InterfaceTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1191
1338
|
nullable_fields = ["label", "description"]
|
|
1192
1339
|
|
|
1193
1340
|
|
|
1194
|
-
class FrontPortTemplateForm(
|
|
1341
|
+
class FrontPortTemplateForm(ModularComponentTemplateForm):
|
|
1195
1342
|
class Meta:
|
|
1196
1343
|
model = FrontPortTemplate
|
|
1197
1344
|
fields = [
|
|
1198
1345
|
"device_type",
|
|
1346
|
+
"module_type",
|
|
1199
1347
|
"name",
|
|
1200
1348
|
"label",
|
|
1201
1349
|
"type",
|
|
@@ -1204,21 +1352,24 @@ class FrontPortTemplateForm(NautobotModelForm):
|
|
|
1204
1352
|
"description",
|
|
1205
1353
|
]
|
|
1206
1354
|
widgets = {
|
|
1207
|
-
"device_type": forms.HiddenInput(),
|
|
1208
1355
|
"rear_port_template": StaticSelect2(),
|
|
1209
1356
|
}
|
|
1210
1357
|
|
|
1211
1358
|
def __init__(self, *args, **kwargs):
|
|
1212
1359
|
super().__init__(*args, **kwargs)
|
|
1213
1360
|
|
|
1214
|
-
# Limit rear_port_template choices to current DeviceType
|
|
1215
|
-
if
|
|
1361
|
+
# Limit rear_port_template choices to current DeviceType or ModuleType
|
|
1362
|
+
if getattr(self.instance, "device_type", None):
|
|
1216
1363
|
self.fields["rear_port_template"].queryset = RearPortTemplate.objects.filter(
|
|
1217
1364
|
device_type=self.instance.device_type
|
|
1218
1365
|
)
|
|
1366
|
+
elif getattr(self.instance, "module_type", None):
|
|
1367
|
+
self.fields["rear_port_template"].queryset = RearPortTemplate.objects.filter(
|
|
1368
|
+
module_type=self.instance.module_type
|
|
1369
|
+
)
|
|
1219
1370
|
|
|
1220
1371
|
|
|
1221
|
-
class FrontPortTemplateCreateForm(
|
|
1372
|
+
class FrontPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1222
1373
|
type = forms.ChoiceField(choices=PortTypeChoices, widget=StaticSelect2())
|
|
1223
1374
|
rear_port_template_set = forms.MultipleChoiceField(
|
|
1224
1375
|
choices=[],
|
|
@@ -1226,8 +1377,8 @@ class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
1226
1377
|
help_text="Select one rear port assignment for each front port being created.",
|
|
1227
1378
|
)
|
|
1228
1379
|
field_order = (
|
|
1229
|
-
"manufacturer",
|
|
1230
1380
|
"device_type",
|
|
1381
|
+
"module_type",
|
|
1231
1382
|
"name_pattern",
|
|
1232
1383
|
"label_pattern",
|
|
1233
1384
|
"type",
|
|
@@ -1238,17 +1389,25 @@ class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
1238
1389
|
def __init__(self, *args, **kwargs):
|
|
1239
1390
|
super().__init__(*args, **kwargs)
|
|
1240
1391
|
|
|
1241
|
-
device_type =
|
|
1392
|
+
device_type = self.initial.get("device_type") or self.data.get("device_type")
|
|
1393
|
+
module_type = self.initial.get("module_type") or self.data.get("module_type")
|
|
1394
|
+
if device_type:
|
|
1395
|
+
parent = DeviceType.objects.get(pk=device_type)
|
|
1396
|
+
elif module_type:
|
|
1397
|
+
parent = ModuleType.objects.get(pk=module_type)
|
|
1398
|
+
else:
|
|
1399
|
+
return
|
|
1242
1400
|
|
|
1243
1401
|
# Determine which rear port positions are occupied. These will be excluded from the list of available mappings.
|
|
1244
1402
|
occupied_port_positions = [
|
|
1245
1403
|
(front_port_template.rear_port_template_id, front_port_template.rear_port_position)
|
|
1246
|
-
for front_port_template in
|
|
1404
|
+
for front_port_template in parent.front_port_templates.all()
|
|
1247
1405
|
]
|
|
1248
1406
|
|
|
1249
1407
|
# Populate rear port choices
|
|
1250
1408
|
choices = []
|
|
1251
|
-
|
|
1409
|
+
parent_field_name = parent._meta.verbose_name.replace(" ", "_")
|
|
1410
|
+
rear_port_templates = RearPortTemplate.objects.filter(**{parent_field_name: parent})
|
|
1252
1411
|
for rear_port_template in rear_port_templates:
|
|
1253
1412
|
for i in range(1, rear_port_template.positions + 1):
|
|
1254
1413
|
if (rear_port_template.pk, i) not in occupied_port_positions:
|
|
@@ -1300,11 +1459,12 @@ class FrontPortTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1300
1459
|
nullable_fields = ["description"]
|
|
1301
1460
|
|
|
1302
1461
|
|
|
1303
|
-
class RearPortTemplateForm(
|
|
1462
|
+
class RearPortTemplateForm(ModularComponentTemplateForm):
|
|
1304
1463
|
class Meta:
|
|
1305
1464
|
model = RearPortTemplate
|
|
1306
1465
|
fields = [
|
|
1307
1466
|
"device_type",
|
|
1467
|
+
"module_type",
|
|
1308
1468
|
"name",
|
|
1309
1469
|
"label",
|
|
1310
1470
|
"type",
|
|
@@ -1312,12 +1472,11 @@ class RearPortTemplateForm(NautobotModelForm):
|
|
|
1312
1472
|
"description",
|
|
1313
1473
|
]
|
|
1314
1474
|
widgets = {
|
|
1315
|
-
"device_type": forms.HiddenInput(),
|
|
1316
1475
|
"type": StaticSelect2(),
|
|
1317
1476
|
}
|
|
1318
1477
|
|
|
1319
1478
|
|
|
1320
|
-
class RearPortTemplateCreateForm(
|
|
1479
|
+
class RearPortTemplateCreateForm(ModularComponentTemplateCreateForm):
|
|
1321
1480
|
type = forms.ChoiceField(
|
|
1322
1481
|
choices=PortTypeChoices,
|
|
1323
1482
|
widget=StaticSelect2(),
|
|
@@ -1329,8 +1488,8 @@ class RearPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
1329
1488
|
help_text="The number of front ports which may be mapped to each rear port",
|
|
1330
1489
|
)
|
|
1331
1490
|
field_order = (
|
|
1332
|
-
"manufacturer",
|
|
1333
1491
|
"device_type",
|
|
1492
|
+
"module_type",
|
|
1334
1493
|
"name_pattern",
|
|
1335
1494
|
"label_pattern",
|
|
1336
1495
|
"type",
|
|
@@ -1353,7 +1512,7 @@ class RearPortTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1353
1512
|
nullable_fields = ["description"]
|
|
1354
1513
|
|
|
1355
1514
|
|
|
1356
|
-
class DeviceBayTemplateForm(
|
|
1515
|
+
class DeviceBayTemplateForm(ComponentTemplateForm):
|
|
1357
1516
|
class Meta:
|
|
1358
1517
|
model = DeviceBayTemplate
|
|
1359
1518
|
fields = [
|
|
@@ -1362,14 +1521,10 @@ class DeviceBayTemplateForm(NautobotModelForm):
|
|
|
1362
1521
|
"label",
|
|
1363
1522
|
"description",
|
|
1364
1523
|
]
|
|
1365
|
-
widgets = {
|
|
1366
|
-
"device_type": forms.HiddenInput(),
|
|
1367
|
-
}
|
|
1368
1524
|
|
|
1369
1525
|
|
|
1370
1526
|
class DeviceBayTemplateCreateForm(ComponentTemplateCreateForm):
|
|
1371
1527
|
field_order = (
|
|
1372
|
-
"manufacturer",
|
|
1373
1528
|
"device_type",
|
|
1374
1529
|
"name_pattern",
|
|
1375
1530
|
"label_pattern",
|
|
@@ -1386,6 +1541,92 @@ class DeviceBayTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1386
1541
|
nullable_fields = ("label", "description")
|
|
1387
1542
|
|
|
1388
1543
|
|
|
1544
|
+
class ModuleBayTemplateForm(ModularComponentTemplateForm):
|
|
1545
|
+
class Meta:
|
|
1546
|
+
model = ModuleBayTemplate
|
|
1547
|
+
fields = [
|
|
1548
|
+
"device_type",
|
|
1549
|
+
"module_type",
|
|
1550
|
+
"name",
|
|
1551
|
+
"position",
|
|
1552
|
+
"label",
|
|
1553
|
+
"description",
|
|
1554
|
+
]
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
class ModuleBayBaseCreateForm(BootstrapMixin, forms.Form):
|
|
1558
|
+
name_pattern = ExpandableNameField(label="Name")
|
|
1559
|
+
label_pattern = ExpandableNameField(
|
|
1560
|
+
label="Label",
|
|
1561
|
+
required=False,
|
|
1562
|
+
help_text="Alphanumeric ranges are supported. (Must match the number of names being created.)",
|
|
1563
|
+
)
|
|
1564
|
+
position_pattern = ExpandableNameField(
|
|
1565
|
+
label="Position",
|
|
1566
|
+
required=False,
|
|
1567
|
+
help_text="Alphanumeric ranges are supported. (Must match the number of names being created.)",
|
|
1568
|
+
)
|
|
1569
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1570
|
+
|
|
1571
|
+
def clean(self):
|
|
1572
|
+
super().clean()
|
|
1573
|
+
|
|
1574
|
+
# Validate that the number of components being created from both the name_pattern, position_pattern and label_pattern are equal
|
|
1575
|
+
if self.cleaned_data["label_pattern"]:
|
|
1576
|
+
name_pattern_count = len(self.cleaned_data["name_pattern"])
|
|
1577
|
+
label_pattern_count = len(self.cleaned_data["label_pattern"])
|
|
1578
|
+
if name_pattern_count != label_pattern_count:
|
|
1579
|
+
raise forms.ValidationError(
|
|
1580
|
+
{
|
|
1581
|
+
"label_pattern": f"The provided name pattern will create {name_pattern_count} components, however "
|
|
1582
|
+
f"{label_pattern_count} labels will be generated. These counts must match."
|
|
1583
|
+
},
|
|
1584
|
+
code="label_pattern_mismatch",
|
|
1585
|
+
)
|
|
1586
|
+
|
|
1587
|
+
if self.cleaned_data["position_pattern"]:
|
|
1588
|
+
name_pattern_count = len(self.cleaned_data["name_pattern"])
|
|
1589
|
+
position_pattern_count = len(self.cleaned_data["position_pattern"])
|
|
1590
|
+
if name_pattern_count != position_pattern_count:
|
|
1591
|
+
raise forms.ValidationError(
|
|
1592
|
+
{
|
|
1593
|
+
"position_pattern": f"The provided name pattern will create {name_pattern_count} components, however "
|
|
1594
|
+
f"{position_pattern_count} positions will be generated. These counts must match."
|
|
1595
|
+
},
|
|
1596
|
+
code="position_pattern_mismatch",
|
|
1597
|
+
)
|
|
1598
|
+
|
|
1599
|
+
|
|
1600
|
+
class ModuleBayTemplateCreateForm(ModuleBayBaseCreateForm):
|
|
1601
|
+
device_type = DynamicModelChoiceField(
|
|
1602
|
+
queryset=DeviceType.objects.all(),
|
|
1603
|
+
required=False,
|
|
1604
|
+
)
|
|
1605
|
+
module_type = DynamicModelChoiceField(
|
|
1606
|
+
queryset=ModuleType.objects.all(),
|
|
1607
|
+
required=False,
|
|
1608
|
+
)
|
|
1609
|
+
|
|
1610
|
+
field_order = (
|
|
1611
|
+
"device_type",
|
|
1612
|
+
"module_type",
|
|
1613
|
+
"name_pattern",
|
|
1614
|
+
"label_pattern",
|
|
1615
|
+
"position_pattern",
|
|
1616
|
+
"description",
|
|
1617
|
+
)
|
|
1618
|
+
|
|
1619
|
+
|
|
1620
|
+
class ModuleBayTemplateBulkEditForm(NautobotBulkEditForm):
|
|
1621
|
+
pk = forms.ModelMultipleChoiceField(queryset=ModuleBayTemplate.objects.all(), widget=forms.MultipleHiddenInput())
|
|
1622
|
+
label = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1623
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1624
|
+
position = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
1625
|
+
|
|
1626
|
+
class Meta:
|
|
1627
|
+
nullable_fields = ("label", "description")
|
|
1628
|
+
|
|
1629
|
+
|
|
1389
1630
|
#
|
|
1390
1631
|
# Component template import forms
|
|
1391
1632
|
#
|
|
@@ -1400,14 +1641,7 @@ class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
|
|
|
1400
1641
|
netbox-community/devicetype-library repository.
|
|
1401
1642
|
"""
|
|
1402
1643
|
|
|
1403
|
-
def __init__(self,
|
|
1404
|
-
# Must pass the parent DeviceType on form initialization
|
|
1405
|
-
data.update(
|
|
1406
|
-
{
|
|
1407
|
-
"device_type": device_type.pk,
|
|
1408
|
-
}
|
|
1409
|
-
)
|
|
1410
|
-
|
|
1644
|
+
def __init__(self, data=None, *args, **kwargs):
|
|
1411
1645
|
super().__init__(data, *args, **kwargs)
|
|
1412
1646
|
|
|
1413
1647
|
if "type" in self.fields:
|
|
@@ -1419,9 +1653,21 @@ class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
|
|
|
1419
1653
|
data = self.cleaned_data["device_type"]
|
|
1420
1654
|
|
|
1421
1655
|
# Limit fields referencing other components to the parent DeviceType
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
field.
|
|
1656
|
+
if data:
|
|
1657
|
+
for field_name, field in self.fields.items():
|
|
1658
|
+
if isinstance(field, forms.ModelChoiceField) and field_name not in ["device_type", "module_type"]:
|
|
1659
|
+
field.queryset = field.queryset.filter(device_type=data)
|
|
1660
|
+
|
|
1661
|
+
return data
|
|
1662
|
+
|
|
1663
|
+
def clean_module_type(self):
|
|
1664
|
+
data = self.cleaned_data["module_type"]
|
|
1665
|
+
|
|
1666
|
+
# Limit fields referencing other components to the parent ModuleType
|
|
1667
|
+
if data:
|
|
1668
|
+
for field_name, field in self.fields.items():
|
|
1669
|
+
if isinstance(field, forms.ModelChoiceField) and field_name not in ["device_type", "module_type"]:
|
|
1670
|
+
field.queryset = field.queryset.filter(module_type=data)
|
|
1425
1671
|
|
|
1426
1672
|
return data
|
|
1427
1673
|
|
|
@@ -1454,6 +1700,7 @@ class ConsolePortTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1454
1700
|
model = ConsolePortTemplate
|
|
1455
1701
|
fields = [
|
|
1456
1702
|
"device_type",
|
|
1703
|
+
"module_type",
|
|
1457
1704
|
"name",
|
|
1458
1705
|
"label",
|
|
1459
1706
|
"type",
|
|
@@ -1465,6 +1712,7 @@ class ConsoleServerPortTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1465
1712
|
model = ConsoleServerPortTemplate
|
|
1466
1713
|
fields = [
|
|
1467
1714
|
"device_type",
|
|
1715
|
+
"module_type",
|
|
1468
1716
|
"name",
|
|
1469
1717
|
"label",
|
|
1470
1718
|
"type",
|
|
@@ -1476,6 +1724,7 @@ class PowerPortTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1476
1724
|
model = PowerPortTemplate
|
|
1477
1725
|
fields = [
|
|
1478
1726
|
"device_type",
|
|
1727
|
+
"module_type",
|
|
1479
1728
|
"name",
|
|
1480
1729
|
"label",
|
|
1481
1730
|
"type",
|
|
@@ -1495,6 +1744,7 @@ class PowerOutletTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1495
1744
|
model = PowerOutletTemplate
|
|
1496
1745
|
fields = [
|
|
1497
1746
|
"device_type",
|
|
1747
|
+
"module_type",
|
|
1498
1748
|
"name",
|
|
1499
1749
|
"label",
|
|
1500
1750
|
"type",
|
|
@@ -1517,6 +1767,7 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1517
1767
|
model = InterfaceTemplate
|
|
1518
1768
|
fields = [
|
|
1519
1769
|
"device_type",
|
|
1770
|
+
"module_type",
|
|
1520
1771
|
"name",
|
|
1521
1772
|
"label",
|
|
1522
1773
|
"type",
|
|
@@ -1535,6 +1786,7 @@ class FrontPortTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1535
1786
|
model = FrontPortTemplate
|
|
1536
1787
|
fields = [
|
|
1537
1788
|
"device_type",
|
|
1789
|
+
"module_type",
|
|
1538
1790
|
"name",
|
|
1539
1791
|
"type",
|
|
1540
1792
|
"rear_port_template",
|
|
@@ -1556,6 +1808,7 @@ class RearPortTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1556
1808
|
model = RearPortTemplate
|
|
1557
1809
|
fields = [
|
|
1558
1810
|
"device_type",
|
|
1811
|
+
"module_type",
|
|
1559
1812
|
"name",
|
|
1560
1813
|
"type",
|
|
1561
1814
|
"positions",
|
|
@@ -1571,6 +1824,17 @@ class DeviceBayTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1571
1824
|
]
|
|
1572
1825
|
|
|
1573
1826
|
|
|
1827
|
+
class ModuleBayTemplateImportForm(ComponentTemplateImportForm):
|
|
1828
|
+
class Meta:
|
|
1829
|
+
model = ModuleBayTemplate
|
|
1830
|
+
fields = [
|
|
1831
|
+
"device_type",
|
|
1832
|
+
"module_type",
|
|
1833
|
+
"name",
|
|
1834
|
+
"position",
|
|
1835
|
+
]
|
|
1836
|
+
|
|
1837
|
+
|
|
1574
1838
|
#
|
|
1575
1839
|
# Platforms
|
|
1576
1840
|
#
|
|
@@ -1734,7 +1998,7 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1734
1998
|
ip_choices = [(None, "---------")]
|
|
1735
1999
|
|
|
1736
2000
|
# Gather PKs of all interfaces belonging to this Device or a peer VirtualChassis member
|
|
1737
|
-
interface_ids = self.instance.
|
|
2001
|
+
interface_ids = self.instance.all_interfaces.values_list("pk", flat=True)
|
|
1738
2002
|
|
|
1739
2003
|
# Collect interface IPs
|
|
1740
2004
|
interface_ip_assignments = IPAddressToInterface.objects.filter(
|
|
@@ -2001,17 +2265,211 @@ class DeviceFilterForm(
|
|
|
2001
2265
|
|
|
2002
2266
|
|
|
2003
2267
|
#
|
|
2004
|
-
#
|
|
2268
|
+
# Modules
|
|
2005
2269
|
#
|
|
2006
2270
|
|
|
2007
2271
|
|
|
2008
|
-
class
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2272
|
+
class ModuleForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
|
|
2273
|
+
manufacturer = DynamicModelChoiceField(
|
|
2274
|
+
queryset=Manufacturer.objects.all(),
|
|
2275
|
+
required=False,
|
|
2276
|
+
initial_params={"module_types": "$module_type"},
|
|
2277
|
+
)
|
|
2278
|
+
module_type = DynamicModelChoiceField(
|
|
2279
|
+
queryset=ModuleType.objects.all(),
|
|
2280
|
+
query_params={"manufacturer": "$manufacturer"},
|
|
2281
|
+
)
|
|
2282
|
+
parent_module_bay_device_filter = DynamicModelChoiceField(
|
|
2283
|
+
queryset=Device.objects.all(),
|
|
2284
|
+
required=False,
|
|
2285
|
+
label="Parent Device",
|
|
2286
|
+
query_params={"has_empty_module_bays": True},
|
|
2287
|
+
initial_params={"module_bays": "$parent_module_bay"},
|
|
2288
|
+
)
|
|
2289
|
+
parent_module_bay_device = DynamicModelChoiceField(
|
|
2290
|
+
queryset=ModuleBay.objects.all(),
|
|
2291
|
+
label="Parent Module Bay",
|
|
2292
|
+
required=False,
|
|
2293
|
+
query_params={"parent_device": "$parent_module_bay_device_filter", "has_installed_module": False},
|
|
2294
|
+
initial_params={"pk": "$parent_module_bay", "parent_device__module_bays": "$parent_module_bay"},
|
|
2295
|
+
)
|
|
2296
|
+
parent_module_bay_module_filter = DynamicModelChoiceField(
|
|
2297
|
+
queryset=Module.objects.all(),
|
|
2298
|
+
required=False,
|
|
2299
|
+
label="Parent Module",
|
|
2300
|
+
query_params={"has_empty_module_bays": True},
|
|
2301
|
+
initial_params={"module_bays": "$parent_module_bay"},
|
|
2302
|
+
)
|
|
2303
|
+
parent_module_bay_module = DynamicModelChoiceField(
|
|
2304
|
+
queryset=ModuleBay.objects.all(),
|
|
2305
|
+
label="Parent Module Bay",
|
|
2306
|
+
required=False,
|
|
2307
|
+
query_params={"parent_module": "$parent_module_bay_module_filter", "has_installed_module": False},
|
|
2308
|
+
initial_params={"pk": "$parent_module_bay", "parent_module__module_bays": "$parent_module_bay"},
|
|
2309
|
+
)
|
|
2310
|
+
location = DynamicModelChoiceField(
|
|
2311
|
+
queryset=Location.objects.all(),
|
|
2312
|
+
required=False,
|
|
2313
|
+
label="Location",
|
|
2314
|
+
query_params={"content_type": Module._meta.label_lower},
|
|
2315
|
+
)
|
|
2316
|
+
role = DynamicModelChoiceField(
|
|
2317
|
+
queryset=Role.objects.all(),
|
|
2318
|
+
required=False,
|
|
2319
|
+
query_params={"content_types": Module._meta.label_lower},
|
|
2320
|
+
)
|
|
2012
2321
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2322
|
+
class Meta:
|
|
2323
|
+
model = Module
|
|
2324
|
+
fields = [
|
|
2325
|
+
"manufacturer",
|
|
2326
|
+
"module_type",
|
|
2327
|
+
"parent_module_bay",
|
|
2328
|
+
"location",
|
|
2329
|
+
"serial",
|
|
2330
|
+
"asset_tag",
|
|
2331
|
+
"role",
|
|
2332
|
+
"status",
|
|
2333
|
+
"tenant_group",
|
|
2334
|
+
"tenant",
|
|
2335
|
+
"tags",
|
|
2336
|
+
]
|
|
2337
|
+
help_texts = {
|
|
2338
|
+
"serial": "Module serial number",
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
def clean(self):
|
|
2342
|
+
cleaned_data = self.cleaned_data
|
|
2343
|
+
if cleaned_data["parent_module_bay_device"] and cleaned_data["parent_module_bay_module"]:
|
|
2344
|
+
raise forms.ValidationError("Multiple parent module bays selected.")
|
|
2345
|
+
elif cleaned_data["parent_module_bay_device"]:
|
|
2346
|
+
cleaned_data["parent_module_bay"] = cleaned_data.pop("parent_module_bay_device")
|
|
2347
|
+
elif cleaned_data["parent_module_bay_module"]:
|
|
2348
|
+
cleaned_data["parent_module_bay"] = cleaned_data.pop("parent_module_bay_module")
|
|
2349
|
+
|
|
2350
|
+
return cleaned_data
|
|
2351
|
+
|
|
2352
|
+
|
|
2353
|
+
class ModuleBulkEditForm(
|
|
2354
|
+
TagsBulkEditFormMixin,
|
|
2355
|
+
LocatableModelBulkEditFormMixin,
|
|
2356
|
+
StatusModelBulkEditFormMixin,
|
|
2357
|
+
RoleModelBulkEditFormMixin,
|
|
2358
|
+
NautobotBulkEditForm,
|
|
2359
|
+
LocalContextModelBulkEditForm,
|
|
2360
|
+
):
|
|
2361
|
+
pk = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), widget=forms.MultipleHiddenInput())
|
|
2362
|
+
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
|
2363
|
+
module_type = DynamicModelChoiceField(
|
|
2364
|
+
queryset=ModuleType.objects.all(),
|
|
2365
|
+
required=False,
|
|
2366
|
+
query_params={"manufacturer": "$manufacturer"},
|
|
2367
|
+
)
|
|
2368
|
+
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
2369
|
+
serial = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False, label="Serial Number")
|
|
2370
|
+
|
|
2371
|
+
class Meta:
|
|
2372
|
+
model = Module
|
|
2373
|
+
nullable_fields = [
|
|
2374
|
+
"location",
|
|
2375
|
+
"tenant",
|
|
2376
|
+
"serial",
|
|
2377
|
+
]
|
|
2378
|
+
|
|
2379
|
+
|
|
2380
|
+
class ModuleFilterForm(
|
|
2381
|
+
NautobotFilterForm,
|
|
2382
|
+
LocalContextFilterForm,
|
|
2383
|
+
LocatableModelFilterFormMixin,
|
|
2384
|
+
TenancyFilterForm,
|
|
2385
|
+
StatusModelFilterFormMixin,
|
|
2386
|
+
RoleModelFilterFormMixin,
|
|
2387
|
+
):
|
|
2388
|
+
model = Module
|
|
2389
|
+
field_order = [
|
|
2390
|
+
"q",
|
|
2391
|
+
"location",
|
|
2392
|
+
"status",
|
|
2393
|
+
"role",
|
|
2394
|
+
"tenant_group",
|
|
2395
|
+
"tenant",
|
|
2396
|
+
"manufacturer",
|
|
2397
|
+
"module_type",
|
|
2398
|
+
"mac_address",
|
|
2399
|
+
]
|
|
2400
|
+
q = forms.CharField(required=False, label="Search")
|
|
2401
|
+
manufacturer = DynamicModelMultipleChoiceField(
|
|
2402
|
+
queryset=Manufacturer.objects.all(),
|
|
2403
|
+
to_field_name="name",
|
|
2404
|
+
required=False,
|
|
2405
|
+
label="Manufacturer",
|
|
2406
|
+
)
|
|
2407
|
+
module_type = DynamicModelMultipleChoiceField(
|
|
2408
|
+
queryset=ModuleType.objects.all(),
|
|
2409
|
+
required=False,
|
|
2410
|
+
label="Model",
|
|
2411
|
+
query_params={"manufacturer": "$manufacturer"},
|
|
2412
|
+
)
|
|
2413
|
+
mac_address = forms.CharField(required=False, label="MAC address")
|
|
2414
|
+
has_console_ports = forms.NullBooleanField(
|
|
2415
|
+
required=False,
|
|
2416
|
+
label="Has console ports",
|
|
2417
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2418
|
+
)
|
|
2419
|
+
has_console_server_ports = forms.NullBooleanField(
|
|
2420
|
+
required=False,
|
|
2421
|
+
label="Has console server ports",
|
|
2422
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2423
|
+
)
|
|
2424
|
+
has_power_ports = forms.NullBooleanField(
|
|
2425
|
+
required=False,
|
|
2426
|
+
label="Has power ports",
|
|
2427
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2428
|
+
)
|
|
2429
|
+
has_power_outlets = forms.NullBooleanField(
|
|
2430
|
+
required=False,
|
|
2431
|
+
label="Has power outlets",
|
|
2432
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2433
|
+
)
|
|
2434
|
+
has_interfaces = forms.NullBooleanField(
|
|
2435
|
+
required=False,
|
|
2436
|
+
label="Has interfaces",
|
|
2437
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2438
|
+
)
|
|
2439
|
+
has_front_ports = forms.NullBooleanField(
|
|
2440
|
+
required=False,
|
|
2441
|
+
label="Has front ports",
|
|
2442
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2443
|
+
)
|
|
2444
|
+
has_rear_ports = forms.NullBooleanField(
|
|
2445
|
+
required=False,
|
|
2446
|
+
label="Has rear ports",
|
|
2447
|
+
widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES),
|
|
2448
|
+
)
|
|
2449
|
+
tags = TagFilterField(model)
|
|
2450
|
+
|
|
2451
|
+
|
|
2452
|
+
#
|
|
2453
|
+
# Device components
|
|
2454
|
+
#
|
|
2455
|
+
|
|
2456
|
+
|
|
2457
|
+
class ComponentCreateForm(ComponentForm):
|
|
2458
|
+
"""
|
|
2459
|
+
Base form for the creation of device components (models subclassed from ComponentModel).
|
|
2460
|
+
"""
|
|
2461
|
+
|
|
2462
|
+
device = DynamicModelChoiceField(queryset=Device.objects.all())
|
|
2463
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
2464
|
+
|
|
2465
|
+
|
|
2466
|
+
class ModularComponentCreateForm(ModularComponentForm):
|
|
2467
|
+
"""
|
|
2468
|
+
Base form for the creation of modular device components (models subclassed from ModularComponentModel).
|
|
2469
|
+
"""
|
|
2470
|
+
|
|
2471
|
+
device = DynamicModelChoiceField(queryset=Device.objects.all(), required=False)
|
|
2472
|
+
module = DynamicModelChoiceField(queryset=Module.objects.all(), required=False)
|
|
2015
2473
|
|
|
2016
2474
|
|
|
2017
2475
|
class ComponentEditForm(NautobotModelForm):
|
|
@@ -2026,9 +2484,26 @@ class ComponentEditForm(NautobotModelForm):
|
|
|
2026
2484
|
def __init__(self, *args, **kwargs):
|
|
2027
2485
|
super().__init__(*args, **kwargs)
|
|
2028
2486
|
|
|
2029
|
-
#
|
|
2030
|
-
if
|
|
2487
|
+
# Disable the device field if an initial value is provided
|
|
2488
|
+
if "device" in self.initial:
|
|
2489
|
+
self.fields["device"].disabled = True
|
|
2490
|
+
|
|
2491
|
+
|
|
2492
|
+
class ModularComponentEditForm(ComponentEditForm):
|
|
2493
|
+
"""
|
|
2494
|
+
Base class for editing modular device components (models subclassed from ModularComponentModel).
|
|
2495
|
+
"""
|
|
2496
|
+
|
|
2497
|
+
device = DynamicModelChoiceField(queryset=Device.objects.all(), required=False)
|
|
2498
|
+
module = DynamicModelChoiceField(queryset=Module.objects.all(), required=False)
|
|
2499
|
+
|
|
2500
|
+
def __init__(self, *args, **kwargs):
|
|
2501
|
+
super().__init__(*args, **kwargs)
|
|
2502
|
+
|
|
2503
|
+
# Disable the device and module fields if an initial value is provided for either
|
|
2504
|
+
if "device" in self.initial or "module" in self.initial:
|
|
2031
2505
|
self.fields["device"].disabled = True
|
|
2506
|
+
self.fields["module"].disabled = True
|
|
2032
2507
|
|
|
2033
2508
|
|
|
2034
2509
|
class DeviceBulkAddComponentForm(ComponentForm, CustomFieldModelBulkEditFormMixin):
|
|
@@ -2039,22 +2514,31 @@ class DeviceBulkAddComponentForm(ComponentForm, CustomFieldModelBulkEditFormMixi
|
|
|
2039
2514
|
nullable_fields = []
|
|
2040
2515
|
|
|
2041
2516
|
|
|
2517
|
+
class ModuleBulkAddComponentForm(ModularComponentForm, CustomFieldModelBulkEditFormMixin):
|
|
2518
|
+
pk = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), widget=forms.MultipleHiddenInput())
|
|
2519
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
2520
|
+
|
|
2521
|
+
class Meta:
|
|
2522
|
+
nullable_fields = []
|
|
2523
|
+
|
|
2524
|
+
|
|
2042
2525
|
#
|
|
2043
2526
|
# Console ports
|
|
2044
2527
|
#
|
|
2045
2528
|
|
|
2046
2529
|
|
|
2047
|
-
class ConsolePortFilterForm(
|
|
2530
|
+
class ConsolePortFilterForm(ModularDeviceComponentFilterForm):
|
|
2048
2531
|
model = ConsolePort
|
|
2049
2532
|
type = forms.MultipleChoiceField(choices=ConsolePortTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2050
2533
|
tags = TagFilterField(model)
|
|
2051
2534
|
|
|
2052
2535
|
|
|
2053
|
-
class ConsolePortForm(
|
|
2536
|
+
class ConsolePortForm(ModularComponentEditForm):
|
|
2054
2537
|
class Meta:
|
|
2055
2538
|
model = ConsolePort
|
|
2056
2539
|
fields = [
|
|
2057
2540
|
"device",
|
|
2541
|
+
"module",
|
|
2058
2542
|
"name",
|
|
2059
2543
|
"label",
|
|
2060
2544
|
"type",
|
|
@@ -2063,7 +2547,7 @@ class ConsolePortForm(ComponentEditForm):
|
|
|
2063
2547
|
]
|
|
2064
2548
|
|
|
2065
2549
|
|
|
2066
|
-
class ConsolePortCreateForm(
|
|
2550
|
+
class ConsolePortCreateForm(ModularComponentCreateForm):
|
|
2067
2551
|
type = forms.ChoiceField(
|
|
2068
2552
|
choices=add_blank_choice(ConsolePortTypeChoices),
|
|
2069
2553
|
required=False,
|
|
@@ -2071,6 +2555,7 @@ class ConsolePortCreateForm(ComponentCreateForm):
|
|
|
2071
2555
|
)
|
|
2072
2556
|
field_order = (
|
|
2073
2557
|
"device",
|
|
2558
|
+
"module",
|
|
2074
2559
|
"name_pattern",
|
|
2075
2560
|
"label_pattern",
|
|
2076
2561
|
"type",
|
|
@@ -2083,6 +2568,10 @@ class ConsolePortBulkCreateForm(form_from_model(ConsolePort, ["type", "tags"]),
|
|
|
2083
2568
|
field_order = ("name_pattern", "label_pattern", "type", "description", "tags")
|
|
2084
2569
|
|
|
2085
2570
|
|
|
2571
|
+
class ModuleConsolePortBulkCreateForm(form_from_model(ConsolePort, ["type", "tags"]), ModuleBulkAddComponentForm):
|
|
2572
|
+
field_order = ("name_pattern", "label_pattern", "type", "description", "tags")
|
|
2573
|
+
|
|
2574
|
+
|
|
2086
2575
|
class ConsolePortBulkEditForm(
|
|
2087
2576
|
form_from_model(ConsolePort, ["label", "type", "description"]),
|
|
2088
2577
|
TagsBulkEditFormMixin,
|
|
@@ -2099,17 +2588,18 @@ class ConsolePortBulkEditForm(
|
|
|
2099
2588
|
#
|
|
2100
2589
|
|
|
2101
2590
|
|
|
2102
|
-
class ConsoleServerPortFilterForm(
|
|
2591
|
+
class ConsoleServerPortFilterForm(ModularDeviceComponentFilterForm):
|
|
2103
2592
|
model = ConsoleServerPort
|
|
2104
2593
|
type = forms.MultipleChoiceField(choices=ConsolePortTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2105
2594
|
tags = TagFilterField(model)
|
|
2106
2595
|
|
|
2107
2596
|
|
|
2108
|
-
class ConsoleServerPortForm(
|
|
2597
|
+
class ConsoleServerPortForm(ModularComponentEditForm):
|
|
2109
2598
|
class Meta:
|
|
2110
2599
|
model = ConsoleServerPort
|
|
2111
2600
|
fields = [
|
|
2112
2601
|
"device",
|
|
2602
|
+
"module",
|
|
2113
2603
|
"name",
|
|
2114
2604
|
"label",
|
|
2115
2605
|
"type",
|
|
@@ -2118,7 +2608,7 @@ class ConsoleServerPortForm(ComponentEditForm):
|
|
|
2118
2608
|
]
|
|
2119
2609
|
|
|
2120
2610
|
|
|
2121
|
-
class ConsoleServerPortCreateForm(
|
|
2611
|
+
class ConsoleServerPortCreateForm(ModularComponentCreateForm):
|
|
2122
2612
|
type = forms.ChoiceField(
|
|
2123
2613
|
choices=add_blank_choice(ConsolePortTypeChoices),
|
|
2124
2614
|
required=False,
|
|
@@ -2126,6 +2616,7 @@ class ConsoleServerPortCreateForm(ComponentCreateForm):
|
|
|
2126
2616
|
)
|
|
2127
2617
|
field_order = (
|
|
2128
2618
|
"device",
|
|
2619
|
+
"module",
|
|
2129
2620
|
"name_pattern",
|
|
2130
2621
|
"label_pattern",
|
|
2131
2622
|
"type",
|
|
@@ -2138,6 +2629,12 @@ class ConsoleServerPortBulkCreateForm(form_from_model(ConsoleServerPort, ["type"
|
|
|
2138
2629
|
field_order = ("name_pattern", "label_pattern", "type", "description", "tags")
|
|
2139
2630
|
|
|
2140
2631
|
|
|
2632
|
+
class ModuleConsoleServerPortBulkCreateForm(
|
|
2633
|
+
form_from_model(ConsoleServerPort, ["type", "tags"]), ModuleBulkAddComponentForm
|
|
2634
|
+
):
|
|
2635
|
+
field_order = ("name_pattern", "label_pattern", "type", "description", "tags")
|
|
2636
|
+
|
|
2637
|
+
|
|
2141
2638
|
class ConsoleServerPortBulkEditForm(
|
|
2142
2639
|
form_from_model(ConsoleServerPort, ["label", "type", "description"]),
|
|
2143
2640
|
TagsBulkEditFormMixin,
|
|
@@ -2154,17 +2651,18 @@ class ConsoleServerPortBulkEditForm(
|
|
|
2154
2651
|
#
|
|
2155
2652
|
|
|
2156
2653
|
|
|
2157
|
-
class PowerPortFilterForm(
|
|
2654
|
+
class PowerPortFilterForm(ModularDeviceComponentFilterForm):
|
|
2158
2655
|
model = PowerPort
|
|
2159
2656
|
type = forms.MultipleChoiceField(choices=PowerPortTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2160
2657
|
tags = TagFilterField(model)
|
|
2161
2658
|
|
|
2162
2659
|
|
|
2163
|
-
class PowerPortForm(
|
|
2660
|
+
class PowerPortForm(ModularComponentEditForm):
|
|
2164
2661
|
class Meta:
|
|
2165
2662
|
model = PowerPort
|
|
2166
2663
|
fields = [
|
|
2167
2664
|
"device",
|
|
2665
|
+
"module",
|
|
2168
2666
|
"name",
|
|
2169
2667
|
"label",
|
|
2170
2668
|
"type",
|
|
@@ -2175,7 +2673,7 @@ class PowerPortForm(ComponentEditForm):
|
|
|
2175
2673
|
]
|
|
2176
2674
|
|
|
2177
2675
|
|
|
2178
|
-
class PowerPortCreateForm(
|
|
2676
|
+
class PowerPortCreateForm(ModularComponentCreateForm):
|
|
2179
2677
|
type = forms.ChoiceField(
|
|
2180
2678
|
choices=add_blank_choice(PowerPortTypeChoices),
|
|
2181
2679
|
required=False,
|
|
@@ -2185,6 +2683,7 @@ class PowerPortCreateForm(ComponentCreateForm):
|
|
|
2185
2683
|
allocated_draw = forms.IntegerField(min_value=1, required=False, help_text="Allocated draw in watts")
|
|
2186
2684
|
field_order = (
|
|
2187
2685
|
"device",
|
|
2686
|
+
"module",
|
|
2188
2687
|
"name_pattern",
|
|
2189
2688
|
"label_pattern",
|
|
2190
2689
|
"type",
|
|
@@ -2210,6 +2709,21 @@ class PowerPortBulkCreateForm(
|
|
|
2210
2709
|
)
|
|
2211
2710
|
|
|
2212
2711
|
|
|
2712
|
+
class ModulePowerPortBulkCreateForm(
|
|
2713
|
+
form_from_model(PowerPort, ["type", "maximum_draw", "allocated_draw", "tags"]),
|
|
2714
|
+
ModuleBulkAddComponentForm,
|
|
2715
|
+
):
|
|
2716
|
+
field_order = (
|
|
2717
|
+
"name_pattern",
|
|
2718
|
+
"label_pattern",
|
|
2719
|
+
"type",
|
|
2720
|
+
"maximum_draw",
|
|
2721
|
+
"allocated_draw",
|
|
2722
|
+
"description",
|
|
2723
|
+
"tags",
|
|
2724
|
+
)
|
|
2725
|
+
|
|
2726
|
+
|
|
2213
2727
|
class PowerPortBulkEditForm(
|
|
2214
2728
|
form_from_model(PowerPort, ["label", "type", "maximum_draw", "allocated_draw", "description"]),
|
|
2215
2729
|
TagsBulkEditFormMixin,
|
|
@@ -2226,13 +2740,13 @@ class PowerPortBulkEditForm(
|
|
|
2226
2740
|
#
|
|
2227
2741
|
|
|
2228
2742
|
|
|
2229
|
-
class PowerOutletFilterForm(
|
|
2743
|
+
class PowerOutletFilterForm(ModularDeviceComponentFilterForm):
|
|
2230
2744
|
model = PowerOutlet
|
|
2231
2745
|
type = forms.MultipleChoiceField(choices=PowerOutletTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2232
2746
|
tags = TagFilterField(model)
|
|
2233
2747
|
|
|
2234
2748
|
|
|
2235
|
-
class PowerOutletForm(
|
|
2749
|
+
class PowerOutletForm(ModularComponentEditForm):
|
|
2236
2750
|
power_port = DynamicModelChoiceField(
|
|
2237
2751
|
queryset=PowerPort.objects.all(),
|
|
2238
2752
|
required=False,
|
|
@@ -2243,6 +2757,7 @@ class PowerOutletForm(ComponentEditForm):
|
|
|
2243
2757
|
model = PowerOutlet
|
|
2244
2758
|
fields = [
|
|
2245
2759
|
"device",
|
|
2760
|
+
"module",
|
|
2246
2761
|
"name",
|
|
2247
2762
|
"label",
|
|
2248
2763
|
"type",
|
|
@@ -2253,7 +2768,7 @@ class PowerOutletForm(ComponentEditForm):
|
|
|
2253
2768
|
]
|
|
2254
2769
|
|
|
2255
2770
|
|
|
2256
|
-
class PowerOutletCreateForm(
|
|
2771
|
+
class PowerOutletCreateForm(ModularComponentCreateForm):
|
|
2257
2772
|
type = forms.ChoiceField(
|
|
2258
2773
|
choices=add_blank_choice(PowerOutletTypeChoices),
|
|
2259
2774
|
required=False,
|
|
@@ -2267,6 +2782,7 @@ class PowerOutletCreateForm(ComponentCreateForm):
|
|
|
2267
2782
|
feed_leg = forms.ChoiceField(choices=add_blank_choice(PowerOutletFeedLegChoices), required=False)
|
|
2268
2783
|
field_order = (
|
|
2269
2784
|
"device",
|
|
2785
|
+
"module",
|
|
2270
2786
|
"name_pattern",
|
|
2271
2787
|
"label_pattern",
|
|
2272
2788
|
"type",
|
|
@@ -2288,6 +2804,19 @@ class PowerOutletBulkCreateForm(form_from_model(PowerOutlet, ["type", "feed_leg"
|
|
|
2288
2804
|
)
|
|
2289
2805
|
|
|
2290
2806
|
|
|
2807
|
+
class ModulePowerOutletBulkCreateForm(
|
|
2808
|
+
form_from_model(PowerOutlet, ["type", "feed_leg", "tags"]), ModuleBulkAddComponentForm
|
|
2809
|
+
):
|
|
2810
|
+
field_order = (
|
|
2811
|
+
"name_pattern",
|
|
2812
|
+
"label_pattern",
|
|
2813
|
+
"type",
|
|
2814
|
+
"feed_leg",
|
|
2815
|
+
"description",
|
|
2816
|
+
"tags",
|
|
2817
|
+
)
|
|
2818
|
+
|
|
2819
|
+
|
|
2291
2820
|
class PowerOutletBulkEditForm(
|
|
2292
2821
|
form_from_model(PowerOutlet, ["label", "type", "feed_leg", "power_port", "description"]),
|
|
2293
2822
|
TagsBulkEditFormMixin,
|
|
@@ -2297,7 +2826,6 @@ class PowerOutletBulkEditForm(
|
|
|
2297
2826
|
device = forms.ModelChoiceField(
|
|
2298
2827
|
queryset=Device.objects.all(),
|
|
2299
2828
|
required=False,
|
|
2300
|
-
disabled=True,
|
|
2301
2829
|
widget=forms.HiddenInput(),
|
|
2302
2830
|
)
|
|
2303
2831
|
|
|
@@ -2321,7 +2849,7 @@ class PowerOutletBulkEditForm(
|
|
|
2321
2849
|
#
|
|
2322
2850
|
|
|
2323
2851
|
|
|
2324
|
-
class InterfaceFilterForm(
|
|
2852
|
+
class InterfaceFilterForm(ModularDeviceComponentFilterForm, RoleModelFilterFormMixin, StatusModelFilterFormMixin):
|
|
2325
2853
|
model = Interface
|
|
2326
2854
|
type = forms.MultipleChoiceField(choices=InterfaceTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2327
2855
|
enabled = forms.NullBooleanField(required=False, widget=StaticSelect2(choices=BOOLEAN_WITH_BLANK_CHOICES))
|
|
@@ -2330,7 +2858,7 @@ class InterfaceFilterForm(DeviceComponentFilterForm, StatusModelFilterFormMixin)
|
|
|
2330
2858
|
tags = TagFilterField(model)
|
|
2331
2859
|
|
|
2332
2860
|
|
|
2333
|
-
class InterfaceForm(InterfaceCommonForm,
|
|
2861
|
+
class InterfaceForm(InterfaceCommonForm, ModularComponentEditForm):
|
|
2334
2862
|
parent_interface = DynamicModelChoiceField(
|
|
2335
2863
|
queryset=Interface.objects.all(),
|
|
2336
2864
|
required=False,
|
|
@@ -2389,7 +2917,9 @@ class InterfaceForm(InterfaceCommonForm, ComponentEditForm):
|
|
|
2389
2917
|
model = Interface
|
|
2390
2918
|
fields = [
|
|
2391
2919
|
"device",
|
|
2920
|
+
"module",
|
|
2392
2921
|
"name",
|
|
2922
|
+
"role",
|
|
2393
2923
|
"label",
|
|
2394
2924
|
"type",
|
|
2395
2925
|
"enabled",
|
|
@@ -2420,7 +2950,8 @@ class InterfaceForm(InterfaceCommonForm, ComponentEditForm):
|
|
|
2420
2950
|
}
|
|
2421
2951
|
|
|
2422
2952
|
|
|
2423
|
-
class InterfaceCreateForm(
|
|
2953
|
+
class InterfaceCreateForm(ModularComponentCreateForm, InterfaceCommonForm, RoleNotRequiredModelFormMixin):
|
|
2954
|
+
model = Interface
|
|
2424
2955
|
type = forms.ChoiceField(
|
|
2425
2956
|
choices=InterfaceTypeChoices,
|
|
2426
2957
|
widget=StaticSelect2(),
|
|
@@ -2503,9 +3034,11 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2503
3034
|
)
|
|
2504
3035
|
field_order = (
|
|
2505
3036
|
"device",
|
|
3037
|
+
"module",
|
|
2506
3038
|
"name_pattern",
|
|
2507
3039
|
"label_pattern",
|
|
2508
3040
|
"status",
|
|
3041
|
+
"role",
|
|
2509
3042
|
"type",
|
|
2510
3043
|
"enabled",
|
|
2511
3044
|
"parent_interface",
|
|
@@ -2527,7 +3060,9 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2527
3060
|
class InterfaceBulkCreateForm(
|
|
2528
3061
|
form_from_model(Interface, ["enabled", "mtu", "vrf", "mgmt_only", "mode", "tags"]),
|
|
2529
3062
|
DeviceBulkAddComponentForm,
|
|
3063
|
+
RoleNotRequiredModelFormMixin,
|
|
2530
3064
|
):
|
|
3065
|
+
model = Interface
|
|
2531
3066
|
type = forms.ChoiceField(
|
|
2532
3067
|
choices=InterfaceTypeChoices,
|
|
2533
3068
|
widget=StaticSelect2(),
|
|
@@ -2542,6 +3077,39 @@ class InterfaceBulkCreateForm(
|
|
|
2542
3077
|
"name_pattern",
|
|
2543
3078
|
"label_pattern",
|
|
2544
3079
|
"status",
|
|
3080
|
+
"role",
|
|
3081
|
+
"type",
|
|
3082
|
+
"enabled",
|
|
3083
|
+
"mtu",
|
|
3084
|
+
"vrf",
|
|
3085
|
+
"mgmt_only",
|
|
3086
|
+
"description",
|
|
3087
|
+
"mode",
|
|
3088
|
+
"tags",
|
|
3089
|
+
)
|
|
3090
|
+
|
|
3091
|
+
|
|
3092
|
+
class ModuleInterfaceBulkCreateForm(
|
|
3093
|
+
form_from_model(Interface, ["enabled", "mtu", "vrf", "mgmt_only", "mode", "tags"]),
|
|
3094
|
+
ModuleBulkAddComponentForm,
|
|
3095
|
+
RoleNotRequiredModelFormMixin,
|
|
3096
|
+
):
|
|
3097
|
+
model = Interface
|
|
3098
|
+
type = forms.ChoiceField(
|
|
3099
|
+
choices=InterfaceTypeChoices,
|
|
3100
|
+
widget=StaticSelect2(),
|
|
3101
|
+
)
|
|
3102
|
+
status = DynamicModelChoiceField(
|
|
3103
|
+
required=True,
|
|
3104
|
+
queryset=Status.objects.all(),
|
|
3105
|
+
query_params={"content_types": Interface._meta.label_lower},
|
|
3106
|
+
)
|
|
3107
|
+
|
|
3108
|
+
field_order = (
|
|
3109
|
+
"name_pattern",
|
|
3110
|
+
"label_pattern",
|
|
3111
|
+
"status",
|
|
3112
|
+
"role",
|
|
2545
3113
|
"type",
|
|
2546
3114
|
"enabled",
|
|
2547
3115
|
"mtu",
|
|
@@ -2559,6 +3127,7 @@ class InterfaceBulkEditForm(
|
|
|
2559
3127
|
),
|
|
2560
3128
|
TagsBulkEditFormMixin,
|
|
2561
3129
|
StatusModelBulkEditFormMixin,
|
|
3130
|
+
RoleModelBulkEditFormMixin,
|
|
2562
3131
|
NautobotBulkEditForm,
|
|
2563
3132
|
):
|
|
2564
3133
|
pk = forms.ModelMultipleChoiceField(queryset=Interface.objects.all(), widget=forms.MultipleHiddenInput())
|
|
@@ -2670,13 +3239,13 @@ class InterfaceBulkEditForm(
|
|
|
2670
3239
|
#
|
|
2671
3240
|
|
|
2672
3241
|
|
|
2673
|
-
class FrontPortFilterForm(
|
|
3242
|
+
class FrontPortFilterForm(ModularDeviceComponentFilterForm):
|
|
2674
3243
|
model = FrontPort
|
|
2675
3244
|
type = forms.MultipleChoiceField(choices=PortTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2676
3245
|
tags = TagFilterField(model)
|
|
2677
3246
|
|
|
2678
3247
|
|
|
2679
|
-
class FrontPortForm(
|
|
3248
|
+
class FrontPortForm(ModularComponentEditForm):
|
|
2680
3249
|
rear_port = DynamicModelChoiceField(
|
|
2681
3250
|
queryset=RearPort.objects.all(),
|
|
2682
3251
|
query_params={"device": "$device"},
|
|
@@ -2686,6 +3255,7 @@ class FrontPortForm(ComponentEditForm):
|
|
|
2686
3255
|
model = FrontPort
|
|
2687
3256
|
fields = [
|
|
2688
3257
|
"device",
|
|
3258
|
+
"module",
|
|
2689
3259
|
"name",
|
|
2690
3260
|
"label",
|
|
2691
3261
|
"type",
|
|
@@ -2700,7 +3270,7 @@ class FrontPortForm(ComponentEditForm):
|
|
|
2700
3270
|
|
|
2701
3271
|
|
|
2702
3272
|
# TODO: Merge with FrontPortTemplateCreateForm to remove duplicate logic
|
|
2703
|
-
class FrontPortCreateForm(
|
|
3273
|
+
class FrontPortCreateForm(ModularComponentCreateForm):
|
|
2704
3274
|
type = forms.ChoiceField(
|
|
2705
3275
|
choices=PortTypeChoices,
|
|
2706
3276
|
widget=StaticSelect2(),
|
|
@@ -2712,6 +3282,7 @@ class FrontPortCreateForm(ComponentCreateForm):
|
|
|
2712
3282
|
)
|
|
2713
3283
|
field_order = (
|
|
2714
3284
|
"device",
|
|
3285
|
+
"module",
|
|
2715
3286
|
"name_pattern",
|
|
2716
3287
|
"label_pattern",
|
|
2717
3288
|
"type",
|
|
@@ -2723,17 +3294,24 @@ class FrontPortCreateForm(ComponentCreateForm):
|
|
|
2723
3294
|
def __init__(self, *args, **kwargs):
|
|
2724
3295
|
super().__init__(*args, **kwargs)
|
|
2725
3296
|
|
|
2726
|
-
device =
|
|
3297
|
+
device = self.initial.get("device") or self.data.get("device")
|
|
3298
|
+
module = self.initial.get("module") or self.data.get("module")
|
|
3299
|
+
if device:
|
|
3300
|
+
parent = Device.objects.get(pk=device)
|
|
3301
|
+
elif module:
|
|
3302
|
+
parent = Module.objects.get(pk=module)
|
|
3303
|
+
else:
|
|
3304
|
+
return
|
|
2727
3305
|
|
|
2728
3306
|
# Determine which rear port positions are occupied. These will be excluded from the list of available
|
|
2729
3307
|
# mappings.
|
|
2730
3308
|
occupied_port_positions = [
|
|
2731
|
-
(front_port.rear_port_id, front_port.rear_port_position) for front_port in
|
|
3309
|
+
(front_port.rear_port_id, front_port.rear_port_position) for front_port in parent.front_ports.all()
|
|
2732
3310
|
]
|
|
2733
3311
|
|
|
2734
3312
|
# Populate rear port choices
|
|
2735
3313
|
choices = []
|
|
2736
|
-
rear_ports = RearPort.objects.filter(
|
|
3314
|
+
rear_ports = RearPort.objects.filter(**{parent._meta.model_name: parent})
|
|
2737
3315
|
for rear_port in rear_ports:
|
|
2738
3316
|
for i in range(1, rear_port.positions + 1):
|
|
2739
3317
|
if (rear_port.pk, i) not in occupied_port_positions:
|
|
@@ -2794,17 +3372,18 @@ class FrontPortBulkEditForm(
|
|
|
2794
3372
|
#
|
|
2795
3373
|
|
|
2796
3374
|
|
|
2797
|
-
class RearPortFilterForm(
|
|
3375
|
+
class RearPortFilterForm(ModularDeviceComponentFilterForm):
|
|
2798
3376
|
model = RearPort
|
|
2799
3377
|
type = forms.MultipleChoiceField(choices=PortTypeChoices, required=False, widget=StaticSelect2Multiple())
|
|
2800
3378
|
tags = TagFilterField(model)
|
|
2801
3379
|
|
|
2802
3380
|
|
|
2803
|
-
class RearPortForm(
|
|
3381
|
+
class RearPortForm(ModularComponentEditForm):
|
|
2804
3382
|
class Meta:
|
|
2805
3383
|
model = RearPort
|
|
2806
3384
|
fields = [
|
|
2807
3385
|
"device",
|
|
3386
|
+
"module",
|
|
2808
3387
|
"name",
|
|
2809
3388
|
"label",
|
|
2810
3389
|
"type",
|
|
@@ -2817,7 +3396,7 @@ class RearPortForm(ComponentEditForm):
|
|
|
2817
3396
|
}
|
|
2818
3397
|
|
|
2819
3398
|
|
|
2820
|
-
class RearPortCreateForm(
|
|
3399
|
+
class RearPortCreateForm(ModularComponentCreateForm):
|
|
2821
3400
|
type = forms.ChoiceField(
|
|
2822
3401
|
choices=PortTypeChoices,
|
|
2823
3402
|
widget=StaticSelect2(),
|
|
@@ -2830,6 +3409,7 @@ class RearPortCreateForm(ComponentCreateForm):
|
|
|
2830
3409
|
)
|
|
2831
3410
|
field_order = (
|
|
2832
3411
|
"device",
|
|
3412
|
+
"module",
|
|
2833
3413
|
"name_pattern",
|
|
2834
3414
|
"label_pattern",
|
|
2835
3415
|
"type",
|
|
@@ -2850,6 +3430,19 @@ class RearPortBulkCreateForm(form_from_model(RearPort, ["type", "positions", "ta
|
|
|
2850
3430
|
)
|
|
2851
3431
|
|
|
2852
3432
|
|
|
3433
|
+
class ModuleRearPortBulkCreateForm(
|
|
3434
|
+
form_from_model(RearPort, ["type", "positions", "tags"]), ModuleBulkAddComponentForm
|
|
3435
|
+
):
|
|
3436
|
+
field_order = (
|
|
3437
|
+
"name_pattern",
|
|
3438
|
+
"label_pattern",
|
|
3439
|
+
"type",
|
|
3440
|
+
"positions",
|
|
3441
|
+
"description",
|
|
3442
|
+
"tags",
|
|
3443
|
+
)
|
|
3444
|
+
|
|
3445
|
+
|
|
2853
3446
|
class RearPortBulkEditForm(
|
|
2854
3447
|
form_from_model(RearPort, ["label", "type", "description"]),
|
|
2855
3448
|
TagsBulkEditFormMixin,
|
|
@@ -2922,13 +3515,119 @@ class DeviceBayBulkEditForm(
|
|
|
2922
3515
|
nullable_fields = ["label", "description"]
|
|
2923
3516
|
|
|
2924
3517
|
|
|
3518
|
+
#
|
|
3519
|
+
# Module bays
|
|
3520
|
+
#
|
|
3521
|
+
|
|
3522
|
+
|
|
3523
|
+
class ModuleBayFilterForm(NautobotFilterForm):
|
|
3524
|
+
model = ModuleBay
|
|
3525
|
+
|
|
3526
|
+
field_order = ["q", "parent_device", "parent_module"]
|
|
3527
|
+
q = forms.CharField(required=False, label="Search")
|
|
3528
|
+
parent_device = DynamicModelMultipleChoiceField(
|
|
3529
|
+
queryset=Device.objects.all(),
|
|
3530
|
+
required=False,
|
|
3531
|
+
label="Parent device",
|
|
3532
|
+
)
|
|
3533
|
+
parent_module = DynamicModelMultipleChoiceField(
|
|
3534
|
+
queryset=Module.objects.all(),
|
|
3535
|
+
required=False,
|
|
3536
|
+
label="Parent module",
|
|
3537
|
+
)
|
|
3538
|
+
|
|
3539
|
+
|
|
3540
|
+
class ModuleBayForm(NautobotModelForm):
|
|
3541
|
+
parent_device = DynamicModelChoiceField(
|
|
3542
|
+
queryset=Device.objects.all(),
|
|
3543
|
+
required=False,
|
|
3544
|
+
label="Parent Device",
|
|
3545
|
+
)
|
|
3546
|
+
parent_module = DynamicModelChoiceField(
|
|
3547
|
+
queryset=Module.objects.all(),
|
|
3548
|
+
required=False,
|
|
3549
|
+
label="Parent Module",
|
|
3550
|
+
)
|
|
3551
|
+
# TODO: Installed module field
|
|
3552
|
+
|
|
3553
|
+
class Meta:
|
|
3554
|
+
model = ModuleBay
|
|
3555
|
+
fields = [
|
|
3556
|
+
"parent_device",
|
|
3557
|
+
"parent_module",
|
|
3558
|
+
"name",
|
|
3559
|
+
"position",
|
|
3560
|
+
"label",
|
|
3561
|
+
"description",
|
|
3562
|
+
"tags",
|
|
3563
|
+
]
|
|
3564
|
+
|
|
3565
|
+
def __init__(self, *args, **kwargs):
|
|
3566
|
+
super().__init__(*args, **kwargs)
|
|
3567
|
+
|
|
3568
|
+
# Disable the parent_device and parent_module fields if an initial value is provided for either
|
|
3569
|
+
if "parent_device" in self.initial or "parent_module" in self.initial:
|
|
3570
|
+
self.fields["parent_device"].disabled = True
|
|
3571
|
+
self.fields["parent_module"].disabled = True
|
|
3572
|
+
|
|
3573
|
+
|
|
3574
|
+
class ModuleBayCreateForm(ModuleBayBaseCreateForm):
|
|
3575
|
+
parent_device = DynamicModelChoiceField(queryset=Device.objects.all(), required=False)
|
|
3576
|
+
parent_module = DynamicModelChoiceField(queryset=Module.objects.all(), required=False)
|
|
3577
|
+
tags = DynamicModelMultipleChoiceField(
|
|
3578
|
+
queryset=Tag.objects.all(),
|
|
3579
|
+
required=False,
|
|
3580
|
+
query_params={"content_types": ModuleBay._meta.label_lower},
|
|
3581
|
+
)
|
|
3582
|
+
field_order = (
|
|
3583
|
+
"parent_device",
|
|
3584
|
+
"parent_module",
|
|
3585
|
+
"name_pattern",
|
|
3586
|
+
"label_pattern",
|
|
3587
|
+
"position_pattern",
|
|
3588
|
+
"description",
|
|
3589
|
+
"tags",
|
|
3590
|
+
)
|
|
3591
|
+
|
|
3592
|
+
|
|
3593
|
+
class ModuleBayBulkCreateForm(
|
|
3594
|
+
form_from_model(ModuleBay, ["tags"]),
|
|
3595
|
+
ModuleBayBaseCreateForm,
|
|
3596
|
+
CustomFieldModelBulkEditFormMixin,
|
|
3597
|
+
):
|
|
3598
|
+
pk = forms.ModelMultipleChoiceField(queryset=Device.objects.all(), widget=forms.MultipleHiddenInput())
|
|
3599
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
3600
|
+
|
|
3601
|
+
field_order = ("name_pattern", "label_pattern", "position_pattern", "description", "tags")
|
|
3602
|
+
|
|
3603
|
+
class Meta:
|
|
3604
|
+
nullable_fields = []
|
|
3605
|
+
|
|
3606
|
+
|
|
3607
|
+
class ModuleModuleBayBulkCreateForm(ModuleBayBulkCreateForm):
|
|
3608
|
+
pk = forms.ModelMultipleChoiceField(queryset=Module.objects.all(), widget=forms.MultipleHiddenInput())
|
|
3609
|
+
|
|
3610
|
+
class Meta(ModuleBayBulkCreateForm.Meta):
|
|
3611
|
+
pass
|
|
3612
|
+
|
|
3613
|
+
|
|
3614
|
+
class ModuleBayBulkEditForm(
|
|
3615
|
+
form_from_model(ModuleBay, ["label", "description", "position"]),
|
|
3616
|
+
TagsBulkEditFormMixin,
|
|
3617
|
+
NautobotBulkEditForm,
|
|
3618
|
+
):
|
|
3619
|
+
pk = forms.ModelMultipleChoiceField(queryset=ModuleBay.objects.all(), widget=forms.MultipleHiddenInput())
|
|
3620
|
+
|
|
3621
|
+
class Meta:
|
|
3622
|
+
nullable_fields = ["label", "description"]
|
|
3623
|
+
|
|
3624
|
+
|
|
2925
3625
|
#
|
|
2926
3626
|
# Inventory items
|
|
2927
3627
|
#
|
|
2928
3628
|
|
|
2929
3629
|
|
|
2930
|
-
class InventoryItemForm(
|
|
2931
|
-
device = DynamicModelChoiceField(queryset=Device.objects.all())
|
|
3630
|
+
class InventoryItemForm(ComponentEditForm):
|
|
2932
3631
|
parent = DynamicModelChoiceField(
|
|
2933
3632
|
queryset=InventoryItem.objects.all(),
|
|
2934
3633
|
required=False,
|
|
@@ -3101,6 +3800,14 @@ class ConnectCableToDeviceForm(ConnectCableExcludeIDMixin, NautobotModelForm):
|
|
|
3101
3800
|
"rack": "$termination_b_rack",
|
|
3102
3801
|
},
|
|
3103
3802
|
)
|
|
3803
|
+
termination_b_module = DynamicModelChoiceField(
|
|
3804
|
+
queryset=Module.objects.all(),
|
|
3805
|
+
label="Module",
|
|
3806
|
+
required=False,
|
|
3807
|
+
query_params={
|
|
3808
|
+
"device": "$termination_b_device",
|
|
3809
|
+
},
|
|
3810
|
+
)
|
|
3104
3811
|
|
|
3105
3812
|
class Meta:
|
|
3106
3813
|
model = Cable
|
|
@@ -3135,7 +3842,7 @@ class ConnectCableToConsolePortForm(ConnectCableToDeviceForm):
|
|
|
3135
3842
|
queryset=ConsolePort.objects.all(),
|
|
3136
3843
|
label="Name",
|
|
3137
3844
|
disabled_indicator="cable",
|
|
3138
|
-
query_params={"device": "$termination_b_device"},
|
|
3845
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3139
3846
|
)
|
|
3140
3847
|
|
|
3141
3848
|
|
|
@@ -3144,7 +3851,7 @@ class ConnectCableToConsoleServerPortForm(ConnectCableToDeviceForm):
|
|
|
3144
3851
|
queryset=ConsoleServerPort.objects.all(),
|
|
3145
3852
|
label="Name",
|
|
3146
3853
|
disabled_indicator="cable",
|
|
3147
|
-
query_params={"device": "$termination_b_device"},
|
|
3854
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3148
3855
|
)
|
|
3149
3856
|
|
|
3150
3857
|
|
|
@@ -3153,7 +3860,7 @@ class ConnectCableToPowerPortForm(ConnectCableToDeviceForm):
|
|
|
3153
3860
|
queryset=PowerPort.objects.all(),
|
|
3154
3861
|
label="Name",
|
|
3155
3862
|
disabled_indicator="cable",
|
|
3156
|
-
query_params={"device": "$termination_b_device"},
|
|
3863
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3157
3864
|
)
|
|
3158
3865
|
|
|
3159
3866
|
|
|
@@ -3162,7 +3869,7 @@ class ConnectCableToPowerOutletForm(ConnectCableToDeviceForm):
|
|
|
3162
3869
|
queryset=PowerOutlet.objects.all(),
|
|
3163
3870
|
label="Name",
|
|
3164
3871
|
disabled_indicator="cable",
|
|
3165
|
-
query_params={"device": "$termination_b_device"},
|
|
3872
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3166
3873
|
)
|
|
3167
3874
|
|
|
3168
3875
|
|
|
@@ -3173,6 +3880,7 @@ class ConnectCableToInterfaceForm(ConnectCableToDeviceForm):
|
|
|
3173
3880
|
disabled_indicator="cable",
|
|
3174
3881
|
query_params={
|
|
3175
3882
|
"device_id": "$termination_b_device",
|
|
3883
|
+
"module": "$termination_b_module",
|
|
3176
3884
|
"kind": "physical",
|
|
3177
3885
|
},
|
|
3178
3886
|
)
|
|
@@ -3183,7 +3891,7 @@ class ConnectCableToFrontPortForm(ConnectCableToDeviceForm):
|
|
|
3183
3891
|
queryset=FrontPort.objects.all(),
|
|
3184
3892
|
label="Name",
|
|
3185
3893
|
disabled_indicator="cable",
|
|
3186
|
-
query_params={"device": "$termination_b_device"},
|
|
3894
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3187
3895
|
)
|
|
3188
3896
|
|
|
3189
3897
|
|
|
@@ -3192,7 +3900,7 @@ class ConnectCableToRearPortForm(ConnectCableToDeviceForm):
|
|
|
3192
3900
|
queryset=RearPort.objects.all(),
|
|
3193
3901
|
label="Name",
|
|
3194
3902
|
disabled_indicator="cable",
|
|
3195
|
-
query_params={"device": "$termination_b_device"},
|
|
3903
|
+
query_params={"device": "$termination_b_device", "module": "$termination_b_module"},
|
|
3196
3904
|
)
|
|
3197
3905
|
|
|
3198
3906
|
|